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/md5.h>
26 #include <apt-pkg/sha1.h>
27 #include <apt-pkg/tagfile.h>
28 #include <apt-pkg/indexrecords.h>
29 #include <apt-pkg/metaindex.h>
44 // Acquire::Item::Item - Constructor /*{{{*/
45 // ---------------------------------------------------------------------
47 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
48 PartialSize(0), Mode(0), ID(0), Complete(false),
49 Local(false), QueueCounter(0)
55 // Acquire::Item::~Item - Destructor /*{{{*/
56 // ---------------------------------------------------------------------
58 pkgAcquire::Item::~Item()
63 // Acquire::Item::Failed - Item failed to download /*{{{*/
64 // ---------------------------------------------------------------------
65 /* We return to an idle state if there are still other queues that could
67 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
70 ErrorText
= LookupTag(Message
,"Message");
71 UsedMirror
= LookupTag(Message
,"UsedMirror");
72 if (QueueCounter
<= 1)
74 /* This indicates that the file is not available right now but might
75 be sometime later. If we do a retry cycle then this should be
77 if (Cnf
->LocalOnly
== true &&
78 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
89 // report mirror failure back to LP if we actually use a mirror
90 string FailReason
= LookupTag(Message
, "FailReason");
91 if(FailReason
.size() != 0)
92 ReportMirrorFailure(FailReason
);
94 ReportMirrorFailure(ErrorText
);
97 // Acquire::Item::Start - Item has begun to download /*{{{*/
98 // ---------------------------------------------------------------------
99 /* Stash status and the file size. Note that setting Complete means
100 sub-phases of the acquire process such as decompresion are operating */
101 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
103 Status
= StatFetching
;
104 if (FileSize
== 0 && Complete
== false)
108 // Acquire::Item::Done - Item downloaded OK /*{{{*/
109 // ---------------------------------------------------------------------
111 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,string Hash
,
112 pkgAcquire::MethodConfig
*Cnf
)
114 // We just downloaded something..
115 string FileName
= LookupTag(Message
,"Filename");
116 UsedMirror
= LookupTag(Message
,"UsedMirror");
117 if (Complete
== false && !Local
&& FileName
== DestFile
)
120 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
126 ErrorText
= string();
127 Owner
->Dequeue(this);
130 // Acquire::Item::Rename - Rename a file /*{{{*/
131 // ---------------------------------------------------------------------
132 /* This helper function is used by alot of item methods as thier final
134 void pkgAcquire::Item::Rename(string From
,string To
)
136 if (rename(From
.c_str(),To
.c_str()) != 0)
139 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
140 From
.c_str(),To
.c_str());
146 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
148 if(FileExists(DestFile
))
149 Rename(DestFile
, DestFile
+ ".FAILED");
153 case HashSumMismatch
:
154 ErrorText
= _("Hash Sum mismatch");
155 Status
= StatAuthError
;
156 ReportMirrorFailure("HashChecksumFailure");
159 ErrorText
= _("Size mismatch");
160 Status
= StatAuthError
;
161 ReportMirrorFailure("SizeFailure");
164 ErrorText
= _("Invalid file format");
166 // do not report as usually its not the mirrors fault, but Portal/Proxy
172 // Acquire::Item::ReportMirrorFailure /*{{{*/
173 // ---------------------------------------------------------------------
174 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
176 // we only act if a mirror was used at all
177 if(UsedMirror
.empty())
180 std::cerr
<< "\nReportMirrorFailure: "
182 << " Uri: " << DescURI()
184 << FailCode
<< std::endl
;
186 const char *Args
[40];
188 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
189 "/usr/lib/apt/apt-report-mirror-failure");
190 if(!FileExists(report
))
192 Args
[i
++] = report
.c_str();
193 Args
[i
++] = UsedMirror
.c_str();
194 Args
[i
++] = DescURI().c_str();
195 Args
[i
++] = FailCode
.c_str();
197 pid_t pid
= ExecFork();
200 _error
->Error("ReportMirrorFailure Fork failed");
205 execvp(Args
[0], (char**)Args
);
206 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
209 if(!ExecWait(pid
, "report-mirror-failure"))
211 _error
->Warning("Couldn't report problem to '%s'",
212 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
216 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
217 // ---------------------------------------------------------------------
218 /* Get a sub-index file based on checksums from a 'master' file and
219 possibly query additional files */
220 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
221 string
const &URIDesc
, string
const &ShortDesc
,
222 HashString
const &ExpectedHash
)
223 : Item(Owner
), ExpectedHash(ExpectedHash
)
225 /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
226 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
228 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
229 DestFile
+= URItoFileName(URI
);
232 Desc
.Description
= URIDesc
;
234 Desc
.ShortDesc
= ShortDesc
;
239 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
242 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
243 // ---------------------------------------------------------------------
244 /* The only header we use is the last-modified header. */
245 string
pkgAcqSubIndex::Custom600Headers()
247 string Final
= _config
->FindDir("Dir::State::lists");
248 Final
+= URItoFileName(Desc
.URI
);
251 if (stat(Final
.c_str(),&Buf
) != 0)
252 return "\nIndex-File: true\nFail-Ignore: true\n";
253 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
256 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
259 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< std::endl
;
265 // No good Index is provided
268 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
269 pkgAcquire::MethodConfig
*Cnf
)
272 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
274 string FileName
= LookupTag(Message
,"Filename");
275 if (FileName
.empty() == true)
278 ErrorText
= "Method gave a blank filename";
282 if (FileName
!= DestFile
)
285 Desc
.URI
= "copy:" + FileName
;
290 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
292 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
294 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
295 indexRecords SubIndexParser
;
296 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
298 ErrorText
= SubIndexParser
.ErrorText
;
302 // sucess in downloading the index
305 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
306 Rename(DestFile
,FinalFile
);
307 chmod(FinalFile
.c_str(),0644);
308 DestFile
= FinalFile
;
310 if(ParseIndex(DestFile
) == false)
311 return Failed("", NULL
);
319 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
321 indexRecords SubIndexParser
;
322 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
324 // so something with the downloaded index
328 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
329 // ---------------------------------------------------------------------
330 /* Get the DiffIndex file first and see if there are patches availabe
331 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
332 * patches. If anything goes wrong in that process, it will fall back to
333 * the original packages file
335 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
336 string URI
,string URIDesc
,string ShortDesc
,
337 HashString ExpectedHash
)
338 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
342 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
344 Desc
.Description
= URIDesc
+ "/DiffIndex";
346 Desc
.ShortDesc
= ShortDesc
;
347 Desc
.URI
= URI
+ ".diff/Index";
349 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
350 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
353 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
355 // look for the current package file
356 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
357 CurrentPackagesFile
+= URItoFileName(RealURI
);
359 // FIXME: this file:/ check is a hack to prevent fetching
360 // from local sources. this is really silly, and
361 // should be fixed cleanly as soon as possible
362 if(!FileExists(CurrentPackagesFile
) ||
363 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
365 // we don't have a pkg file or we don't want to queue
367 std::clog
<< "No index file, local or canceld by user" << std::endl
;
373 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
374 << CurrentPackagesFile
<< std::endl
;
380 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
381 // ---------------------------------------------------------------------
382 /* The only header we use is the last-modified header. */
383 string
pkgAcqDiffIndex::Custom600Headers()
385 string Final
= _config
->FindDir("Dir::State::lists");
386 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
389 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
392 if (stat(Final
.c_str(),&Buf
) != 0)
393 return "\nIndex-File: true";
395 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
398 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
401 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
406 vector
<DiffInfo
> available_patches
;
408 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
410 if (_error
->PendingError() == true)
413 if(TF
.Step(Tags
) == true)
419 string
const tmp
= Tags
.FindS("SHA1-Current");
420 std::stringstream
ss(tmp
);
421 ss
>> ServerSha1
>> size
;
422 unsigned long const ServerSize
= atol(size
.c_str());
424 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
427 string
const local_sha1
= SHA1
.Result();
429 if(local_sha1
== ServerSha1
)
431 // we have the same sha1 as the server so we are done here
433 std::clog
<< "Package file is up-to-date" << std::endl
;
434 // list cleanup needs to know that this file as well as the already
435 // present index is ours, so we create an empty diff to save it for us
436 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
437 ExpectedHash
, ServerSha1
, available_patches
);
443 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
445 // check the historie and see what patches we need
446 string
const history
= Tags
.FindS("SHA1-History");
447 std::stringstream
hist(history
);
448 while(hist
>> d
.sha1
>> size
>> d
.file
)
450 // read until the first match is found
451 // from that point on, we probably need all diffs
452 if(d
.sha1
== local_sha1
)
454 else if (found
== false)
458 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
459 available_patches
.push_back(d
);
462 if (available_patches
.empty() == false)
464 // patching with too many files is rather slow compared to a fast download
465 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
466 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
469 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
470 << ") so fallback to complete download" << std::endl
;
474 // see if the patches are too big
475 found
= false; // it was true and it will be true again at the end
476 d
= *available_patches
.begin();
477 string
const firstPatch
= d
.file
;
478 unsigned long patchesSize
= 0;
479 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
480 while(patches
>> d
.sha1
>> size
>> d
.file
)
482 if (firstPatch
== d
.file
)
484 else if (found
== false)
487 patchesSize
+= atol(size
.c_str());
489 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
490 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
493 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
494 << ") so fallback to complete download" << std::endl
;
500 // we have something, queue the next diff
504 string::size_type
const last_space
= Description
.rfind(" ");
505 if(last_space
!= string::npos
)
506 Description
.erase(last_space
, Description
.size()-last_space
);
508 /* decide if we should download patches one by one or in one go:
509 The first is good if the server merges patches, but many don't so client
510 based merging can be attempt in which case the second is better.
511 "bad things" will happen if patches are merged on the server,
512 but client side merging is attempt as well */
513 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
514 if (pdiff_merge
== true)
516 // reprepro adds this flag if it has merged patches on the server
517 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
518 pdiff_merge
= (precedence
!= "merged");
521 if (pdiff_merge
== false)
522 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
523 ExpectedHash
, ServerSha1
, available_patches
);
526 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
527 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
528 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
, ExpectedHash
,
529 available_patches
[i
], diffs
);
539 // Nothing found, report and return false
540 // Failing here is ok, if we return false later, the full
541 // IndexFile is queued
543 std::clog
<< "Can't find a patch in the index file" << std::endl
;
547 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
550 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
551 << "Falling back to normal index file aquire" << std::endl
;
553 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
561 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
562 pkgAcquire::MethodConfig
*Cnf
)
565 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
567 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
570 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
572 // sucess in downloading the index
574 FinalFile
+= string(".IndexDiff");
576 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
578 Rename(DestFile
,FinalFile
);
579 chmod(FinalFile
.c_str(),0644);
580 DestFile
= FinalFile
;
582 if(!ParseDiffIndex(DestFile
))
583 return Failed("", NULL
);
591 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
592 // ---------------------------------------------------------------------
593 /* The package diff is added to the queue. one object is constructed
594 * for each diff and the index
596 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
597 string URI
,string URIDesc
,string ShortDesc
,
598 HashString ExpectedHash
,
600 vector
<DiffInfo
> diffs
)
601 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
602 available_patches(diffs
), ServerSha1(ServerSha1
)
605 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
606 DestFile
+= URItoFileName(URI
);
608 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
610 Description
= URIDesc
;
612 Desc
.ShortDesc
= ShortDesc
;
614 if(available_patches
.empty() == true)
616 // we are done (yeah!)
622 State
= StateFetchDiff
;
627 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
630 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
631 << "Falling back to normal index file aquire" << std::endl
;
632 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
637 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
638 void pkgAcqIndexDiffs::Finish(bool allDone
)
640 // we restore the original name, this is required, otherwise
641 // the file will be cleaned
644 DestFile
= _config
->FindDir("Dir::State::lists");
645 DestFile
+= URItoFileName(RealURI
);
647 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
649 RenameOnError(HashSumMismatch
);
654 // this is for the "real" finish
659 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
664 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
671 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
674 // calc sha1 of the just patched file
675 string FinalFile
= _config
->FindDir("Dir::State::lists");
676 FinalFile
+= URItoFileName(RealURI
);
678 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
681 string local_sha1
= string(SHA1
.Result());
683 std::clog
<< "QueueNextDiff: "
684 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
686 // final file reached before all patches are applied
687 if(local_sha1
== ServerSha1
)
693 // remove all patches until the next matching patch is found
694 // this requires the Index file to be ordered
695 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
696 available_patches
.empty() == false &&
697 I
!= available_patches
.end() &&
698 I
->sha1
!= local_sha1
;
701 available_patches
.erase(I
);
704 // error checking and falling back if no patch was found
705 if(available_patches
.empty() == true)
711 // queue the right diff
712 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
713 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
714 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
715 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
718 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
725 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
726 pkgAcquire::MethodConfig
*Cnf
)
729 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
731 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
734 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
736 // sucess in downloading a diff, enter ApplyDiff state
737 if(State
== StateFetchDiff
)
740 // rred excepts the patch as $FinalFile.ed
741 Rename(DestFile
,FinalFile
+".ed");
744 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
746 State
= StateApplyDiff
;
748 Desc
.URI
= "rred:" + FinalFile
;
755 // success in download/apply a diff, queue next (if needed)
756 if(State
== StateApplyDiff
)
758 // remove the just applied patch
759 available_patches
.erase(available_patches
.begin());
764 std::clog
<< "Moving patched file in place: " << std::endl
765 << DestFile
<< " -> " << FinalFile
<< std::endl
;
767 Rename(DestFile
,FinalFile
);
768 chmod(FinalFile
.c_str(),0644);
770 // see if there is more to download
771 if(available_patches
.empty() == false) {
772 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
773 ExpectedHash
, ServerSha1
, available_patches
);
780 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
781 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
782 string
const &URI
, string
const &URIDesc
,
783 string
const &ShortDesc
, HashString
const &ExpectedHash
,
784 DiffInfo
const &patch
,
785 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
786 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
787 patch(patch
),allPatches(allPatches
), State(StateFetchDiff
)
790 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
791 DestFile
+= URItoFileName(URI
);
793 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
795 Description
= URIDesc
;
797 Desc
.ShortDesc
= ShortDesc
;
799 Desc
.URI
= string(RealURI
) + ".diff/" + patch
.file
+ ".gz";
800 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
801 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
802 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
805 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
810 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
813 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
818 // check if we are the first to fail, otherwise we are done here
819 State
= StateDoneDiff
;
820 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
821 I
!= allPatches
->end(); ++I
)
822 if ((*I
)->State
== StateErrorDiff
)
825 // first failure means we should fallback
826 State
= StateErrorDiff
;
827 std::clog
<< "Falling back to normal index file aquire" << std::endl
;
828 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
832 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
833 pkgAcquire::MethodConfig
*Cnf
)
836 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
838 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
840 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
842 if (State
== StateFetchDiff
)
844 // rred expects the patch as $FinalFile.ed.$patchname.gz
845 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
847 // check if this is the last completed diff
848 State
= StateDoneDiff
;
849 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
850 I
!= allPatches
->end(); ++I
)
851 if ((*I
)->State
!= StateDoneDiff
)
854 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
858 // this is the last completed diff, so we are ready to apply now
859 State
= StateApplyDiff
;
862 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
865 Desc
.URI
= "rred:" + FinalFile
;
870 // success in download/apply all diffs, clean up
871 else if (State
== StateApplyDiff
)
873 // see if we really got the expected file
874 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
876 RenameOnError(HashSumMismatch
);
880 // move the result into place
882 std::clog
<< "Moving patched file in place: " << std::endl
883 << DestFile
<< " -> " << FinalFile
<< std::endl
;
884 Rename(DestFile
, FinalFile
);
885 chmod(FinalFile
.c_str(), 0644);
887 // otherwise lists cleanup will eat the file
888 DestFile
= FinalFile
;
893 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
897 // AcqIndex::AcqIndex - Constructor /*{{{*/
898 // ---------------------------------------------------------------------
899 /* The package file is added to the queue and a second class is
900 instantiated to fetch the revision file */
901 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
902 string URI
,string URIDesc
,string ShortDesc
,
903 HashString ExpectedHash
, string comprExt
)
904 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
906 if(comprExt
.empty() == true)
908 // autoselect the compression method
909 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
910 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
911 comprExt
.append(*t
).append(" ");
912 if (comprExt
.empty() == false)
913 comprExt
.erase(comprExt
.end()-1);
915 CompressionExtension
= comprExt
;
917 Init(URI
, URIDesc
, ShortDesc
);
919 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
920 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
921 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
923 // autoselect the compression method
924 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
925 CompressionExtension
= "";
926 if (ExpectedHash
.empty() == false)
928 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
929 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
930 CompressionExtension
.append(*t
).append(" ");
934 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
935 CompressionExtension
.append(*t
).append(" ");
937 if (CompressionExtension
.empty() == false)
938 CompressionExtension
.erase(CompressionExtension
.end()-1);
940 // only verify non-optional targets, see acquire-item.h for a FIXME
941 // to make this more flexible
942 if (Target
->IsOptional())
947 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
950 // AcqIndex::Init - defered Constructor /*{{{*/
951 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
952 Decompression
= false;
955 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
956 DestFile
+= URItoFileName(URI
);
958 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
959 if (comprExt
== "uncompressed")
962 Desc
.URI
= URI
+ '.' + comprExt
;
964 Desc
.Description
= URIDesc
;
966 Desc
.ShortDesc
= ShortDesc
;
971 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
972 // ---------------------------------------------------------------------
973 /* The only header we use is the last-modified header. */
974 string
pkgAcqIndex::Custom600Headers()
976 string Final
= _config
->FindDir("Dir::State::lists");
977 Final
+= URItoFileName(RealURI
);
978 if (_config
->FindB("Acquire::GzipIndexes",false))
981 string msg
= "\nIndex-File: true";
982 // FIXME: this really should use "IndexTarget::IsOptional()" but that
983 // seems to be difficult without breaking ABI
984 if (ShortDesc().find("Translation") != 0)
985 msg
+= "\nFail-Ignore: true";
987 if (stat(Final
.c_str(),&Buf
) == 0)
988 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
993 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
995 size_t const nextExt
= CompressionExtension
.find(' ');
996 if (nextExt
!= std::string::npos
)
998 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
999 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1003 // on decompression failure, remove bad versions in partial/
1004 if (Decompression
&& Erase
) {
1005 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1006 s
.append(URItoFileName(RealURI
));
1010 Item::Failed(Message
,Cnf
);
1013 // AcqIndex::Done - Finished a fetch /*{{{*/
1014 // ---------------------------------------------------------------------
1015 /* This goes through a number of states.. On the initial fetch the
1016 method could possibly return an alternate filename which points
1017 to the uncompressed version of the file. If this is so the file
1018 is copied into the partial directory. In all other cases the file
1019 is decompressed with a gzip uri. */
1020 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
1021 pkgAcquire::MethodConfig
*Cfg
)
1023 Item::Done(Message
,Size
,Hash
,Cfg
);
1025 if (Decompression
== true)
1027 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1029 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
1030 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
1033 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
1035 RenameOnError(HashSumMismatch
);
1039 /* Verify the index file for correctness (all indexes must
1040 * have a Package field) (LP: #346386) (Closes: #627642) */
1043 FileFd
fd(DestFile
, FileFd::ReadOnly
);
1044 // Only test for correctness if the file is not empty (empty is ok)
1045 if (fd
.FileSize() > 0)
1048 pkgTagFile
tag(&fd
);
1050 // all our current indexes have a field 'Package' in each section
1051 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1053 RenameOnError(InvalidFormat
);
1059 // Done, move it into position
1060 string FinalFile
= _config
->FindDir("Dir::State::lists");
1061 FinalFile
+= URItoFileName(RealURI
);
1062 Rename(DestFile
,FinalFile
);
1063 chmod(FinalFile
.c_str(),0644);
1065 /* We restore the original name to DestFile so that the clean operation
1067 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1068 DestFile
+= URItoFileName(RealURI
);
1070 // Remove the compressed version.
1072 unlink(DestFile
.c_str());
1079 // Handle the unzipd case
1080 string FileName
= LookupTag(Message
,"Alt-Filename");
1081 if (FileName
.empty() == false)
1083 // The files timestamp matches
1084 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
1086 Decompression
= true;
1088 DestFile
+= ".decomp";
1089 Desc
.URI
= "copy:" + FileName
;
1095 FileName
= LookupTag(Message
,"Filename");
1096 if (FileName
.empty() == true)
1099 ErrorText
= "Method gave a blank filename";
1102 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1104 // The files timestamp matches
1105 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
1106 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1107 // Update DestFile for .gz suffix so that the clean operation keeps it
1112 if (FileName
== DestFile
)
1119 // If we enable compressed indexes and already have gzip, keep it
1120 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
1121 string FinalFile
= _config
->FindDir("Dir::State::lists");
1122 FinalFile
+= URItoFileName(RealURI
) + ".gz";
1123 Rename(DestFile
,FinalFile
);
1124 chmod(FinalFile
.c_str(),0644);
1126 // Update DestFile for .gz suffix so that the clean operation keeps it
1127 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1128 DestFile
+= URItoFileName(RealURI
) + ".gz";
1132 // get the binary name for your used compression type
1133 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1134 if(decompProg
.empty() == false);
1135 else if(compExt
== "uncompressed")
1136 decompProg
= "copy";
1138 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1142 Decompression
= true;
1143 DestFile
+= ".decomp";
1144 Desc
.URI
= decompProg
+ ":" + FileName
;
1147 // FIXME: this points to a c++ string that goes out of scope
1148 Mode
= decompProg
.c_str();
1151 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1152 // ---------------------------------------------------------------------
1153 /* The Translation file is added to the queue */
1154 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1155 string URI
,string URIDesc
,string ShortDesc
)
1156 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1159 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1160 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1161 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1165 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1166 // ---------------------------------------------------------------------
1167 string
pkgAcqIndexTrans::Custom600Headers()
1169 string Final
= _config
->FindDir("Dir::State::lists");
1170 Final
+= URItoFileName(RealURI
);
1173 if (stat(Final
.c_str(),&Buf
) != 0)
1174 return "\nFail-Ignore: true\nIndex-File: true";
1175 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1178 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1179 // ---------------------------------------------------------------------
1181 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1183 size_t const nextExt
= CompressionExtension
.find(' ');
1184 if (nextExt
!= std::string::npos
)
1186 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1187 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1192 if (Cnf
->LocalOnly
== true ||
1193 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1202 Item::Failed(Message
,Cnf
);
1205 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1206 string URI
,string URIDesc
,string ShortDesc
,
1207 string MetaIndexURI
, string MetaIndexURIDesc
,
1208 string MetaIndexShortDesc
,
1209 const vector
<IndexTarget
*>* IndexTargets
,
1210 indexRecords
* MetaIndexParser
) :
1211 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1212 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1213 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1215 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1216 DestFile
+= URItoFileName(URI
);
1218 // remove any partial downloaded sig-file in partial/.
1219 // it may confuse proxies and is too small to warrant a
1220 // partial download anyway
1221 unlink(DestFile
.c_str());
1224 Desc
.Description
= URIDesc
;
1226 Desc
.ShortDesc
= ShortDesc
;
1229 string Final
= _config
->FindDir("Dir::State::lists");
1230 Final
+= URItoFileName(RealURI
);
1231 if (RealFileExists(Final
) == true)
1233 // File was already in place. It needs to be re-downloaded/verified
1234 // because Release might have changed, we do give it a differnt
1235 // name than DestFile because otherwise the http method will
1236 // send If-Range requests and there are too many broken servers
1237 // out there that do not understand them
1238 LastGoodSig
= DestFile
+".reverify";
1239 Rename(Final
,LastGoodSig
);
1245 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1247 // if the file was never queued undo file-changes done in the constructor
1248 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1249 LastGoodSig
.empty() == false)
1251 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1252 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1253 Rename(LastGoodSig
, Final
);
1258 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1259 // ---------------------------------------------------------------------
1260 /* The only header we use is the last-modified header. */
1261 string
pkgAcqMetaSig::Custom600Headers()
1264 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1265 return "\nIndex-File: true";
1267 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1270 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1271 pkgAcquire::MethodConfig
*Cfg
)
1273 Item::Done(Message
,Size
,MD5
,Cfg
);
1275 string FileName
= LookupTag(Message
,"Filename");
1276 if (FileName
.empty() == true)
1279 ErrorText
= "Method gave a blank filename";
1283 if (FileName
!= DestFile
)
1285 // We have to copy it into place
1287 Desc
.URI
= "copy:" + FileName
;
1294 // put the last known good file back on i-m-s hit (it will
1295 // be re-verified again)
1296 // Else do nothing, we have the new file in DestFile then
1297 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1298 Rename(LastGoodSig
, DestFile
);
1300 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1301 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1302 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1307 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1309 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1311 // if we get a network error we fail gracefully
1312 if(Status
== StatTransientNetworkError
)
1314 Item::Failed(Message
,Cnf
);
1315 // move the sigfile back on transient network failures
1316 if(FileExists(LastGoodSig
))
1317 Rename(LastGoodSig
,Final
);
1319 // set the status back to , Item::Failed likes to reset it
1320 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1324 // Delete any existing sigfile when the acquire failed
1325 unlink(Final
.c_str());
1327 // queue a pkgAcqMetaIndex with no sigfile
1328 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1329 "", IndexTargets
, MetaIndexParser
);
1331 if (Cnf
->LocalOnly
== true ||
1332 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1341 Item::Failed(Message
,Cnf
);
1344 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1345 string URI
,string URIDesc
,string ShortDesc
,
1347 const vector
<struct IndexTarget
*>* IndexTargets
,
1348 indexRecords
* MetaIndexParser
) :
1349 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1350 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1352 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1353 DestFile
+= URItoFileName(URI
);
1356 Desc
.Description
= URIDesc
;
1358 Desc
.ShortDesc
= ShortDesc
;
1364 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1365 // ---------------------------------------------------------------------
1366 /* The only header we use is the last-modified header. */
1367 string
pkgAcqMetaIndex::Custom600Headers()
1369 string Final
= _config
->FindDir("Dir::State::lists");
1370 Final
+= URItoFileName(RealURI
);
1373 if (stat(Final
.c_str(),&Buf
) != 0)
1374 return "\nIndex-File: true";
1376 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1379 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1380 pkgAcquire::MethodConfig
*Cfg
)
1382 Item::Done(Message
,Size
,Hash
,Cfg
);
1384 // MetaIndexes are done in two passes: one to download the
1385 // metaindex with an appropriate method, and a second to verify it
1386 // with the gpgv method
1388 if (AuthPass
== true)
1392 // all cool, move Release file into place
1397 RetrievalDone(Message
);
1399 // Still more retrieving to do
1404 // There was no signature file, so we are finished. Download
1405 // the indexes and do only hashsum verification if possible
1406 MetaIndexParser
->Load(DestFile
);
1407 QueueIndexes(false);
1411 // There was a signature file, so pass it to gpgv for
1414 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1415 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1416 << SigFile
<< "," << DestFile
<< ")\n";
1418 Desc
.URI
= "gpgv:" + SigFile
;
1425 if (Complete
== true)
1427 string FinalFile
= _config
->FindDir("Dir::State::lists");
1428 FinalFile
+= URItoFileName(RealURI
);
1429 if (SigFile
== DestFile
)
1430 SigFile
= FinalFile
;
1431 Rename(DestFile
,FinalFile
);
1432 chmod(FinalFile
.c_str(),0644);
1433 DestFile
= FinalFile
;
1437 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1439 // We have just finished downloading a Release file (it is not
1442 string FileName
= LookupTag(Message
,"Filename");
1443 if (FileName
.empty() == true)
1446 ErrorText
= "Method gave a blank filename";
1450 if (FileName
!= DestFile
)
1453 Desc
.URI
= "copy:" + FileName
;
1458 // make sure to verify against the right file on I-M-S hit
1459 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1462 string FinalFile
= _config
->FindDir("Dir::State::lists");
1463 FinalFile
+= URItoFileName(RealURI
);
1464 if (SigFile
== DestFile
)
1466 SigFile
= FinalFile
;
1467 // constructor of pkgAcqMetaClearSig moved it out of the way,
1468 // now move it back in on IMS hit for the 'old' file
1469 string
const OldClearSig
= DestFile
+ ".reverify";
1470 if (RealFileExists(OldClearSig
) == true)
1471 Rename(OldClearSig
, FinalFile
);
1473 DestFile
= FinalFile
;
1478 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1480 // At this point, the gpgv method has succeeded, so there is a
1481 // valid signature from a key in the trusted keyring. We
1482 // perform additional verification of its contents, and use them
1483 // to verify the indexes we are about to download
1485 if (!MetaIndexParser
->Load(DestFile
))
1487 Status
= StatAuthError
;
1488 ErrorText
= MetaIndexParser
->ErrorText
;
1492 if (!VerifyVendor(Message
))
1497 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1498 std::cerr
<< "Signature verification succeeded: "
1499 << DestFile
<< std::endl
;
1501 // Download further indexes with verification
1504 // is it a clearsigned MetaIndex file?
1505 if (DestFile
== SigFile
)
1508 // Done, move signature file into position
1509 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1510 URItoFileName(RealURI
) + ".gpg";
1511 Rename(SigFile
,VerifiedSigFile
);
1512 chmod(VerifiedSigFile
.c_str(),0644);
1515 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1518 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1519 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1520 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1523 ErrorText
= MetaIndexParser
->ErrorText
;
1527 bool transInRelease
= false;
1529 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1530 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1531 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1532 if (k
->find("Translation-") != std::string::npos
)
1534 transInRelease
= true;
1539 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1540 Target
!= IndexTargets
->end();
1543 HashString ExpectedIndexHash
;
1544 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1545 bool compressedAvailable
= false;
1548 if ((*Target
)->IsOptional() == true)
1550 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1551 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1552 if (MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".").append(*t
)) == true)
1554 compressedAvailable
= true;
1558 else if (verify
== true)
1560 Status
= StatAuthError
;
1561 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1567 ExpectedIndexHash
= Record
->Hash
;
1568 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1570 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1571 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1572 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1574 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1576 Status
= StatAuthError
;
1577 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1582 if ((*Target
)->IsOptional() == true)
1584 if ((*Target
)->IsSubIndex() == true)
1585 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1586 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1587 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1589 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1590 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true)
1591 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1592 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1594 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1599 /* Queue Packages file (either diff or full packages files, depending
1600 on the users option) - we also check if the PDiff Index file is listed
1601 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1602 instead, but passing the required info to it is to much hassle */
1603 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1604 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1605 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1606 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1608 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1612 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1614 string::size_type pos
;
1616 // check for missing sigs (that where not fatal because otherwise we had
1619 string msg
= _("There is no public key available for the "
1620 "following key IDs:\n");
1621 pos
= Message
.find("NO_PUBKEY ");
1622 if (pos
!= std::string::npos
)
1624 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1625 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1626 missingkeys
+= (Fingerprint
);
1628 if(!missingkeys
.empty())
1629 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1631 string Transformed
= MetaIndexParser
->GetExpectedDist();
1633 if (Transformed
== "../project/experimental")
1635 Transformed
= "experimental";
1638 pos
= Transformed
.rfind('/');
1639 if (pos
!= string::npos
)
1641 Transformed
= Transformed
.substr(0, pos
);
1644 if (Transformed
== ".")
1649 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1650 MetaIndexParser
->GetValidUntil() > 0) {
1651 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1652 if (invalid_since
> 0)
1653 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1654 // the time since then the file is invalid - formated in the same way as in
1655 // the download progress display (e.g. 7d 3h 42min 1s)
1656 return _error
->Error(
1657 _("Release file for %s is expired (invalid since %s). "
1658 "Updates for this repository will not be applied."),
1659 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1662 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1664 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1665 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1666 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1669 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1671 // This might become fatal one day
1672 // Status = StatAuthError;
1673 // ErrorText = "Conflicting distribution; expected "
1674 // + MetaIndexParser->GetExpectedDist() + " but got "
1675 // + MetaIndexParser->GetDist();
1677 if (!Transformed
.empty())
1679 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1680 Desc
.Description
.c_str(),
1681 Transformed
.c_str(),
1682 MetaIndexParser
->GetDist().c_str());
1689 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1690 // ---------------------------------------------------------------------
1692 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1694 if (AuthPass
== true)
1696 // gpgv method failed, if we have a good signature
1697 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1698 if (DestFile
!= SigFile
)
1699 LastGoodSigFile
.append(".gpg");
1700 LastGoodSigFile
.append(".reverify");
1702 if(FileExists(LastGoodSigFile
))
1704 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1705 if (DestFile
!= SigFile
)
1706 VerifiedSigFile
.append(".gpg");
1707 Rename(LastGoodSigFile
, VerifiedSigFile
);
1708 Status
= StatTransientNetworkError
;
1709 _error
->Warning(_("An error occurred during the signature "
1710 "verification. The repository is not updated "
1711 "and the previous index files will be used. "
1712 "GPG error: %s: %s\n"),
1713 Desc
.Description
.c_str(),
1714 LookupTag(Message
,"Message").c_str());
1715 RunScripts("APT::Update::Auth-Failure");
1717 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1718 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1719 _error
->Error(_("GPG error: %s: %s"),
1720 Desc
.Description
.c_str(),
1721 LookupTag(Message
,"Message").c_str());
1724 _error
->Warning(_("GPG error: %s: %s"),
1725 Desc
.Description
.c_str(),
1726 LookupTag(Message
,"Message").c_str());
1728 // gpgv method failed
1729 ReportMirrorFailure("GPGFailure");
1732 /* Always move the meta index, even if gpgv failed. This ensures
1733 * that PackageFile objects are correctly filled in */
1734 if (FileExists(DestFile
)) {
1735 string FinalFile
= _config
->FindDir("Dir::State::lists");
1736 FinalFile
+= URItoFileName(RealURI
);
1737 /* InRelease files become Release files, otherwise
1738 * they would be considered as trusted later on */
1739 if (SigFile
== DestFile
) {
1740 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1742 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1744 SigFile
= FinalFile
;
1746 Rename(DestFile
,FinalFile
);
1747 chmod(FinalFile
.c_str(),0644);
1749 DestFile
= FinalFile
;
1752 // No Release file was present, or verification failed, so fall
1753 // back to queueing Packages files without verification
1754 QueueIndexes(false);
1757 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1758 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1759 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1760 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1761 const vector
<struct IndexTarget
*>* IndexTargets
,
1762 indexRecords
* MetaIndexParser
) :
1763 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1764 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1765 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1769 // keep the old InRelease around in case of transistent network errors
1770 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1771 if (RealFileExists(Final
) == true)
1773 string
const LastGoodSig
= DestFile
+ ".reverify";
1774 Rename(Final
,LastGoodSig
);
1778 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1780 // if the file was never queued undo file-changes done in the constructor
1781 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1783 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1784 string
const LastGoodSig
= DestFile
+ ".reverify";
1785 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1786 Rename(LastGoodSig
, Final
);
1790 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1791 // ---------------------------------------------------------------------
1792 // FIXME: this can go away once the InRelease file is used widely
1793 string
pkgAcqMetaClearSig::Custom600Headers()
1795 string Final
= _config
->FindDir("Dir::State::lists");
1796 Final
+= URItoFileName(RealURI
);
1799 if (stat(Final
.c_str(),&Buf
) != 0)
1801 Final
= DestFile
+ ".reverify";
1802 if (stat(Final
.c_str(),&Buf
) != 0)
1803 return "\nIndex-File: true\nFail-Ignore: true\n";
1806 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1809 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1811 if (AuthPass
== false)
1813 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1814 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1815 string FinalFile
= _config
->FindDir("Dir::State::lists");
1816 FinalFile
.append(URItoFileName(RealURI
));
1817 if (FileExists(FinalFile
))
1818 unlink(FinalFile
.c_str());
1820 new pkgAcqMetaSig(Owner
,
1821 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1822 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1823 IndexTargets
, MetaIndexParser
);
1824 if (Cnf
->LocalOnly
== true ||
1825 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1829 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1832 // AcqArchive::AcqArchive - Constructor /*{{{*/
1833 // ---------------------------------------------------------------------
1834 /* This just sets up the initial fetch environment and queues the first
1836 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1837 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1838 string
&StoreFilename
) :
1839 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1840 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1843 Retries
= _config
->FindI("Acquire::Retries",0);
1845 if (Version
.Arch() == 0)
1847 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1848 "This might mean you need to manually fix this package. "
1849 "(due to missing arch)"),
1850 Version
.ParentPkg().Name());
1854 /* We need to find a filename to determine the extension. We make the
1855 assumption here that all the available sources for this version share
1856 the same extension.. */
1857 // Skip not source sources, they do not have file fields.
1858 for (; Vf
.end() == false; ++Vf
)
1860 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1865 // Does not really matter here.. we are going to fail out below
1866 if (Vf
.end() != true)
1868 // If this fails to get a file name we will bomb out below.
1869 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1870 if (_error
->PendingError() == true)
1873 // Generate the final file name as: package_version_arch.foo
1874 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1875 QuoteString(Version
.VerStr(),"_:") + '_' +
1876 QuoteString(Version
.Arch(),"_:.") +
1877 "." + flExtension(Parse
.FileName());
1880 // check if we have one trusted source for the package. if so, switch
1881 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1882 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
1883 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
1884 bool seenUntrusted
= false;
1885 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1887 pkgIndexFile
*Index
;
1888 if (Sources
->FindIndex(i
.File(),Index
) == false)
1891 if (debugAuth
== true)
1892 std::cerr
<< "Checking index: " << Index
->Describe()
1893 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
1895 if (Index
->IsTrusted() == true)
1898 if (allowUnauth
== false)
1902 seenUntrusted
= true;
1905 // "allow-unauthenticated" restores apts old fetching behaviour
1906 // that means that e.g. unauthenticated file:// uris are higher
1907 // priority than authenticated http:// uris
1908 if (allowUnauth
== true && seenUntrusted
== true)
1912 if (QueueNext() == false && _error
->PendingError() == false)
1913 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
1914 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
1917 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1918 // ---------------------------------------------------------------------
1919 /* This queues the next available file version for download. It checks if
1920 the archive is already available in the cache and stashs the MD5 for
1922 bool pkgAcqArchive::QueueNext()
1924 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1925 for (; Vf
.end() == false; ++Vf
)
1927 // Ignore not source sources
1928 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1931 // Try to cross match against the source list
1932 pkgIndexFile
*Index
;
1933 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1936 // only try to get a trusted package from another source if that source
1938 if(Trusted
&& !Index
->IsTrusted())
1941 // Grab the text package record
1942 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1943 if (_error
->PendingError() == true)
1946 string PkgFile
= Parse
.FileName();
1947 if (ForceHash
.empty() == false)
1949 if(stringcasecmp(ForceHash
, "sha512") == 0)
1950 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
1951 else if(stringcasecmp(ForceHash
, "sha256") == 0)
1952 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1953 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1954 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1956 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1961 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
1962 ExpectedHash
= HashString("SHA512", Hash
);
1963 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1964 ExpectedHash
= HashString("SHA256", Hash
);
1965 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1966 ExpectedHash
= HashString("SHA1", Hash
);
1968 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1970 if (PkgFile
.empty() == true)
1971 return _error
->Error(_("The package index files are corrupted. No Filename: "
1972 "field for package %s."),
1973 Version
.ParentPkg().Name());
1975 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1976 Desc
.Description
= Index
->ArchiveInfo(Version
);
1978 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1980 // See if we already have the file. (Legacy filenames)
1981 FileSize
= Version
->Size
;
1982 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1984 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1986 // Make sure the size matches
1987 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1992 StoreFilename
= DestFile
= FinalFile
;
1996 /* Hmm, we have a file and its size does not match, this means it is
1997 an old style mismatched arch */
1998 unlink(FinalFile
.c_str());
2001 // Check it again using the new style output filenames
2002 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2003 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2005 // Make sure the size matches
2006 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2011 StoreFilename
= DestFile
= FinalFile
;
2015 /* Hmm, we have a file and its size does not match, this shouldnt
2017 unlink(FinalFile
.c_str());
2020 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2022 // Check the destination file
2023 if (stat(DestFile
.c_str(),&Buf
) == 0)
2025 // Hmm, the partial file is too big, erase it
2026 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2027 unlink(DestFile
.c_str());
2029 PartialSize
= Buf
.st_size
;
2032 // Disables download of archives - useful if no real installation follows,
2033 // e.g. if we are just interested in proposed installation order
2034 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2039 StoreFilename
= DestFile
= FinalFile
;
2045 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2046 Desc
.Description
= Index
->ArchiveInfo(Version
);
2048 Desc
.ShortDesc
= Version
.ParentPkg().Name();
2057 // AcqArchive::Done - Finished fetching /*{{{*/
2058 // ---------------------------------------------------------------------
2060 void pkgAcqArchive::Done(string Message
,unsigned long long Size
,string CalcHash
,
2061 pkgAcquire::MethodConfig
*Cfg
)
2063 Item::Done(Message
,Size
,CalcHash
,Cfg
);
2066 if (Size
!= Version
->Size
)
2068 RenameOnError(SizeMismatch
);
2073 if(ExpectedHash
.toStr() != CalcHash
)
2075 RenameOnError(HashSumMismatch
);
2079 // Grab the output filename
2080 string FileName
= LookupTag(Message
,"Filename");
2081 if (FileName
.empty() == true)
2084 ErrorText
= "Method gave a blank filename";
2090 // Reference filename
2091 if (FileName
!= DestFile
)
2093 StoreFilename
= DestFile
= FileName
;
2098 // Done, move it into position
2099 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2100 FinalFile
+= flNotDir(StoreFilename
);
2101 Rename(DestFile
,FinalFile
);
2103 StoreFilename
= DestFile
= FinalFile
;
2107 // AcqArchive::Failed - Failure handler /*{{{*/
2108 // ---------------------------------------------------------------------
2109 /* Here we try other sources */
2110 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2112 ErrorText
= LookupTag(Message
,"Message");
2114 /* We don't really want to retry on failed media swaps, this prevents
2115 that. An interesting observation is that permanent failures are not
2117 if (Cnf
->Removable
== true &&
2118 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2120 // Vf = Version.FileList();
2121 while (Vf
.end() == false) ++Vf
;
2122 StoreFilename
= string();
2123 Item::Failed(Message
,Cnf
);
2127 if (QueueNext() == false)
2129 // This is the retry counter
2131 Cnf
->LocalOnly
== false &&
2132 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2135 Vf
= Version
.FileList();
2136 if (QueueNext() == true)
2140 StoreFilename
= string();
2141 Item::Failed(Message
,Cnf
);
2145 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2146 // ---------------------------------------------------------------------
2147 bool pkgAcqArchive::IsTrusted()
2152 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2153 // ---------------------------------------------------------------------
2155 void pkgAcqArchive::Finished()
2157 if (Status
== pkgAcquire::Item::StatDone
&&
2160 StoreFilename
= string();
2163 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2164 // ---------------------------------------------------------------------
2165 /* The file is added to the queue */
2166 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
2167 unsigned long long Size
,string Dsc
,string ShortDesc
,
2168 const string
&DestDir
, const string
&DestFilename
,
2170 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
2172 Retries
= _config
->FindI("Acquire::Retries",0);
2174 if(!DestFilename
.empty())
2175 DestFile
= DestFilename
;
2176 else if(!DestDir
.empty())
2177 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2179 DestFile
= flNotDir(URI
);
2183 Desc
.Description
= Dsc
;
2186 // Set the short description to the archive component
2187 Desc
.ShortDesc
= ShortDesc
;
2189 // Get the transfer sizes
2192 if (stat(DestFile
.c_str(),&Buf
) == 0)
2194 // Hmm, the partial file is too big, erase it
2195 if ((unsigned long long)Buf
.st_size
> Size
)
2196 unlink(DestFile
.c_str());
2198 PartialSize
= Buf
.st_size
;
2204 // AcqFile::Done - Item downloaded OK /*{{{*/
2205 // ---------------------------------------------------------------------
2207 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
2208 pkgAcquire::MethodConfig
*Cnf
)
2210 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2213 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2215 RenameOnError(HashSumMismatch
);
2219 string FileName
= LookupTag(Message
,"Filename");
2220 if (FileName
.empty() == true)
2223 ErrorText
= "Method gave a blank filename";
2229 // The files timestamp matches
2230 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2233 // We have to copy it into place
2234 if (FileName
!= DestFile
)
2237 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2238 Cnf
->Removable
== true)
2240 Desc
.URI
= "copy:" + FileName
;
2245 // Erase the file if it is a symlink so we can overwrite it
2247 if (lstat(DestFile
.c_str(),&St
) == 0)
2249 if (S_ISLNK(St
.st_mode
) != 0)
2250 unlink(DestFile
.c_str());
2254 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2256 ErrorText
= "Link to " + DestFile
+ " failure ";
2263 // AcqFile::Failed - Failure handler /*{{{*/
2264 // ---------------------------------------------------------------------
2265 /* Here we try other sources */
2266 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2268 ErrorText
= LookupTag(Message
,"Message");
2270 // This is the retry counter
2272 Cnf
->LocalOnly
== false &&
2273 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2280 Item::Failed(Message
,Cnf
);
2283 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2284 // ---------------------------------------------------------------------
2285 /* The only header we use is the last-modified header. */
2286 string
pkgAcqFile::Custom600Headers()
2289 return "\nIndex-File: true";