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 // Acquire::Item::Item - Constructor /*{{{*/
54 // ---------------------------------------------------------------------
56 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
57 PartialSize(0), Mode(0), ID(0), Complete(false),
58 Local(false), QueueCounter(0)
64 // Acquire::Item::~Item - Destructor /*{{{*/
65 // ---------------------------------------------------------------------
67 pkgAcquire::Item::~Item()
72 // Acquire::Item::Failed - Item failed to download /*{{{*/
73 // ---------------------------------------------------------------------
74 /* We return to an idle state if there are still other queues that could
76 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
79 ErrorText
= LookupTag(Message
,"Message");
80 UsedMirror
= LookupTag(Message
,"UsedMirror");
81 if (QueueCounter
<= 1)
83 /* This indicates that the file is not available right now but might
84 be sometime later. If we do a retry cycle then this should be
86 if (Cnf
->LocalOnly
== true &&
87 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
98 // report mirror failure back to LP if we actually use a mirror
99 string FailReason
= LookupTag(Message
, "FailReason");
100 if(FailReason
.size() != 0)
101 ReportMirrorFailure(FailReason
);
103 ReportMirrorFailure(ErrorText
);
106 // Acquire::Item::Start - Item has begun to download /*{{{*/
107 // ---------------------------------------------------------------------
108 /* Stash status and the file size. Note that setting Complete means
109 sub-phases of the acquire process such as decompresion are operating */
110 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
112 Status
= StatFetching
;
113 if (FileSize
== 0 && Complete
== false)
117 // Acquire::Item::Done - Item downloaded OK /*{{{*/
118 // ---------------------------------------------------------------------
120 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,string
/*Hash*/,
121 pkgAcquire::MethodConfig
* /*Cnf*/)
123 // We just downloaded something..
124 string FileName
= LookupTag(Message
,"Filename");
125 UsedMirror
= LookupTag(Message
,"UsedMirror");
126 if (Complete
== false && !Local
&& FileName
== DestFile
)
129 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
135 ErrorText
= string();
136 Owner
->Dequeue(this);
139 // Acquire::Item::Rename - Rename a file /*{{{*/
140 // ---------------------------------------------------------------------
141 /* This helper function is used by a lot of item methods as their final
143 void pkgAcquire::Item::Rename(string From
,string To
)
145 if (rename(From
.c_str(),To
.c_str()) != 0)
148 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
149 From
.c_str(),To
.c_str());
155 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
157 if(FileExists(DestFile
))
158 Rename(DestFile
, DestFile
+ ".FAILED");
162 case HashSumMismatch
:
163 ErrorText
= _("Hash Sum mismatch");
164 Status
= StatAuthError
;
165 ReportMirrorFailure("HashChecksumFailure");
168 ErrorText
= _("Size mismatch");
169 Status
= StatAuthError
;
170 ReportMirrorFailure("SizeFailure");
173 ErrorText
= _("Invalid file format");
175 // do not report as usually its not the mirrors fault, but Portal/Proxy
181 // Acquire::Item::ReportMirrorFailure /*{{{*/
182 // ---------------------------------------------------------------------
183 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
185 // we only act if a mirror was used at all
186 if(UsedMirror
.empty())
189 std::cerr
<< "\nReportMirrorFailure: "
191 << " Uri: " << DescURI()
193 << FailCode
<< std::endl
;
195 const char *Args
[40];
197 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
198 "/usr/lib/apt/apt-report-mirror-failure");
199 if(!FileExists(report
))
201 Args
[i
++] = report
.c_str();
202 Args
[i
++] = UsedMirror
.c_str();
203 Args
[i
++] = DescURI().c_str();
204 Args
[i
++] = FailCode
.c_str();
206 pid_t pid
= ExecFork();
209 _error
->Error("ReportMirrorFailure Fork failed");
214 execvp(Args
[0], (char**)Args
);
215 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
218 if(!ExecWait(pid
, "report-mirror-failure"))
220 _error
->Warning("Couldn't report problem to '%s'",
221 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
225 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
226 // ---------------------------------------------------------------------
227 /* Get a sub-index file based on checksums from a 'master' file and
228 possibly query additional files */
229 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
230 string
const &URIDesc
, string
const &ShortDesc
,
231 HashString
const &ExpectedHash
)
232 : Item(Owner
), ExpectedHash(ExpectedHash
)
234 /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
235 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
237 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
238 DestFile
+= URItoFileName(URI
);
241 Desc
.Description
= URIDesc
;
243 Desc
.ShortDesc
= ShortDesc
;
248 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
251 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
252 // ---------------------------------------------------------------------
253 /* The only header we use is the last-modified header. */
254 string
pkgAcqSubIndex::Custom600Headers()
256 string Final
= _config
->FindDir("Dir::State::lists");
257 Final
+= URItoFileName(Desc
.URI
);
260 if (stat(Final
.c_str(),&Buf
) != 0)
261 return "\nIndex-File: true\nFail-Ignore: true\n";
262 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
265 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
268 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
274 // No good Index is provided
277 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
278 pkgAcquire::MethodConfig
*Cnf
)
281 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
283 string FileName
= LookupTag(Message
,"Filename");
284 if (FileName
.empty() == true)
287 ErrorText
= "Method gave a blank filename";
291 if (FileName
!= DestFile
)
294 Desc
.URI
= "copy:" + FileName
;
299 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
301 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
303 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
304 indexRecords SubIndexParser
;
305 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
307 ErrorText
= SubIndexParser
.ErrorText
;
311 // success in downloading the index
314 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
315 Rename(DestFile
,FinalFile
);
316 chmod(FinalFile
.c_str(),0644);
317 DestFile
= FinalFile
;
319 if(ParseIndex(DestFile
) == false)
320 return Failed("", NULL
);
328 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
330 indexRecords SubIndexParser
;
331 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
333 // so something with the downloaded index
337 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
338 // ---------------------------------------------------------------------
339 /* Get the DiffIndex file first and see if there are patches available
340 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
341 * patches. If anything goes wrong in that process, it will fall back to
342 * the original packages file
344 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
345 string URI
,string URIDesc
,string ShortDesc
,
346 HashString ExpectedHash
)
347 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
351 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
353 Desc
.Description
= URIDesc
+ "/DiffIndex";
355 Desc
.ShortDesc
= ShortDesc
;
356 Desc
.URI
= URI
+ ".diff/Index";
358 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
359 DestFile
+= URItoFileName(Desc
.URI
);
362 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
364 // look for the current package file
365 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
366 CurrentPackagesFile
+= URItoFileName(RealURI
);
368 // FIXME: this file:/ check is a hack to prevent fetching
369 // from local sources. this is really silly, and
370 // should be fixed cleanly as soon as possible
371 if(!FileExists(CurrentPackagesFile
) ||
372 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
374 // we don't have a pkg file or we don't want to queue
376 std::clog
<< "No index file, local or canceld by user" << std::endl
;
382 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
383 << CurrentPackagesFile
<< std::endl
;
389 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
390 // ---------------------------------------------------------------------
391 /* The only header we use is the last-modified header. */
392 string
pkgAcqDiffIndex::Custom600Headers()
394 string Final
= _config
->FindDir("Dir::State::lists");
395 Final
+= URItoFileName(Desc
.URI
);
398 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
401 if (stat(Final
.c_str(),&Buf
) != 0)
402 return "\nIndex-File: true";
404 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
407 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
410 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
415 vector
<DiffInfo
> available_patches
;
417 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
419 if (_error
->PendingError() == true)
422 if(TF
.Step(Tags
) == true)
428 string
const tmp
= Tags
.FindS("SHA1-Current");
429 std::stringstream
ss(tmp
);
430 ss
>> ServerSha1
>> size
;
431 unsigned long const ServerSize
= atol(size
.c_str());
433 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
436 string
const local_sha1
= SHA1
.Result();
438 if(local_sha1
== ServerSha1
)
440 // we have the same sha1 as the server so we are done here
442 std::clog
<< "Package file is up-to-date" << std::endl
;
443 // list cleanup needs to know that this file as well as the already
444 // present index is ours, so we create an empty diff to save it for us
445 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
446 ExpectedHash
, ServerSha1
, available_patches
);
452 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
454 // check the historie and see what patches we need
455 string
const history
= Tags
.FindS("SHA1-History");
456 std::stringstream
hist(history
);
457 while(hist
>> d
.sha1
>> size
>> d
.file
)
459 // read until the first match is found
460 // from that point on, we probably need all diffs
461 if(d
.sha1
== local_sha1
)
463 else if (found
== false)
467 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
468 available_patches
.push_back(d
);
471 if (available_patches
.empty() == false)
473 // patching with too many files is rather slow compared to a fast download
474 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
475 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
478 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
479 << ") so fallback to complete download" << std::endl
;
483 // see if the patches are too big
484 found
= false; // it was true and it will be true again at the end
485 d
= *available_patches
.begin();
486 string
const firstPatch
= d
.file
;
487 unsigned long patchesSize
= 0;
488 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
489 while(patches
>> d
.sha1
>> size
>> d
.file
)
491 if (firstPatch
== d
.file
)
493 else if (found
== false)
496 patchesSize
+= atol(size
.c_str());
498 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
499 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
502 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
503 << ") so fallback to complete download" << std::endl
;
509 // we have something, queue the next diff
513 string::size_type
const last_space
= Description
.rfind(" ");
514 if(last_space
!= string::npos
)
515 Description
.erase(last_space
, Description
.size()-last_space
);
517 /* decide if we should download patches one by one or in one go:
518 The first is good if the server merges patches, but many don't so client
519 based merging can be attempt in which case the second is better.
520 "bad things" will happen if patches are merged on the server,
521 but client side merging is attempt as well */
522 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
523 if (pdiff_merge
== true)
525 // reprepro adds this flag if it has merged patches on the server
526 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
527 pdiff_merge
= (precedence
!= "merged");
530 if (pdiff_merge
== false)
531 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
532 ExpectedHash
, ServerSha1
, available_patches
);
535 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
536 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
537 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
, ExpectedHash
,
538 available_patches
[i
], diffs
);
548 // Nothing found, report and return false
549 // Failing here is ok, if we return false later, the full
550 // IndexFile is queued
552 std::clog
<< "Can't find a patch in the index file" << std::endl
;
556 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
559 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
560 << "Falling back to normal index file acquire" << std::endl
;
562 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
570 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
571 pkgAcquire::MethodConfig
*Cnf
)
574 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
576 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
579 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
581 // success in downloading the index
583 FinalFile
+= string(".IndexDiff");
585 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
587 Rename(DestFile
,FinalFile
);
588 chmod(FinalFile
.c_str(),0644);
589 DestFile
= FinalFile
;
591 if(!ParseDiffIndex(DestFile
))
592 return Failed("", NULL
);
600 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
601 // ---------------------------------------------------------------------
602 /* The package diff is added to the queue. one object is constructed
603 * for each diff and the index
605 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
606 string URI
,string URIDesc
,string ShortDesc
,
607 HashString ExpectedHash
,
609 vector
<DiffInfo
> diffs
)
610 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
611 available_patches(diffs
), ServerSha1(ServerSha1
)
614 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
615 DestFile
+= URItoFileName(URI
);
617 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
619 Description
= URIDesc
;
621 Desc
.ShortDesc
= ShortDesc
;
623 if(available_patches
.empty() == true)
625 // we are done (yeah!)
631 State
= StateFetchDiff
;
636 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
639 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
640 << "Falling back to normal index file acquire" << std::endl
;
641 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
646 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
647 void pkgAcqIndexDiffs::Finish(bool allDone
)
649 // we restore the original name, this is required, otherwise
650 // the file will be cleaned
653 DestFile
= _config
->FindDir("Dir::State::lists");
654 DestFile
+= URItoFileName(RealURI
);
656 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
658 RenameOnError(HashSumMismatch
);
663 // this is for the "real" finish
668 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
673 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
680 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
683 // calc sha1 of the just patched file
684 string FinalFile
= _config
->FindDir("Dir::State::lists");
685 FinalFile
+= URItoFileName(RealURI
);
687 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
690 string local_sha1
= string(SHA1
.Result());
692 std::clog
<< "QueueNextDiff: "
693 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
695 // final file reached before all patches are applied
696 if(local_sha1
== ServerSha1
)
702 // remove all patches until the next matching patch is found
703 // this requires the Index file to be ordered
704 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
705 available_patches
.empty() == false &&
706 I
!= available_patches
.end() &&
707 I
->sha1
!= local_sha1
;
710 available_patches
.erase(I
);
713 // error checking and falling back if no patch was found
714 if(available_patches
.empty() == true)
720 // queue the right diff
721 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
722 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
723 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
724 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
727 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
734 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
735 pkgAcquire::MethodConfig
*Cnf
)
738 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
740 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
743 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
745 // success in downloading a diff, enter ApplyDiff state
746 if(State
== StateFetchDiff
)
749 // rred excepts the patch as $FinalFile.ed
750 Rename(DestFile
,FinalFile
+".ed");
753 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
755 State
= StateApplyDiff
;
757 Desc
.URI
= "rred:" + FinalFile
;
764 // success in download/apply a diff, queue next (if needed)
765 if(State
== StateApplyDiff
)
767 // remove the just applied patch
768 available_patches
.erase(available_patches
.begin());
769 unlink((FinalFile
+ ".ed").c_str());
774 std::clog
<< "Moving patched file in place: " << std::endl
775 << DestFile
<< " -> " << FinalFile
<< std::endl
;
777 Rename(DestFile
,FinalFile
);
778 chmod(FinalFile
.c_str(),0644);
780 // see if there is more to download
781 if(available_patches
.empty() == false) {
782 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
783 ExpectedHash
, ServerSha1
, available_patches
);
790 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
791 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
792 string
const &URI
, string
const &URIDesc
,
793 string
const &ShortDesc
, HashString
const &ExpectedHash
,
794 DiffInfo
const &patch
,
795 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
796 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
797 patch(patch
),allPatches(allPatches
), State(StateFetchDiff
)
800 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
801 DestFile
+= URItoFileName(URI
);
803 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
805 Description
= URIDesc
;
807 Desc
.ShortDesc
= ShortDesc
;
809 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
810 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
811 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
812 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
815 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
820 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
823 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
828 // check if we are the first to fail, otherwise we are done here
829 State
= StateDoneDiff
;
830 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
831 I
!= allPatches
->end(); ++I
)
832 if ((*I
)->State
== StateErrorDiff
)
835 // first failure means we should fallback
836 State
= StateErrorDiff
;
837 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
838 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
842 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
843 pkgAcquire::MethodConfig
*Cnf
)
846 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
848 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
850 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
852 if (State
== StateFetchDiff
)
854 // rred expects the patch as $FinalFile.ed.$patchname.gz
855 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
857 // check if this is the last completed diff
858 State
= StateDoneDiff
;
859 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
860 I
!= allPatches
->end(); ++I
)
861 if ((*I
)->State
!= StateDoneDiff
)
864 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
868 // this is the last completed diff, so we are ready to apply now
869 State
= StateApplyDiff
;
872 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
875 Desc
.URI
= "rred:" + FinalFile
;
880 // success in download/apply all diffs, clean up
881 else if (State
== StateApplyDiff
)
883 // see if we really got the expected file
884 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
886 RenameOnError(HashSumMismatch
);
890 // move the result into place
892 std::clog
<< "Moving patched file in place: " << std::endl
893 << DestFile
<< " -> " << FinalFile
<< std::endl
;
894 Rename(DestFile
, FinalFile
);
895 chmod(FinalFile
.c_str(), 0644);
897 // otherwise lists cleanup will eat the file
898 DestFile
= FinalFile
;
900 // ensure the ed's are gone regardless of list-cleanup
901 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
902 I
!= allPatches
->end(); ++I
)
904 std::string patch
= FinalFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
905 unlink(patch
.c_str());
911 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
915 // AcqIndex::AcqIndex - Constructor /*{{{*/
916 // ---------------------------------------------------------------------
917 /* The package file is added to the queue and a second class is
918 instantiated to fetch the revision file */
919 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
920 string URI
,string URIDesc
,string ShortDesc
,
921 HashString ExpectedHash
, string comprExt
)
922 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
924 if(comprExt
.empty() == true)
926 // autoselect the compression method
927 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
928 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
929 comprExt
.append(*t
).append(" ");
930 if (comprExt
.empty() == false)
931 comprExt
.erase(comprExt
.end()-1);
933 CompressionExtension
= comprExt
;
935 Init(URI
, URIDesc
, ShortDesc
);
937 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
938 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
939 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
941 // autoselect the compression method
942 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
943 CompressionExtension
= "";
944 if (ExpectedHash
.empty() == false)
946 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
947 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
948 CompressionExtension
.append(*t
).append(" ");
952 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
953 CompressionExtension
.append(*t
).append(" ");
955 if (CompressionExtension
.empty() == false)
956 CompressionExtension
.erase(CompressionExtension
.end()-1);
958 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
961 // AcqIndex::Init - defered Constructor /*{{{*/
962 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
963 Decompression
= false;
966 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
967 DestFile
+= URItoFileName(URI
);
969 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
970 if (comprExt
== "uncompressed")
973 Desc
.URI
= URI
+ '.' + comprExt
;
975 Desc
.Description
= URIDesc
;
977 Desc
.ShortDesc
= ShortDesc
;
982 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
983 // ---------------------------------------------------------------------
984 /* The only header we use is the last-modified header. */
985 string
pkgAcqIndex::Custom600Headers()
987 string Final
= _config
->FindDir("Dir::State::lists");
988 Final
+= URItoFileName(RealURI
);
989 if (_config
->FindB("Acquire::GzipIndexes",false))
992 string msg
= "\nIndex-File: true";
993 // FIXME: this really should use "IndexTarget::IsOptional()" but that
994 // seems to be difficult without breaking ABI
995 if (ShortDesc().find("Translation") != 0)
996 msg
+= "\nFail-Ignore: true";
998 if (stat(Final
.c_str(),&Buf
) == 0)
999 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1004 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1006 size_t const nextExt
= CompressionExtension
.find(' ');
1007 if (nextExt
!= std::string::npos
)
1009 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1010 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1014 // on decompression failure, remove bad versions in partial/
1015 if (Decompression
&& Erase
) {
1016 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1017 s
.append(URItoFileName(RealURI
));
1021 Item::Failed(Message
,Cnf
);
1024 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1025 std::string
pkgAcqIndex::GetFinalFilename(std::string
const &URI
,
1026 std::string
const &compExt
)
1028 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1029 FinalFile
+= URItoFileName(URI
);
1030 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1035 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1036 void pkgAcqIndex::ReverifyAfterIMS(std::string
const &FileName
)
1038 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1039 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1042 string FinalFile
= GetFinalFilename(RealURI
, compExt
);
1043 Rename(FinalFile
, FileName
);
1044 Decompression
= true;
1045 Desc
.URI
= "copy:" + FileName
;
1049 // AcqIndex::Done - Finished a fetch /*{{{*/
1050 // ---------------------------------------------------------------------
1051 /* This goes through a number of states.. On the initial fetch the
1052 method could possibly return an alternate filename which points
1053 to the uncompressed version of the file. If this is so the file
1054 is copied into the partial directory. In all other cases the file
1055 is decompressed with a gzip uri. */
1056 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
1057 pkgAcquire::MethodConfig
*Cfg
)
1059 Item::Done(Message
,Size
,Hash
,Cfg
);
1060 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1062 if (Decompression
== true)
1064 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1066 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
1067 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
1070 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
1073 RenameOnError(HashSumMismatch
);
1077 // FIXME: this can go away once we only ever download stuff that
1078 // has a valid hash and we never do GET based probing
1080 /* Always verify the index file for correctness (all indexes must
1081 * have a Package field) (LP: #346386) (Closes: #627642)
1083 FileFd
fd(DestFile
, FileFd::ReadOnlyGzip
);
1084 // Only test for correctness if the file is not empty (empty is ok)
1088 pkgTagFile
tag(&fd
);
1090 // all our current indexes have a field 'Package' in each section
1091 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1093 RenameOnError(InvalidFormat
);
1098 // Done, move it into position
1099 string FinalFile
= GetFinalFilename(RealURI
, compExt
);
1100 Rename(DestFile
,FinalFile
);
1101 chmod(FinalFile
.c_str(),0644);
1103 /* We restore the original name to DestFile so that the clean operation
1105 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1106 DestFile
+= URItoFileName(RealURI
);
1107 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1110 // Remove the compressed version.
1112 unlink(DestFile
.c_str());
1119 // Handle the unzipd case
1120 string FileName
= LookupTag(Message
,"Alt-Filename");
1121 if (FileName
.empty() == false)
1123 // The files timestamp matches
1124 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
1126 ReverifyAfterIMS(FileName
);
1129 Decompression
= true;
1131 DestFile
+= ".decomp";
1132 Desc
.URI
= "copy:" + FileName
;
1138 FileName
= LookupTag(Message
,"Filename");
1139 if (FileName
.empty() == true)
1142 ErrorText
= "Method gave a blank filename";
1145 // The files timestamp matches
1146 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1148 ReverifyAfterIMS(FileName
);
1152 if (FileName
== DestFile
)
1159 // If we enable compressed indexes, queue for hash verification
1160 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
)
1162 DestFile
= _config
->FindDir("Dir::State::lists");
1163 DestFile
+= URItoFileName(RealURI
) + ".gz";
1165 Decompression
= true;
1166 Desc
.URI
= "copy:" + FileName
;
1172 // get the binary name for your used compression type
1173 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1174 if(decompProg
.empty() == false);
1175 else if(compExt
== "uncompressed")
1176 decompProg
= "copy";
1178 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1182 Decompression
= true;
1183 DestFile
+= ".decomp";
1184 Desc
.URI
= decompProg
+ ":" + FileName
;
1187 // FIXME: this points to a c++ string that goes out of scope
1188 Mode
= decompProg
.c_str();
1191 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1192 // ---------------------------------------------------------------------
1193 /* The Translation file is added to the queue */
1194 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1195 string URI
,string URIDesc
,string ShortDesc
)
1196 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1199 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1200 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1201 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1205 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1206 // ---------------------------------------------------------------------
1207 string
pkgAcqIndexTrans::Custom600Headers()
1209 string Final
= _config
->FindDir("Dir::State::lists");
1210 Final
+= URItoFileName(RealURI
);
1212 if (_config
->FindB("Acquire::GzipIndexes",false))
1216 if (stat(Final
.c_str(),&Buf
) != 0)
1217 return "\nFail-Ignore: true\nIndex-File: true";
1218 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1221 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1222 // ---------------------------------------------------------------------
1224 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1226 size_t const nextExt
= CompressionExtension
.find(' ');
1227 if (nextExt
!= std::string::npos
)
1229 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1230 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1235 if (Cnf
->LocalOnly
== true ||
1236 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1245 Item::Failed(Message
,Cnf
);
1248 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1249 string URI
,string URIDesc
,string ShortDesc
,
1250 string MetaIndexURI
, string MetaIndexURIDesc
,
1251 string MetaIndexShortDesc
,
1252 const vector
<IndexTarget
*>* IndexTargets
,
1253 indexRecords
* MetaIndexParser
) :
1254 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1255 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1256 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1258 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1259 DestFile
+= URItoFileName(URI
);
1261 // remove any partial downloaded sig-file in partial/.
1262 // it may confuse proxies and is too small to warrant a
1263 // partial download anyway
1264 unlink(DestFile
.c_str());
1267 Desc
.Description
= URIDesc
;
1269 Desc
.ShortDesc
= ShortDesc
;
1272 string Final
= _config
->FindDir("Dir::State::lists");
1273 Final
+= URItoFileName(RealURI
);
1274 if (RealFileExists(Final
) == true)
1276 // File was already in place. It needs to be re-downloaded/verified
1277 // because Release might have changed, we do give it a different
1278 // name than DestFile because otherwise the http method will
1279 // send If-Range requests and there are too many broken servers
1280 // out there that do not understand them
1281 LastGoodSig
= DestFile
+".reverify";
1282 Rename(Final
,LastGoodSig
);
1288 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1290 // if the file was never queued undo file-changes done in the constructor
1291 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1292 LastGoodSig
.empty() == false)
1294 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1295 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1296 Rename(LastGoodSig
, Final
);
1301 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1302 // ---------------------------------------------------------------------
1303 /* The only header we use is the last-modified header. */
1304 string
pkgAcqMetaSig::Custom600Headers()
1307 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1308 return "\nIndex-File: true";
1310 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1313 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1314 pkgAcquire::MethodConfig
*Cfg
)
1316 Item::Done(Message
,Size
,MD5
,Cfg
);
1318 string FileName
= LookupTag(Message
,"Filename");
1319 if (FileName
.empty() == true)
1322 ErrorText
= "Method gave a blank filename";
1326 if (FileName
!= DestFile
)
1328 // We have to copy it into place
1330 Desc
.URI
= "copy:" + FileName
;
1337 // put the last known good file back on i-m-s hit (it will
1338 // be re-verified again)
1339 // Else do nothing, we have the new file in DestFile then
1340 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1341 Rename(LastGoodSig
, DestFile
);
1343 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1344 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1345 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1350 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1352 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1354 // if we get a network error we fail gracefully
1355 if(Status
== StatTransientNetworkError
)
1357 Item::Failed(Message
,Cnf
);
1358 // move the sigfile back on transient network failures
1359 if(FileExists(LastGoodSig
))
1360 Rename(LastGoodSig
,Final
);
1362 // set the status back to , Item::Failed likes to reset it
1363 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1367 // Delete any existing sigfile when the acquire failed
1368 unlink(Final
.c_str());
1370 // queue a pkgAcqMetaIndex with no sigfile
1371 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1372 "", IndexTargets
, MetaIndexParser
);
1374 if (Cnf
->LocalOnly
== true ||
1375 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1384 Item::Failed(Message
,Cnf
);
1387 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1388 string URI
,string URIDesc
,string ShortDesc
,
1390 const vector
<struct IndexTarget
*>* IndexTargets
,
1391 indexRecords
* MetaIndexParser
) :
1392 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1393 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1395 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1396 DestFile
+= URItoFileName(URI
);
1399 Desc
.Description
= URIDesc
;
1401 Desc
.ShortDesc
= ShortDesc
;
1407 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1408 // ---------------------------------------------------------------------
1409 /* The only header we use is the last-modified header. */
1410 string
pkgAcqMetaIndex::Custom600Headers()
1412 string Final
= _config
->FindDir("Dir::State::lists");
1413 Final
+= URItoFileName(RealURI
);
1416 if (stat(Final
.c_str(),&Buf
) != 0)
1417 return "\nIndex-File: true";
1419 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1422 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1423 pkgAcquire::MethodConfig
*Cfg
)
1425 Item::Done(Message
,Size
,Hash
,Cfg
);
1427 // MetaIndexes are done in two passes: one to download the
1428 // metaindex with an appropriate method, and a second to verify it
1429 // with the gpgv method
1431 if (AuthPass
== true)
1435 // all cool, move Release file into place
1440 RetrievalDone(Message
);
1442 // Still more retrieving to do
1447 // There was no signature file, so we are finished. Download
1448 // the indexes and do only hashsum verification if possible
1449 MetaIndexParser
->Load(DestFile
);
1450 QueueIndexes(false);
1454 // There was a signature file, so pass it to gpgv for
1457 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1458 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1459 << SigFile
<< "," << DestFile
<< ")\n";
1461 Desc
.URI
= "gpgv:" + SigFile
;
1468 if (Complete
== true)
1470 string FinalFile
= _config
->FindDir("Dir::State::lists");
1471 FinalFile
+= URItoFileName(RealURI
);
1472 if (SigFile
== DestFile
)
1473 SigFile
= FinalFile
;
1474 Rename(DestFile
,FinalFile
);
1475 chmod(FinalFile
.c_str(),0644);
1476 DestFile
= FinalFile
;
1480 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1482 // We have just finished downloading a Release file (it is not
1485 string FileName
= LookupTag(Message
,"Filename");
1486 if (FileName
.empty() == true)
1489 ErrorText
= "Method gave a blank filename";
1493 if (FileName
!= DestFile
)
1496 Desc
.URI
= "copy:" + FileName
;
1501 // make sure to verify against the right file on I-M-S hit
1502 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1505 string FinalFile
= _config
->FindDir("Dir::State::lists");
1506 FinalFile
+= URItoFileName(RealURI
);
1507 if (SigFile
== DestFile
)
1509 SigFile
= FinalFile
;
1510 // constructor of pkgAcqMetaClearSig moved it out of the way,
1511 // now move it back in on IMS hit for the 'old' file
1512 string
const OldClearSig
= DestFile
+ ".reverify";
1513 if (RealFileExists(OldClearSig
) == true)
1514 Rename(OldClearSig
, FinalFile
);
1516 DestFile
= FinalFile
;
1521 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1523 // At this point, the gpgv method has succeeded, so there is a
1524 // valid signature from a key in the trusted keyring. We
1525 // perform additional verification of its contents, and use them
1526 // to verify the indexes we are about to download
1528 if (!MetaIndexParser
->Load(DestFile
))
1530 Status
= StatAuthError
;
1531 ErrorText
= MetaIndexParser
->ErrorText
;
1535 if (!VerifyVendor(Message
))
1540 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1541 std::cerr
<< "Signature verification succeeded: "
1542 << DestFile
<< std::endl
;
1544 // do not trust any previously unverified content that we may have
1545 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1546 if (DestFile
!= SigFile
)
1547 LastGoodSigFile
.append(".gpg");
1548 LastGoodSigFile
.append(".reverify");
1549 if(IMSHit
== false && RealFileExists(LastGoodSigFile
) == false)
1551 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1552 Target
!= IndexTargets
->end();
1555 // remove old indexes
1556 std::string index
= _config
->FindDir("Dir::State::lists") +
1557 URItoFileName((*Target
)->URI
);
1558 unlink(index
.c_str());
1559 // and also old gzipindexes
1561 unlink(index
.c_str());
1566 // Download further indexes with verification
1569 // is it a clearsigned MetaIndex file?
1570 if (DestFile
== SigFile
)
1573 // Done, move signature file into position
1574 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1575 URItoFileName(RealURI
) + ".gpg";
1576 Rename(SigFile
,VerifiedSigFile
);
1577 chmod(VerifiedSigFile
.c_str(),0644);
1580 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1583 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1584 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1585 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1588 ErrorText
= MetaIndexParser
->ErrorText
;
1592 bool transInRelease
= false;
1594 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1595 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1596 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1597 if (k
->find("Translation-") != std::string::npos
)
1599 transInRelease
= true;
1604 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1605 Target
!= IndexTargets
->end();
1608 HashString ExpectedIndexHash
;
1609 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1610 bool compressedAvailable
= false;
1613 if ((*Target
)->IsOptional() == true)
1615 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1616 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1617 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1619 compressedAvailable
= true;
1623 else if (verify
== true)
1625 Status
= StatAuthError
;
1626 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1632 ExpectedIndexHash
= Record
->Hash
;
1633 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1635 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1636 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1637 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1639 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1641 Status
= StatAuthError
;
1642 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1647 if ((*Target
)->IsOptional() == true)
1649 if ((*Target
)->IsSubIndex() == true)
1650 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1651 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1652 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1654 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1655 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1656 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1657 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1659 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1664 /* Queue Packages file (either diff or full packages files, depending
1665 on the users option) - we also check if the PDiff Index file is listed
1666 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1667 instead, but passing the required info to it is to much hassle */
1668 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1669 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1670 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1671 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1673 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1677 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1679 string::size_type pos
;
1681 // check for missing sigs (that where not fatal because otherwise we had
1684 string msg
= _("There is no public key available for the "
1685 "following key IDs:\n");
1686 pos
= Message
.find("NO_PUBKEY ");
1687 if (pos
!= std::string::npos
)
1689 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1690 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1691 missingkeys
+= (Fingerprint
);
1693 if(!missingkeys
.empty())
1694 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1696 string Transformed
= MetaIndexParser
->GetExpectedDist();
1698 if (Transformed
== "../project/experimental")
1700 Transformed
= "experimental";
1703 pos
= Transformed
.rfind('/');
1704 if (pos
!= string::npos
)
1706 Transformed
= Transformed
.substr(0, pos
);
1709 if (Transformed
== ".")
1714 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1715 MetaIndexParser
->GetValidUntil() > 0) {
1716 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1717 if (invalid_since
> 0)
1718 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1719 // the time since then the file is invalid - formated in the same way as in
1720 // the download progress display (e.g. 7d 3h 42min 1s)
1721 return _error
->Error(
1722 _("Release file for %s is expired (invalid since %s). "
1723 "Updates for this repository will not be applied."),
1724 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1727 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1729 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1730 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1731 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1734 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1736 // This might become fatal one day
1737 // Status = StatAuthError;
1738 // ErrorText = "Conflicting distribution; expected "
1739 // + MetaIndexParser->GetExpectedDist() + " but got "
1740 // + MetaIndexParser->GetDist();
1742 if (!Transformed
.empty())
1744 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1745 Desc
.Description
.c_str(),
1746 Transformed
.c_str(),
1747 MetaIndexParser
->GetDist().c_str());
1754 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1755 // ---------------------------------------------------------------------
1757 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)
1759 if (AuthPass
== true)
1761 // gpgv method failed, if we have a good signature
1762 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1763 if (DestFile
!= SigFile
)
1764 LastGoodSigFile
.append(".gpg");
1765 LastGoodSigFile
.append(".reverify");
1767 if(FileExists(LastGoodSigFile
))
1769 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1770 if (DestFile
!= SigFile
)
1771 VerifiedSigFile
.append(".gpg");
1772 Rename(LastGoodSigFile
, VerifiedSigFile
);
1773 Status
= StatTransientNetworkError
;
1774 _error
->Warning(_("An error occurred during the signature "
1775 "verification. The repository is not updated "
1776 "and the previous index files will be used. "
1777 "GPG error: %s: %s\n"),
1778 Desc
.Description
.c_str(),
1779 LookupTag(Message
,"Message").c_str());
1780 RunScripts("APT::Update::Auth-Failure");
1782 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1783 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1784 _error
->Error(_("GPG error: %s: %s"),
1785 Desc
.Description
.c_str(),
1786 LookupTag(Message
,"Message").c_str());
1789 _error
->Warning(_("GPG error: %s: %s"),
1790 Desc
.Description
.c_str(),
1791 LookupTag(Message
,"Message").c_str());
1793 // gpgv method failed
1794 ReportMirrorFailure("GPGFailure");
1797 /* Always move the meta index, even if gpgv failed. This ensures
1798 * that PackageFile objects are correctly filled in */
1799 if (FileExists(DestFile
)) {
1800 string FinalFile
= _config
->FindDir("Dir::State::lists");
1801 FinalFile
+= URItoFileName(RealURI
);
1802 /* InRelease files become Release files, otherwise
1803 * they would be considered as trusted later on */
1804 if (SigFile
== DestFile
) {
1805 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1807 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1809 SigFile
= FinalFile
;
1811 Rename(DestFile
,FinalFile
);
1812 chmod(FinalFile
.c_str(),0644);
1814 DestFile
= FinalFile
;
1817 // No Release file was present, or verification failed, so fall
1818 // back to queueing Packages files without verification
1819 QueueIndexes(false);
1822 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1823 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1824 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1825 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1826 const vector
<struct IndexTarget
*>* IndexTargets
,
1827 indexRecords
* MetaIndexParser
) :
1828 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1829 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1830 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1834 // keep the old InRelease around in case of transistent network errors
1835 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1836 if (RealFileExists(Final
) == true)
1838 string
const LastGoodSig
= DestFile
+ ".reverify";
1839 Rename(Final
,LastGoodSig
);
1843 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1845 // if the file was never queued undo file-changes done in the constructor
1846 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1848 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1849 string
const LastGoodSig
= DestFile
+ ".reverify";
1850 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1851 Rename(LastGoodSig
, Final
);
1855 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1856 // ---------------------------------------------------------------------
1857 // FIXME: this can go away once the InRelease file is used widely
1858 string
pkgAcqMetaClearSig::Custom600Headers()
1860 string Final
= _config
->FindDir("Dir::State::lists");
1861 Final
+= URItoFileName(RealURI
);
1864 if (stat(Final
.c_str(),&Buf
) != 0)
1866 Final
= DestFile
+ ".reverify";
1867 if (stat(Final
.c_str(),&Buf
) != 0)
1868 return "\nIndex-File: true\nFail-Ignore: true\n";
1871 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1874 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1876 if (AuthPass
== false)
1878 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1879 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1880 string FinalFile
= _config
->FindDir("Dir::State::lists");
1881 FinalFile
.append(URItoFileName(RealURI
));
1882 if (FileExists(FinalFile
))
1883 unlink(FinalFile
.c_str());
1885 new pkgAcqMetaSig(Owner
,
1886 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1887 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1888 IndexTargets
, MetaIndexParser
);
1889 if (Cnf
->LocalOnly
== true ||
1890 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1894 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1897 // AcqArchive::AcqArchive - Constructor /*{{{*/
1898 // ---------------------------------------------------------------------
1899 /* This just sets up the initial fetch environment and queues the first
1901 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1902 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1903 string
&StoreFilename
) :
1904 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1905 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1908 Retries
= _config
->FindI("Acquire::Retries",0);
1910 if (Version
.Arch() == 0)
1912 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1913 "This might mean you need to manually fix this package. "
1914 "(due to missing arch)"),
1915 Version
.ParentPkg().FullName().c_str());
1919 /* We need to find a filename to determine the extension. We make the
1920 assumption here that all the available sources for this version share
1921 the same extension.. */
1922 // Skip not source sources, they do not have file fields.
1923 for (; Vf
.end() == false; ++Vf
)
1925 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1930 // Does not really matter here.. we are going to fail out below
1931 if (Vf
.end() != true)
1933 // If this fails to get a file name we will bomb out below.
1934 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1935 if (_error
->PendingError() == true)
1938 // Generate the final file name as: package_version_arch.foo
1939 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1940 QuoteString(Version
.VerStr(),"_:") + '_' +
1941 QuoteString(Version
.Arch(),"_:.") +
1942 "." + flExtension(Parse
.FileName());
1945 // check if we have one trusted source for the package. if so, switch
1946 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1947 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
1948 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
1949 bool seenUntrusted
= false;
1950 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1952 pkgIndexFile
*Index
;
1953 if (Sources
->FindIndex(i
.File(),Index
) == false)
1956 if (debugAuth
== true)
1957 std::cerr
<< "Checking index: " << Index
->Describe()
1958 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
1960 if (Index
->IsTrusted() == true)
1963 if (allowUnauth
== false)
1967 seenUntrusted
= true;
1970 // "allow-unauthenticated" restores apts old fetching behaviour
1971 // that means that e.g. unauthenticated file:// uris are higher
1972 // priority than authenticated http:// uris
1973 if (allowUnauth
== true && seenUntrusted
== true)
1977 if (QueueNext() == false && _error
->PendingError() == false)
1978 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
1979 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
1982 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1983 // ---------------------------------------------------------------------
1984 /* This queues the next available file version for download. It checks if
1985 the archive is already available in the cache and stashs the MD5 for
1987 bool pkgAcqArchive::QueueNext()
1989 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1990 for (; Vf
.end() == false; ++Vf
)
1992 // Ignore not source sources
1993 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1996 // Try to cross match against the source list
1997 pkgIndexFile
*Index
;
1998 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2001 // only try to get a trusted package from another source if that source
2003 if(Trusted
&& !Index
->IsTrusted())
2006 // Grab the text package record
2007 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2008 if (_error
->PendingError() == true)
2011 string PkgFile
= Parse
.FileName();
2012 if (ForceHash
.empty() == false)
2014 if(stringcasecmp(ForceHash
, "sha512") == 0)
2015 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
2016 else if(stringcasecmp(ForceHash
, "sha256") == 0)
2017 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
2018 else if (stringcasecmp(ForceHash
, "sha1") == 0)
2019 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
2021 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
2026 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
2027 ExpectedHash
= HashString("SHA512", Hash
);
2028 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
2029 ExpectedHash
= HashString("SHA256", Hash
);
2030 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
2031 ExpectedHash
= HashString("SHA1", Hash
);
2033 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
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
,string CalcHash
,
2122 pkgAcquire::MethodConfig
*Cfg
)
2124 Item::Done(Message
,Size
,CalcHash
,Cfg
);
2127 if (Size
!= Version
->Size
)
2129 RenameOnError(SizeMismatch
);
2134 if(ExpectedHash
.toStr() != CalcHash
)
2136 RenameOnError(HashSumMismatch
);
2140 // Grab the output filename
2141 string FileName
= LookupTag(Message
,"Filename");
2142 if (FileName
.empty() == true)
2145 ErrorText
= "Method gave a blank filename";
2151 // Reference filename
2152 if (FileName
!= DestFile
)
2154 StoreFilename
= DestFile
= FileName
;
2159 // Done, move it into position
2160 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2161 FinalFile
+= flNotDir(StoreFilename
);
2162 Rename(DestFile
,FinalFile
);
2164 StoreFilename
= DestFile
= FinalFile
;
2168 // AcqArchive::Failed - Failure handler /*{{{*/
2169 // ---------------------------------------------------------------------
2170 /* Here we try other sources */
2171 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2173 ErrorText
= LookupTag(Message
,"Message");
2175 /* We don't really want to retry on failed media swaps, this prevents
2176 that. An interesting observation is that permanent failures are not
2178 if (Cnf
->Removable
== true &&
2179 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2181 // Vf = Version.FileList();
2182 while (Vf
.end() == false) ++Vf
;
2183 StoreFilename
= string();
2184 Item::Failed(Message
,Cnf
);
2188 if (QueueNext() == false)
2190 // This is the retry counter
2192 Cnf
->LocalOnly
== false &&
2193 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2196 Vf
= Version
.FileList();
2197 if (QueueNext() == true)
2201 StoreFilename
= string();
2202 Item::Failed(Message
,Cnf
);
2206 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2207 // ---------------------------------------------------------------------
2208 APT_PURE
bool pkgAcqArchive::IsTrusted()
2213 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2214 // ---------------------------------------------------------------------
2216 void pkgAcqArchive::Finished()
2218 if (Status
== pkgAcquire::Item::StatDone
&&
2221 StoreFilename
= string();
2224 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2225 // ---------------------------------------------------------------------
2226 /* The file is added to the queue */
2227 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
2228 unsigned long long Size
,string Dsc
,string ShortDesc
,
2229 const string
&DestDir
, const string
&DestFilename
,
2231 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
2233 Retries
= _config
->FindI("Acquire::Retries",0);
2235 if(!DestFilename
.empty())
2236 DestFile
= DestFilename
;
2237 else if(!DestDir
.empty())
2238 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2240 DestFile
= flNotDir(URI
);
2244 Desc
.Description
= Dsc
;
2247 // Set the short description to the archive component
2248 Desc
.ShortDesc
= ShortDesc
;
2250 // Get the transfer sizes
2253 if (stat(DestFile
.c_str(),&Buf
) == 0)
2255 // Hmm, the partial file is too big, erase it
2256 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2257 unlink(DestFile
.c_str());
2259 PartialSize
= Buf
.st_size
;
2265 // AcqFile::Done - Item downloaded OK /*{{{*/
2266 // ---------------------------------------------------------------------
2268 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
2269 pkgAcquire::MethodConfig
*Cnf
)
2271 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2274 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2276 RenameOnError(HashSumMismatch
);
2280 string FileName
= LookupTag(Message
,"Filename");
2281 if (FileName
.empty() == true)
2284 ErrorText
= "Method gave a blank filename";
2290 // The files timestamp matches
2291 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2294 // We have to copy it into place
2295 if (FileName
!= DestFile
)
2298 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2299 Cnf
->Removable
== true)
2301 Desc
.URI
= "copy:" + FileName
;
2306 // Erase the file if it is a symlink so we can overwrite it
2308 if (lstat(DestFile
.c_str(),&St
) == 0)
2310 if (S_ISLNK(St
.st_mode
) != 0)
2311 unlink(DestFile
.c_str());
2315 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2317 ErrorText
= "Link to " + DestFile
+ " failure ";
2324 // AcqFile::Failed - Failure handler /*{{{*/
2325 // ---------------------------------------------------------------------
2326 /* Here we try other sources */
2327 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2329 ErrorText
= LookupTag(Message
,"Message");
2331 // This is the retry counter
2333 Cnf
->LocalOnly
== false &&
2334 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2341 Item::Failed(Message
,Cnf
);
2344 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2345 // ---------------------------------------------------------------------
2346 /* The only header we use is the last-modified header. */
2347 string
pkgAcqFile::Custom600Headers()
2350 return "\nIndex-File: true";