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 // this perl script is provided by apt-file
517 pdiff_merge
= FileExists(_config
->FindFile("Dir::Bin::rred", "/usr/bin/diffindex-rred"));
518 if (pdiff_merge
== true)
520 // reprepro adds this flag if it has merged patches on the server
521 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
522 pdiff_merge
= (precedence
!= "merged");
526 if (pdiff_merge
== false)
527 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
528 ExpectedHash
, ServerSha1
, available_patches
);
531 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
532 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
533 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
, ExpectedHash
,
534 available_patches
[i
], diffs
);
544 // Nothing found, report and return false
545 // Failing here is ok, if we return false later, the full
546 // IndexFile is queued
548 std::clog
<< "Can't find a patch in the index file" << std::endl
;
552 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
555 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
556 << "Falling back to normal index file aquire" << std::endl
;
558 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
566 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
567 pkgAcquire::MethodConfig
*Cnf
)
570 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
572 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
575 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
577 // sucess in downloading the index
579 FinalFile
+= string(".IndexDiff");
581 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
583 Rename(DestFile
,FinalFile
);
584 chmod(FinalFile
.c_str(),0644);
585 DestFile
= FinalFile
;
587 if(!ParseDiffIndex(DestFile
))
588 return Failed("", NULL
);
596 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
597 // ---------------------------------------------------------------------
598 /* The package diff is added to the queue. one object is constructed
599 * for each diff and the index
601 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
602 string URI
,string URIDesc
,string ShortDesc
,
603 HashString ExpectedHash
,
605 vector
<DiffInfo
> diffs
)
606 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
607 available_patches(diffs
), ServerSha1(ServerSha1
)
610 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
611 DestFile
+= URItoFileName(URI
);
613 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
615 Description
= URIDesc
;
617 Desc
.ShortDesc
= ShortDesc
;
619 if(available_patches
.empty() == true)
621 // we are done (yeah!)
627 State
= StateFetchDiff
;
632 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
635 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
636 << "Falling back to normal index file aquire" << std::endl
;
637 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
642 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
643 void pkgAcqIndexDiffs::Finish(bool allDone
)
645 // we restore the original name, this is required, otherwise
646 // the file will be cleaned
649 DestFile
= _config
->FindDir("Dir::State::lists");
650 DestFile
+= URItoFileName(RealURI
);
652 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
654 RenameOnError(HashSumMismatch
);
659 // this is for the "real" finish
664 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
669 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
676 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
679 // calc sha1 of the just patched file
680 string FinalFile
= _config
->FindDir("Dir::State::lists");
681 FinalFile
+= URItoFileName(RealURI
);
683 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
686 string local_sha1
= string(SHA1
.Result());
688 std::clog
<< "QueueNextDiff: "
689 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
691 // final file reached before all patches are applied
692 if(local_sha1
== ServerSha1
)
698 // remove all patches until the next matching patch is found
699 // this requires the Index file to be ordered
700 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
701 available_patches
.empty() == false &&
702 I
!= available_patches
.end() &&
703 I
->sha1
!= local_sha1
;
706 available_patches
.erase(I
);
709 // error checking and falling back if no patch was found
710 if(available_patches
.empty() == true)
716 // queue the right diff
717 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
718 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
719 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
720 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
723 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
730 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
731 pkgAcquire::MethodConfig
*Cnf
)
734 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
736 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
739 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
741 // sucess in downloading a diff, enter ApplyDiff state
742 if(State
== StateFetchDiff
)
745 // rred excepts the patch as $FinalFile.ed
746 Rename(DestFile
,FinalFile
+".ed");
749 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
751 State
= StateApplyDiff
;
753 Desc
.URI
= "rred:" + FinalFile
;
760 // success in download/apply a diff, queue next (if needed)
761 if(State
== StateApplyDiff
)
763 // remove the just applied patch
764 available_patches
.erase(available_patches
.begin());
769 std::clog
<< "Moving patched file in place: " << std::endl
770 << DestFile
<< " -> " << FinalFile
<< std::endl
;
772 Rename(DestFile
,FinalFile
);
773 chmod(FinalFile
.c_str(),0644);
775 // see if there is more to download
776 if(available_patches
.empty() == false) {
777 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
778 ExpectedHash
, ServerSha1
, available_patches
);
785 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
786 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
787 string
const &URI
, string
const &URIDesc
,
788 string
const &ShortDesc
, HashString
const &ExpectedHash
,
789 DiffInfo
const &patch
,
790 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
791 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
792 patch(patch
),allPatches(allPatches
), State(StateFetchDiff
)
795 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
796 DestFile
+= URItoFileName(URI
);
798 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
800 Description
= URIDesc
;
802 Desc
.ShortDesc
= ShortDesc
;
804 Desc
.URI
= string(RealURI
) + ".diff/" + patch
.file
+ ".gz";
805 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
806 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
807 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
810 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
815 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
818 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
823 // check if we are the first to fail, otherwise we are done here
824 State
= StateDoneDiff
;
825 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
826 I
!= allPatches
->end(); ++I
)
827 if ((*I
)->State
== StateErrorDiff
)
830 // first failure means we should fallback
831 State
= StateErrorDiff
;
832 std::clog
<< "Falling back to normal index file aquire" << std::endl
;
833 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
837 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
838 pkgAcquire::MethodConfig
*Cnf
)
841 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
843 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
845 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
847 if (State
== StateFetchDiff
)
849 // rred expects the patch as $FinalFile.ed.$patchname.gz
850 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
852 // check if this is the last completed diff
853 State
= StateDoneDiff
;
854 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
855 I
!= allPatches
->end(); ++I
)
856 if ((*I
)->State
!= StateDoneDiff
)
859 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
863 // this is the last completed diff, so we are ready to apply now
864 State
= StateApplyDiff
;
867 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
870 Desc
.URI
= "rred:" + FinalFile
;
875 // success in download/apply all diffs, clean up
876 else if (State
== StateApplyDiff
)
878 // see if we really got the expected file
879 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
881 RenameOnError(HashSumMismatch
);
885 // move the result into place
887 std::clog
<< "Moving patched file in place: " << std::endl
888 << DestFile
<< " -> " << FinalFile
<< std::endl
;
889 Rename(DestFile
, FinalFile
);
890 chmod(FinalFile
.c_str(), 0644);
892 // otherwise lists cleanup will eat the file
893 DestFile
= FinalFile
;
898 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
902 // AcqIndex::AcqIndex - Constructor /*{{{*/
903 // ---------------------------------------------------------------------
904 /* The package file is added to the queue and a second class is
905 instantiated to fetch the revision file */
906 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
907 string URI
,string URIDesc
,string ShortDesc
,
908 HashString ExpectedHash
, string comprExt
)
909 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
911 if(comprExt
.empty() == true)
913 // autoselect the compression method
914 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
915 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
916 comprExt
.append(*t
).append(" ");
917 if (comprExt
.empty() == false)
918 comprExt
.erase(comprExt
.end()-1);
920 CompressionExtension
= comprExt
;
922 Init(URI
, URIDesc
, ShortDesc
);
924 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
925 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
926 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
928 // autoselect the compression method
929 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
930 CompressionExtension
= "";
931 if (ExpectedHash
.empty() == false)
933 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
934 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
935 CompressionExtension
.append(*t
).append(" ");
939 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
940 CompressionExtension
.append(*t
).append(" ");
942 if (CompressionExtension
.empty() == false)
943 CompressionExtension
.erase(CompressionExtension
.end()-1);
945 // only verify non-optional targets, see acquire-item.h for a FIXME
946 // to make this more flexible
947 if (Target
->IsOptional())
952 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
955 // AcqIndex::Init - defered Constructor /*{{{*/
956 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
957 Decompression
= false;
960 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
961 DestFile
+= URItoFileName(URI
);
963 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
964 if (comprExt
== "uncompressed")
967 Desc
.URI
= URI
+ '.' + comprExt
;
969 Desc
.Description
= URIDesc
;
971 Desc
.ShortDesc
= ShortDesc
;
976 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
977 // ---------------------------------------------------------------------
978 /* The only header we use is the last-modified header. */
979 string
pkgAcqIndex::Custom600Headers()
981 string Final
= _config
->FindDir("Dir::State::lists");
982 Final
+= URItoFileName(RealURI
);
983 if (_config
->FindB("Acquire::GzipIndexes",false))
986 string msg
= "\nIndex-File: true";
987 // FIXME: this really should use "IndexTarget::IsOptional()" but that
988 // seems to be difficult without breaking ABI
989 if (ShortDesc().find("Translation") != 0)
990 msg
+= "\nFail-Ignore: true";
992 if (stat(Final
.c_str(),&Buf
) == 0)
993 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
998 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1000 size_t const nextExt
= CompressionExtension
.find(' ');
1001 if (nextExt
!= std::string::npos
)
1003 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1004 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1008 // on decompression failure, remove bad versions in partial/
1009 if (Decompression
&& Erase
) {
1010 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1011 s
.append(URItoFileName(RealURI
));
1015 Item::Failed(Message
,Cnf
);
1018 // AcqIndex::Done - Finished a fetch /*{{{*/
1019 // ---------------------------------------------------------------------
1020 /* This goes through a number of states.. On the initial fetch the
1021 method could possibly return an alternate filename which points
1022 to the uncompressed version of the file. If this is so the file
1023 is copied into the partial directory. In all other cases the file
1024 is decompressed with a gzip uri. */
1025 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
1026 pkgAcquire::MethodConfig
*Cfg
)
1028 Item::Done(Message
,Size
,Hash
,Cfg
);
1030 if (Decompression
== true)
1032 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1034 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
1035 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
1038 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
1040 RenameOnError(HashSumMismatch
);
1044 /* Verify the index file for correctness (all indexes must
1045 * have a Package field) (LP: #346386) (Closes: #627642) */
1048 FileFd
fd(DestFile
, FileFd::ReadOnly
);
1049 // Only test for correctness if the file is not empty (empty is ok)
1050 if (fd
.FileSize() > 0)
1053 pkgTagFile
tag(&fd
);
1055 // all our current indexes have a field 'Package' in each section
1056 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1058 RenameOnError(InvalidFormat
);
1064 // Done, move it into position
1065 string FinalFile
= _config
->FindDir("Dir::State::lists");
1066 FinalFile
+= URItoFileName(RealURI
);
1067 Rename(DestFile
,FinalFile
);
1068 chmod(FinalFile
.c_str(),0644);
1070 /* We restore the original name to DestFile so that the clean operation
1072 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1073 DestFile
+= URItoFileName(RealURI
);
1075 // Remove the compressed version.
1077 unlink(DestFile
.c_str());
1084 // Handle the unzipd case
1085 string FileName
= LookupTag(Message
,"Alt-Filename");
1086 if (FileName
.empty() == false)
1088 // The files timestamp matches
1089 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
1091 Decompression
= true;
1093 DestFile
+= ".decomp";
1094 Desc
.URI
= "copy:" + FileName
;
1100 FileName
= LookupTag(Message
,"Filename");
1101 if (FileName
.empty() == true)
1104 ErrorText
= "Method gave a blank filename";
1107 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1109 // The files timestamp matches
1110 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
1111 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1112 // Update DestFile for .gz suffix so that the clean operation keeps it
1117 if (FileName
== DestFile
)
1124 // If we enable compressed indexes and already have gzip, keep it
1125 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
1126 string FinalFile
= _config
->FindDir("Dir::State::lists");
1127 FinalFile
+= URItoFileName(RealURI
) + ".gz";
1128 Rename(DestFile
,FinalFile
);
1129 chmod(FinalFile
.c_str(),0644);
1131 // Update DestFile for .gz suffix so that the clean operation keeps it
1132 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1133 DestFile
+= URItoFileName(RealURI
) + ".gz";
1137 // get the binary name for your used compression type
1138 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1139 if(decompProg
.empty() == false);
1140 else if(compExt
== "uncompressed")
1141 decompProg
= "copy";
1143 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1147 Decompression
= true;
1148 DestFile
+= ".decomp";
1149 Desc
.URI
= decompProg
+ ":" + FileName
;
1152 // FIXME: this points to a c++ string that goes out of scope
1153 Mode
= decompProg
.c_str();
1156 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1157 // ---------------------------------------------------------------------
1158 /* The Translation file is added to the queue */
1159 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1160 string URI
,string URIDesc
,string ShortDesc
)
1161 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1164 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1165 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1166 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1170 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1171 // ---------------------------------------------------------------------
1172 string
pkgAcqIndexTrans::Custom600Headers()
1174 string Final
= _config
->FindDir("Dir::State::lists");
1175 Final
+= URItoFileName(RealURI
);
1178 if (stat(Final
.c_str(),&Buf
) != 0)
1179 return "\nFail-Ignore: true\nIndex-File: true";
1180 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1183 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1184 // ---------------------------------------------------------------------
1186 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1188 size_t const nextExt
= CompressionExtension
.find(' ');
1189 if (nextExt
!= std::string::npos
)
1191 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1192 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1197 if (Cnf
->LocalOnly
== true ||
1198 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1207 Item::Failed(Message
,Cnf
);
1210 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1211 string URI
,string URIDesc
,string ShortDesc
,
1212 string MetaIndexURI
, string MetaIndexURIDesc
,
1213 string MetaIndexShortDesc
,
1214 const vector
<IndexTarget
*>* IndexTargets
,
1215 indexRecords
* MetaIndexParser
) :
1216 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1217 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1218 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1220 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1221 DestFile
+= URItoFileName(URI
);
1223 // remove any partial downloaded sig-file in partial/.
1224 // it may confuse proxies and is too small to warrant a
1225 // partial download anyway
1226 unlink(DestFile
.c_str());
1229 Desc
.Description
= URIDesc
;
1231 Desc
.ShortDesc
= ShortDesc
;
1234 string Final
= _config
->FindDir("Dir::State::lists");
1235 Final
+= URItoFileName(RealURI
);
1236 if (RealFileExists(Final
) == true)
1238 // File was already in place. It needs to be re-downloaded/verified
1239 // because Release might have changed, we do give it a differnt
1240 // name than DestFile because otherwise the http method will
1241 // send If-Range requests and there are too many broken servers
1242 // out there that do not understand them
1243 LastGoodSig
= DestFile
+".reverify";
1244 Rename(Final
,LastGoodSig
);
1250 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1252 // if the file was never queued undo file-changes done in the constructor
1253 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1254 LastGoodSig
.empty() == false)
1256 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1257 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1258 Rename(LastGoodSig
, Final
);
1263 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1264 // ---------------------------------------------------------------------
1265 /* The only header we use is the last-modified header. */
1266 string
pkgAcqMetaSig::Custom600Headers()
1269 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1270 return "\nIndex-File: true";
1272 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1275 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1276 pkgAcquire::MethodConfig
*Cfg
)
1278 Item::Done(Message
,Size
,MD5
,Cfg
);
1280 string FileName
= LookupTag(Message
,"Filename");
1281 if (FileName
.empty() == true)
1284 ErrorText
= "Method gave a blank filename";
1288 if (FileName
!= DestFile
)
1290 // We have to copy it into place
1292 Desc
.URI
= "copy:" + FileName
;
1299 // put the last known good file back on i-m-s hit (it will
1300 // be re-verified again)
1301 // Else do nothing, we have the new file in DestFile then
1302 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1303 Rename(LastGoodSig
, DestFile
);
1305 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1306 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1307 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1312 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1314 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1316 // if we get a network error we fail gracefully
1317 if(Status
== StatTransientNetworkError
)
1319 Item::Failed(Message
,Cnf
);
1320 // move the sigfile back on transient network failures
1321 if(FileExists(LastGoodSig
))
1322 Rename(LastGoodSig
,Final
);
1324 // set the status back to , Item::Failed likes to reset it
1325 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1329 // Delete any existing sigfile when the acquire failed
1330 unlink(Final
.c_str());
1332 // queue a pkgAcqMetaIndex with no sigfile
1333 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1334 "", IndexTargets
, MetaIndexParser
);
1336 if (Cnf
->LocalOnly
== true ||
1337 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1346 Item::Failed(Message
,Cnf
);
1349 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1350 string URI
,string URIDesc
,string ShortDesc
,
1352 const vector
<struct IndexTarget
*>* IndexTargets
,
1353 indexRecords
* MetaIndexParser
) :
1354 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1355 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1357 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1358 DestFile
+= URItoFileName(URI
);
1361 Desc
.Description
= URIDesc
;
1363 Desc
.ShortDesc
= ShortDesc
;
1369 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1370 // ---------------------------------------------------------------------
1371 /* The only header we use is the last-modified header. */
1372 string
pkgAcqMetaIndex::Custom600Headers()
1374 string Final
= _config
->FindDir("Dir::State::lists");
1375 Final
+= URItoFileName(RealURI
);
1378 if (stat(Final
.c_str(),&Buf
) != 0)
1379 return "\nIndex-File: true";
1381 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1384 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1385 pkgAcquire::MethodConfig
*Cfg
)
1387 Item::Done(Message
,Size
,Hash
,Cfg
);
1389 // MetaIndexes are done in two passes: one to download the
1390 // metaindex with an appropriate method, and a second to verify it
1391 // with the gpgv method
1393 if (AuthPass
== true)
1397 // all cool, move Release file into place
1402 RetrievalDone(Message
);
1404 // Still more retrieving to do
1409 // There was no signature file, so we are finished. Download
1410 // the indexes and do only hashsum verification if possible
1411 MetaIndexParser
->Load(DestFile
);
1412 QueueIndexes(false);
1416 // There was a signature file, so pass it to gpgv for
1419 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1420 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1421 << SigFile
<< "," << DestFile
<< ")\n";
1423 Desc
.URI
= "gpgv:" + SigFile
;
1430 if (Complete
== true)
1432 string FinalFile
= _config
->FindDir("Dir::State::lists");
1433 FinalFile
+= URItoFileName(RealURI
);
1434 if (SigFile
== DestFile
)
1435 SigFile
= FinalFile
;
1436 Rename(DestFile
,FinalFile
);
1437 chmod(FinalFile
.c_str(),0644);
1438 DestFile
= FinalFile
;
1442 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1444 // We have just finished downloading a Release file (it is not
1447 string FileName
= LookupTag(Message
,"Filename");
1448 if (FileName
.empty() == true)
1451 ErrorText
= "Method gave a blank filename";
1455 if (FileName
!= DestFile
)
1458 Desc
.URI
= "copy:" + FileName
;
1463 // make sure to verify against the right file on I-M-S hit
1464 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1467 string FinalFile
= _config
->FindDir("Dir::State::lists");
1468 FinalFile
+= URItoFileName(RealURI
);
1469 if (SigFile
== DestFile
)
1471 SigFile
= FinalFile
;
1472 // constructor of pkgAcqMetaClearSig moved it out of the way,
1473 // now move it back in on IMS hit for the 'old' file
1474 string
const OldClearSig
= DestFile
+ ".reverify";
1475 if (RealFileExists(OldClearSig
) == true)
1476 Rename(OldClearSig
, FinalFile
);
1478 DestFile
= FinalFile
;
1483 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1485 // At this point, the gpgv method has succeeded, so there is a
1486 // valid signature from a key in the trusted keyring. We
1487 // perform additional verification of its contents, and use them
1488 // to verify the indexes we are about to download
1490 if (!MetaIndexParser
->Load(DestFile
))
1492 Status
= StatAuthError
;
1493 ErrorText
= MetaIndexParser
->ErrorText
;
1497 if (!VerifyVendor(Message
))
1502 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1503 std::cerr
<< "Signature verification succeeded: "
1504 << DestFile
<< std::endl
;
1506 // Download further indexes with verification
1509 // is it a clearsigned MetaIndex file?
1510 if (DestFile
== SigFile
)
1513 // Done, move signature file into position
1514 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1515 URItoFileName(RealURI
) + ".gpg";
1516 Rename(SigFile
,VerifiedSigFile
);
1517 chmod(VerifiedSigFile
.c_str(),0644);
1520 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1523 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1524 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1525 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1528 ErrorText
= MetaIndexParser
->ErrorText
;
1532 bool transInRelease
= false;
1534 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1535 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1536 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1537 if (k
->find("Translation-") != std::string::npos
)
1539 transInRelease
= true;
1544 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1545 Target
!= IndexTargets
->end();
1548 HashString ExpectedIndexHash
;
1549 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1550 bool compressedAvailable
= false;
1553 if ((*Target
)->IsOptional() == true)
1555 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1556 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1557 if (MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".").append(*t
)) == true)
1559 compressedAvailable
= true;
1563 else if (verify
== true)
1565 Status
= StatAuthError
;
1566 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1572 ExpectedIndexHash
= Record
->Hash
;
1573 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1575 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1576 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1577 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1579 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1581 Status
= StatAuthError
;
1582 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1587 if ((*Target
)->IsOptional() == true)
1589 if ((*Target
)->IsSubIndex() == true)
1590 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1591 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1592 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1594 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1595 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true)
1596 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1597 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1599 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1604 /* Queue Packages file (either diff or full packages files, depending
1605 on the users option) - we also check if the PDiff Index file is listed
1606 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1607 instead, but passing the required info to it is to much hassle */
1608 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1609 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1610 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1611 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1613 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1617 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1619 string::size_type pos
;
1621 // check for missing sigs (that where not fatal because otherwise we had
1624 string msg
= _("There is no public key available for the "
1625 "following key IDs:\n");
1626 pos
= Message
.find("NO_PUBKEY ");
1627 if (pos
!= std::string::npos
)
1629 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1630 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1631 missingkeys
+= (Fingerprint
);
1633 if(!missingkeys
.empty())
1634 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1636 string Transformed
= MetaIndexParser
->GetExpectedDist();
1638 if (Transformed
== "../project/experimental")
1640 Transformed
= "experimental";
1643 pos
= Transformed
.rfind('/');
1644 if (pos
!= string::npos
)
1646 Transformed
= Transformed
.substr(0, pos
);
1649 if (Transformed
== ".")
1654 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1655 MetaIndexParser
->GetValidUntil() > 0) {
1656 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1657 if (invalid_since
> 0)
1658 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1659 // the time since then the file is invalid - formated in the same way as in
1660 // the download progress display (e.g. 7d 3h 42min 1s)
1661 return _error
->Error(
1662 _("Release file for %s is expired (invalid since %s). "
1663 "Updates for this repository will not be applied."),
1664 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1667 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1669 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1670 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1671 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1674 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1676 // This might become fatal one day
1677 // Status = StatAuthError;
1678 // ErrorText = "Conflicting distribution; expected "
1679 // + MetaIndexParser->GetExpectedDist() + " but got "
1680 // + MetaIndexParser->GetDist();
1682 if (!Transformed
.empty())
1684 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1685 Desc
.Description
.c_str(),
1686 Transformed
.c_str(),
1687 MetaIndexParser
->GetDist().c_str());
1694 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1695 // ---------------------------------------------------------------------
1697 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1699 if (AuthPass
== true)
1701 // gpgv method failed, if we have a good signature
1702 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1703 if (DestFile
!= SigFile
)
1704 LastGoodSigFile
.append(".gpg");
1705 LastGoodSigFile
.append(".reverify");
1707 if(FileExists(LastGoodSigFile
))
1709 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1710 if (DestFile
!= SigFile
)
1711 VerifiedSigFile
.append(".gpg");
1712 Rename(LastGoodSigFile
, VerifiedSigFile
);
1713 Status
= StatTransientNetworkError
;
1714 _error
->Warning(_("An error occurred during the signature "
1715 "verification. The repository is not updated "
1716 "and the previous index files will be used. "
1717 "GPG error: %s: %s\n"),
1718 Desc
.Description
.c_str(),
1719 LookupTag(Message
,"Message").c_str());
1720 RunScripts("APT::Update::Auth-Failure");
1722 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1723 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1724 _error
->Error(_("GPG error: %s: %s"),
1725 Desc
.Description
.c_str(),
1726 LookupTag(Message
,"Message").c_str());
1729 _error
->Warning(_("GPG error: %s: %s"),
1730 Desc
.Description
.c_str(),
1731 LookupTag(Message
,"Message").c_str());
1733 // gpgv method failed
1734 ReportMirrorFailure("GPGFailure");
1737 /* Always move the meta index, even if gpgv failed. This ensures
1738 * that PackageFile objects are correctly filled in */
1739 if (FileExists(DestFile
)) {
1740 string FinalFile
= _config
->FindDir("Dir::State::lists");
1741 FinalFile
+= URItoFileName(RealURI
);
1742 /* InRelease files become Release files, otherwise
1743 * they would be considered as trusted later on */
1744 if (SigFile
== DestFile
) {
1745 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1747 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1749 SigFile
= FinalFile
;
1751 Rename(DestFile
,FinalFile
);
1752 chmod(FinalFile
.c_str(),0644);
1754 DestFile
= FinalFile
;
1757 // No Release file was present, or verification failed, so fall
1758 // back to queueing Packages files without verification
1759 QueueIndexes(false);
1762 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1763 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1764 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1765 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1766 const vector
<struct IndexTarget
*>* IndexTargets
,
1767 indexRecords
* MetaIndexParser
) :
1768 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1769 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1770 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1774 // keep the old InRelease around in case of transistent network errors
1775 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1776 if (RealFileExists(Final
) == true)
1778 string
const LastGoodSig
= DestFile
+ ".reverify";
1779 Rename(Final
,LastGoodSig
);
1783 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1785 // if the file was never queued undo file-changes done in the constructor
1786 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1788 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1789 string
const LastGoodSig
= DestFile
+ ".reverify";
1790 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1791 Rename(LastGoodSig
, Final
);
1795 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1796 // ---------------------------------------------------------------------
1797 // FIXME: this can go away once the InRelease file is used widely
1798 string
pkgAcqMetaClearSig::Custom600Headers()
1800 string Final
= _config
->FindDir("Dir::State::lists");
1801 Final
+= URItoFileName(RealURI
);
1804 if (stat(Final
.c_str(),&Buf
) != 0)
1806 Final
= DestFile
+ ".reverify";
1807 if (stat(Final
.c_str(),&Buf
) != 0)
1808 return "\nIndex-File: true\nFail-Ignore: true\n";
1811 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1814 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1816 if (AuthPass
== false)
1818 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1819 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1820 string FinalFile
= _config
->FindDir("Dir::State::lists");
1821 FinalFile
.append(URItoFileName(RealURI
));
1822 if (FileExists(FinalFile
))
1823 unlink(FinalFile
.c_str());
1825 new pkgAcqMetaSig(Owner
,
1826 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1827 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1828 IndexTargets
, MetaIndexParser
);
1829 if (Cnf
->LocalOnly
== true ||
1830 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1834 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1837 // AcqArchive::AcqArchive - Constructor /*{{{*/
1838 // ---------------------------------------------------------------------
1839 /* This just sets up the initial fetch environment and queues the first
1841 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1842 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1843 string
&StoreFilename
) :
1844 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1845 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1848 Retries
= _config
->FindI("Acquire::Retries",0);
1850 if (Version
.Arch() == 0)
1852 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1853 "This might mean you need to manually fix this package. "
1854 "(due to missing arch)"),
1855 Version
.ParentPkg().Name());
1859 /* We need to find a filename to determine the extension. We make the
1860 assumption here that all the available sources for this version share
1861 the same extension.. */
1862 // Skip not source sources, they do not have file fields.
1863 for (; Vf
.end() == false; ++Vf
)
1865 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1870 // Does not really matter here.. we are going to fail out below
1871 if (Vf
.end() != true)
1873 // If this fails to get a file name we will bomb out below.
1874 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1875 if (_error
->PendingError() == true)
1878 // Generate the final file name as: package_version_arch.foo
1879 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1880 QuoteString(Version
.VerStr(),"_:") + '_' +
1881 QuoteString(Version
.Arch(),"_:.") +
1882 "." + flExtension(Parse
.FileName());
1885 // check if we have one trusted source for the package. if so, switch
1886 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1887 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
1888 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
1889 bool seenUntrusted
= false;
1890 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1892 pkgIndexFile
*Index
;
1893 if (Sources
->FindIndex(i
.File(),Index
) == false)
1896 if (debugAuth
== true)
1897 std::cerr
<< "Checking index: " << Index
->Describe()
1898 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
1900 if (Index
->IsTrusted() == true)
1903 if (allowUnauth
== false)
1907 seenUntrusted
= true;
1910 // "allow-unauthenticated" restores apts old fetching behaviour
1911 // that means that e.g. unauthenticated file:// uris are higher
1912 // priority than authenticated http:// uris
1913 if (allowUnauth
== true && seenUntrusted
== true)
1917 if (QueueNext() == false && _error
->PendingError() == false)
1918 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
1919 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
1922 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1923 // ---------------------------------------------------------------------
1924 /* This queues the next available file version for download. It checks if
1925 the archive is already available in the cache and stashs the MD5 for
1927 bool pkgAcqArchive::QueueNext()
1929 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1930 for (; Vf
.end() == false; ++Vf
)
1932 // Ignore not source sources
1933 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1936 // Try to cross match against the source list
1937 pkgIndexFile
*Index
;
1938 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1941 // only try to get a trusted package from another source if that source
1943 if(Trusted
&& !Index
->IsTrusted())
1946 // Grab the text package record
1947 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1948 if (_error
->PendingError() == true)
1951 string PkgFile
= Parse
.FileName();
1952 if (ForceHash
.empty() == false)
1954 if(stringcasecmp(ForceHash
, "sha512") == 0)
1955 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
1956 else if(stringcasecmp(ForceHash
, "sha256") == 0)
1957 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1958 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1959 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1961 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1966 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
1967 ExpectedHash
= HashString("SHA512", Hash
);
1968 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1969 ExpectedHash
= HashString("SHA256", Hash
);
1970 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1971 ExpectedHash
= HashString("SHA1", Hash
);
1973 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1975 if (PkgFile
.empty() == true)
1976 return _error
->Error(_("The package index files are corrupted. No Filename: "
1977 "field for package %s."),
1978 Version
.ParentPkg().Name());
1980 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1981 Desc
.Description
= Index
->ArchiveInfo(Version
);
1983 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1985 // See if we already have the file. (Legacy filenames)
1986 FileSize
= Version
->Size
;
1987 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1989 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1991 // Make sure the size matches
1992 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1997 StoreFilename
= DestFile
= FinalFile
;
2001 /* Hmm, we have a file and its size does not match, this means it is
2002 an old style mismatched arch */
2003 unlink(FinalFile
.c_str());
2006 // Check it again using the new style output filenames
2007 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2008 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2010 // Make sure the size matches
2011 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2016 StoreFilename
= DestFile
= FinalFile
;
2020 /* Hmm, we have a file and its size does not match, this shouldnt
2022 unlink(FinalFile
.c_str());
2025 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2027 // Check the destination file
2028 if (stat(DestFile
.c_str(),&Buf
) == 0)
2030 // Hmm, the partial file is too big, erase it
2031 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2032 unlink(DestFile
.c_str());
2034 PartialSize
= Buf
.st_size
;
2037 // Disables download of archives - useful if no real installation follows,
2038 // e.g. if we are just interested in proposed installation order
2039 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2044 StoreFilename
= DestFile
= FinalFile
;
2050 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2051 Desc
.Description
= Index
->ArchiveInfo(Version
);
2053 Desc
.ShortDesc
= Version
.ParentPkg().Name();
2062 // AcqArchive::Done - Finished fetching /*{{{*/
2063 // ---------------------------------------------------------------------
2065 void pkgAcqArchive::Done(string Message
,unsigned long long Size
,string CalcHash
,
2066 pkgAcquire::MethodConfig
*Cfg
)
2068 Item::Done(Message
,Size
,CalcHash
,Cfg
);
2071 if (Size
!= Version
->Size
)
2073 RenameOnError(SizeMismatch
);
2078 if(ExpectedHash
.toStr() != CalcHash
)
2080 RenameOnError(HashSumMismatch
);
2084 // Grab the output filename
2085 string FileName
= LookupTag(Message
,"Filename");
2086 if (FileName
.empty() == true)
2089 ErrorText
= "Method gave a blank filename";
2095 // Reference filename
2096 if (FileName
!= DestFile
)
2098 StoreFilename
= DestFile
= FileName
;
2103 // Done, move it into position
2104 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2105 FinalFile
+= flNotDir(StoreFilename
);
2106 Rename(DestFile
,FinalFile
);
2108 StoreFilename
= DestFile
= FinalFile
;
2112 // AcqArchive::Failed - Failure handler /*{{{*/
2113 // ---------------------------------------------------------------------
2114 /* Here we try other sources */
2115 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2117 ErrorText
= LookupTag(Message
,"Message");
2119 /* We don't really want to retry on failed media swaps, this prevents
2120 that. An interesting observation is that permanent failures are not
2122 if (Cnf
->Removable
== true &&
2123 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2125 // Vf = Version.FileList();
2126 while (Vf
.end() == false) ++Vf
;
2127 StoreFilename
= string();
2128 Item::Failed(Message
,Cnf
);
2132 if (QueueNext() == false)
2134 // This is the retry counter
2136 Cnf
->LocalOnly
== false &&
2137 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2140 Vf
= Version
.FileList();
2141 if (QueueNext() == true)
2145 StoreFilename
= string();
2146 Item::Failed(Message
,Cnf
);
2150 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2151 // ---------------------------------------------------------------------
2152 bool pkgAcqArchive::IsTrusted()
2157 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2158 // ---------------------------------------------------------------------
2160 void pkgAcqArchive::Finished()
2162 if (Status
== pkgAcquire::Item::StatDone
&&
2165 StoreFilename
= string();
2168 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2169 // ---------------------------------------------------------------------
2170 /* The file is added to the queue */
2171 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
2172 unsigned long long Size
,string Dsc
,string ShortDesc
,
2173 const string
&DestDir
, const string
&DestFilename
,
2175 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
2177 Retries
= _config
->FindI("Acquire::Retries",0);
2179 if(!DestFilename
.empty())
2180 DestFile
= DestFilename
;
2181 else if(!DestDir
.empty())
2182 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2184 DestFile
= flNotDir(URI
);
2188 Desc
.Description
= Dsc
;
2191 // Set the short description to the archive component
2192 Desc
.ShortDesc
= ShortDesc
;
2194 // Get the transfer sizes
2197 if (stat(DestFile
.c_str(),&Buf
) == 0)
2199 // Hmm, the partial file is too big, erase it
2200 if ((unsigned long long)Buf
.st_size
> Size
)
2201 unlink(DestFile
.c_str());
2203 PartialSize
= Buf
.st_size
;
2209 // AcqFile::Done - Item downloaded OK /*{{{*/
2210 // ---------------------------------------------------------------------
2212 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
2213 pkgAcquire::MethodConfig
*Cnf
)
2215 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2218 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2220 RenameOnError(HashSumMismatch
);
2224 string FileName
= LookupTag(Message
,"Filename");
2225 if (FileName
.empty() == true)
2228 ErrorText
= "Method gave a blank filename";
2234 // The files timestamp matches
2235 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2238 // We have to copy it into place
2239 if (FileName
!= DestFile
)
2242 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2243 Cnf
->Removable
== true)
2245 Desc
.URI
= "copy:" + FileName
;
2250 // Erase the file if it is a symlink so we can overwrite it
2252 if (lstat(DestFile
.c_str(),&St
) == 0)
2254 if (S_ISLNK(St
.st_mode
) != 0)
2255 unlink(DestFile
.c_str());
2259 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2261 ErrorText
= "Link to " + DestFile
+ " failure ";
2268 // AcqFile::Failed - Failure handler /*{{{*/
2269 // ---------------------------------------------------------------------
2270 /* Here we try other sources */
2271 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2273 ErrorText
= LookupTag(Message
,"Message");
2275 // This is the retry counter
2277 Cnf
->LocalOnly
== false &&
2278 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2285 Item::Failed(Message
,Cnf
);
2288 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2289 // ---------------------------------------------------------------------
2290 /* The only header we use is the last-modified header. */
2291 string
pkgAcqFile::Custom600Headers()
2294 return "\nIndex-File: true";