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 /*{{{*/
16 #include <apt-pkg/acquire-item.h>
17 #include <apt-pkg/configuration.h>
18 #include <apt-pkg/aptconfiguration.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/vendorlist.h>
21 #include <apt-pkg/error.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/fileutl.h>
24 #include <apt-pkg/md5.h>
25 #include <apt-pkg/sha1.h>
26 #include <apt-pkg/tagfile.h>
40 // Acquire::Item::Item - Constructor /*{{{*/
41 // ---------------------------------------------------------------------
43 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
44 PartialSize(0), Mode(0), ID(0), Complete(false),
45 Local(false), QueueCounter(0)
51 // Acquire::Item::~Item - Destructor /*{{{*/
52 // ---------------------------------------------------------------------
54 pkgAcquire::Item::~Item()
59 // Acquire::Item::Failed - Item failed to download /*{{{*/
60 // ---------------------------------------------------------------------
61 /* We return to an idle state if there are still other queues that could
63 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
66 ErrorText
= LookupTag(Message
,"Message");
67 UsedMirror
= LookupTag(Message
,"UsedMirror");
68 if (QueueCounter
<= 1)
70 /* This indicates that the file is not available right now but might
71 be sometime later. If we do a retry cycle then this should be
73 if (Cnf
->LocalOnly
== true &&
74 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
85 // report mirror failure back to LP if we actually use a mirror
86 string FailReason
= LookupTag(Message
, "FailReason");
87 if(FailReason
.size() != 0)
88 ReportMirrorFailure(FailReason
);
90 ReportMirrorFailure(ErrorText
);
93 // Acquire::Item::Start - Item has begun to download /*{{{*/
94 // ---------------------------------------------------------------------
95 /* Stash status and the file size. Note that setting Complete means
96 sub-phases of the acquire process such as decompresion are operating */
97 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long Size
)
99 Status
= StatFetching
;
100 if (FileSize
== 0 && Complete
== false)
104 // Acquire::Item::Done - Item downloaded OK /*{{{*/
105 // ---------------------------------------------------------------------
107 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string Hash
,
108 pkgAcquire::MethodConfig
*Cnf
)
110 // We just downloaded something..
111 string FileName
= LookupTag(Message
,"Filename");
112 UsedMirror
= LookupTag(Message
,"UsedMirror");
113 if (Complete
== false && !Local
&& FileName
== DestFile
)
116 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
122 ErrorText
= string();
123 Owner
->Dequeue(this);
126 // Acquire::Item::Rename - Rename a file /*{{{*/
127 // ---------------------------------------------------------------------
128 /* This helper function is used by alot of item methods as thier final
130 void pkgAcquire::Item::Rename(string From
,string To
)
132 if (rename(From
.c_str(),To
.c_str()) != 0)
135 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
136 From
.c_str(),To
.c_str());
143 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
145 // we only act if a mirror was used at all
146 if(UsedMirror
.empty())
149 std::cerr
<< "\nReportMirrorFailure: "
151 << " Uri: " << DescURI()
153 << FailCode
<< std::endl
;
155 const char *Args
[40];
157 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
158 "/usr/lib/apt/apt-report-mirror-failure");
159 if(!FileExists(report
))
161 Args
[i
++] = report
.c_str();
162 Args
[i
++] = UsedMirror
.c_str();
163 Args
[i
++] = DescURI().c_str();
164 Args
[i
++] = FailCode
.c_str();
166 pid_t pid
= ExecFork();
169 _error
->Error("ReportMirrorFailure Fork failed");
174 execvp(Args
[0], (char**)Args
);
175 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
178 if(!ExecWait(pid
, "report-mirror-failure"))
180 _error
->Warning("Couldn't report problem to '%s'",
181 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
185 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
186 // ---------------------------------------------------------------------
187 /* Get the DiffIndex file first and see if there are patches availabe
188 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
189 * patches. If anything goes wrong in that process, it will fall back to
190 * the original packages file
192 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
193 string URI
,string URIDesc
,string ShortDesc
,
194 HashString ExpectedHash
)
195 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
199 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
201 Desc
.Description
= URIDesc
+ "/DiffIndex";
203 Desc
.ShortDesc
= ShortDesc
;
204 Desc
.URI
= URI
+ ".diff/Index";
206 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
207 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
210 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
212 // look for the current package file
213 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
214 CurrentPackagesFile
+= URItoFileName(RealURI
);
216 // FIXME: this file:/ check is a hack to prevent fetching
217 // from local sources. this is really silly, and
218 // should be fixed cleanly as soon as possible
219 if(!FileExists(CurrentPackagesFile
) ||
220 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
222 // we don't have a pkg file or we don't want to queue
224 std::clog
<< "No index file, local or canceld by user" << std::endl
;
230 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
231 << CurrentPackagesFile
<< std::endl
;
237 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
238 // ---------------------------------------------------------------------
239 /* The only header we use is the last-modified header. */
240 string
pkgAcqDiffIndex::Custom600Headers()
242 string Final
= _config
->FindDir("Dir::State::lists");
243 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
246 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
249 if (stat(Final
.c_str(),&Buf
) != 0)
250 return "\nIndex-File: true";
252 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
255 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
258 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
263 vector
<DiffInfo
> available_patches
;
265 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
267 if (_error
->PendingError() == true)
270 if(TF
.Step(Tags
) == true)
276 string
const tmp
= Tags
.FindS("SHA1-Current");
277 std::stringstream
ss(tmp
);
278 ss
>> ServerSha1
>> size
;
279 unsigned long const ServerSize
= atol(size
.c_str());
281 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
283 SHA1
.AddFD(fd
.Fd(), fd
.Size());
284 string
const local_sha1
= SHA1
.Result();
286 if(local_sha1
== ServerSha1
)
288 // we have the same sha1 as the server
290 std::clog
<< "Package file is up-to-date" << std::endl
;
291 // set found to true, this will queue a pkgAcqIndexDiffs with
292 // a empty availabe_patches
298 std::clog
<< "SHA1-Current: " << ServerSha1
<< std::endl
;
300 // check the historie and see what patches we need
301 string
const history
= Tags
.FindS("SHA1-History");
302 std::stringstream
hist(history
);
303 while(hist
>> d
.sha1
>> size
>> d
.file
)
305 // read until the first match is found
306 // from that point on, we probably need all diffs
307 if(d
.sha1
== local_sha1
)
309 else if (found
== false)
313 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
314 available_patches
.push_back(d
);
317 if (available_patches
.empty() == false)
319 // patching with too many files is rather slow compared to a fast download
320 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
321 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
324 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
325 << ") so fallback to complete download" << std::endl
;
329 // see if the patches are too big
330 found
= false; // it was true and it will be true again at the end
331 d
= *available_patches
.begin();
332 string
const firstPatch
= d
.file
;
333 unsigned long patchesSize
= 0;
334 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
335 while(patches
>> d
.sha1
>> size
>> d
.file
)
337 if (firstPatch
== d
.file
)
339 else if (found
== false)
342 patchesSize
+= atol(size
.c_str());
344 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
345 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
348 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
349 << ") so fallback to complete download" << std::endl
;
355 // we have something, queue the next diff
359 string::size_type
const last_space
= Description
.rfind(" ");
360 if(last_space
!= string::npos
)
361 Description
.erase(last_space
, Description
.size()-last_space
);
362 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
363 ExpectedHash
, available_patches
);
371 // Nothing found, report and return false
372 // Failing here is ok, if we return false later, the full
373 // IndexFile is queued
375 std::clog
<< "Can't find a patch in the index file" << std::endl
;
379 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
382 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
383 << "Falling back to normal index file aquire" << std::endl
;
385 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
393 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
394 pkgAcquire::MethodConfig
*Cnf
)
397 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
399 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
402 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
404 // sucess in downloading the index
406 FinalFile
+= string(".IndexDiff");
408 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
410 Rename(DestFile
,FinalFile
);
411 chmod(FinalFile
.c_str(),0644);
412 DestFile
= FinalFile
;
414 if(!ParseDiffIndex(DestFile
))
415 return Failed("", NULL
);
423 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
424 // ---------------------------------------------------------------------
425 /* The package diff is added to the queue. one object is constructed
426 * for each diff and the index
428 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
429 string URI
,string URIDesc
,string ShortDesc
,
430 HashString ExpectedHash
,
431 vector
<DiffInfo
> diffs
)
432 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
433 available_patches(diffs
)
436 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
437 DestFile
+= URItoFileName(URI
);
439 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
441 Description
= URIDesc
;
443 Desc
.ShortDesc
= ShortDesc
;
445 if(available_patches
.size() == 0)
447 // we are done (yeah!)
453 State
= StateFetchDiff
;
458 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
461 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
462 << "Falling back to normal index file aquire" << std::endl
;
463 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
468 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
469 void pkgAcqIndexDiffs::Finish(bool allDone
)
471 // we restore the original name, this is required, otherwise
472 // the file will be cleaned
475 DestFile
= _config
->FindDir("Dir::State::lists");
476 DestFile
+= URItoFileName(RealURI
);
478 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
480 Status
= StatAuthError
;
481 ErrorText
= _("MD5Sum mismatch");
482 Rename(DestFile
,DestFile
+ ".FAILED");
487 // this is for the "real" finish
492 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
497 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
504 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
507 // calc sha1 of the just patched file
508 string FinalFile
= _config
->FindDir("Dir::State::lists");
509 FinalFile
+= URItoFileName(RealURI
);
511 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
513 SHA1
.AddFD(fd
.Fd(), fd
.Size());
514 string local_sha1
= string(SHA1
.Result());
516 std::clog
<< "QueueNextDiff: "
517 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
519 // remove all patches until the next matching patch is found
520 // this requires the Index file to be ordered
521 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
522 available_patches
.size() > 0 &&
523 I
!= available_patches
.end() &&
524 (*I
).sha1
!= local_sha1
;
527 available_patches
.erase(I
);
530 // error checking and falling back if no patch was found
531 if(available_patches
.size() == 0)
537 // queue the right diff
538 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
539 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
540 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
541 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
544 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
551 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
552 pkgAcquire::MethodConfig
*Cnf
)
555 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
557 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
560 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
562 // sucess in downloading a diff, enter ApplyDiff state
563 if(State
== StateFetchDiff
)
567 std::clog
<< "Sending to gzip method: " << FinalFile
<< std::endl
;
569 string FileName
= LookupTag(Message
,"Filename");
570 State
= StateUnzipDiff
;
572 Desc
.URI
= "gzip:" + FileName
;
573 DestFile
+= ".decomp";
579 // sucess in downloading a diff, enter ApplyDiff state
580 if(State
== StateUnzipDiff
)
583 // rred excepts the patch as $FinalFile.ed
584 Rename(DestFile
,FinalFile
+".ed");
587 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
589 State
= StateApplyDiff
;
591 Desc
.URI
= "rred:" + FinalFile
;
598 // success in download/apply a diff, queue next (if needed)
599 if(State
== StateApplyDiff
)
601 // remove the just applied patch
602 available_patches
.erase(available_patches
.begin());
607 std::clog
<< "Moving patched file in place: " << std::endl
608 << DestFile
<< " -> " << FinalFile
<< std::endl
;
610 Rename(DestFile
,FinalFile
);
611 chmod(FinalFile
.c_str(),0644);
613 // see if there is more to download
614 if(available_patches
.size() > 0) {
615 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
616 ExpectedHash
, available_patches
);
623 // AcqIndex::AcqIndex - Constructor /*{{{*/
624 // ---------------------------------------------------------------------
625 /* The package file is added to the queue and a second class is
626 instantiated to fetch the revision file */
627 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
628 string URI
,string URIDesc
,string ShortDesc
,
629 HashString ExpectedHash
, string comprExt
)
630 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
632 Decompression
= false;
635 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
636 DestFile
+= URItoFileName(URI
);
640 // autoselect the compression method
641 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
642 if (types
.empty() == true)
645 comprExt
= "." + types
[0];
647 CompressionExtension
= ((comprExt
== "plain" || comprExt
== ".") ? "" : comprExt
);
649 Desc
.URI
= URI
+ CompressionExtension
;
651 Desc
.Description
= URIDesc
;
653 Desc
.ShortDesc
= ShortDesc
;
658 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
659 // ---------------------------------------------------------------------
660 /* The only header we use is the last-modified header. */
661 string
pkgAcqIndex::Custom600Headers()
663 string Final
= _config
->FindDir("Dir::State::lists");
664 Final
+= URItoFileName(RealURI
);
667 if (stat(Final
.c_str(),&Buf
) != 0)
668 return "\nIndex-File: true";
669 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
672 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
674 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
676 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
677 t
!= types
.end(); t
++)
679 // jump over all already tried compression types
680 const unsigned int nameLen
= Desc
.URI
.size() - (*t
).size();
681 if(Desc
.URI
.substr(nameLen
) != *t
)
684 // we want to try it with the next extension (and make sure to
685 // not skip over the end)
687 if (t
== types
.end())
690 // queue new download
691 Desc
.URI
= Desc
.URI
.substr(0, nameLen
) + *t
;
692 new pkgAcqIndex(Owner
, RealURI
, Desc
.Description
, Desc
.ShortDesc
,
693 ExpectedHash
, string(".").append(*t
));
701 // on decompression failure, remove bad versions in partial/
702 if(Decompression
&& Erase
) {
703 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
704 s
+= URItoFileName(RealURI
);
708 Item::Failed(Message
,Cnf
);
711 // AcqIndex::Done - Finished a fetch /*{{{*/
712 // ---------------------------------------------------------------------
713 /* This goes through a number of states.. On the initial fetch the
714 method could possibly return an alternate filename which points
715 to the uncompressed version of the file. If this is so the file
716 is copied into the partial directory. In all other cases the file
717 is decompressed with a gzip uri. */
718 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string Hash
,
719 pkgAcquire::MethodConfig
*Cfg
)
721 Item::Done(Message
,Size
,Hash
,Cfg
);
723 if (Decompression
== true)
725 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
727 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
728 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
731 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
733 Status
= StatAuthError
;
734 ErrorText
= _("Hash Sum mismatch");
735 Rename(DestFile
,DestFile
+ ".FAILED");
736 ReportMirrorFailure("HashChecksumFailure");
739 // Done, move it into position
740 string FinalFile
= _config
->FindDir("Dir::State::lists");
741 FinalFile
+= URItoFileName(RealURI
);
742 Rename(DestFile
,FinalFile
);
743 chmod(FinalFile
.c_str(),0644);
745 /* We restore the original name to DestFile so that the clean operation
747 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
748 DestFile
+= URItoFileName(RealURI
);
750 // Remove the compressed version.
752 unlink(DestFile
.c_str());
759 // Handle the unzipd case
760 string FileName
= LookupTag(Message
,"Alt-Filename");
761 if (FileName
.empty() == false)
763 // The files timestamp matches
764 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
766 Decompression
= true;
768 DestFile
+= ".decomp";
769 Desc
.URI
= "copy:" + FileName
;
775 FileName
= LookupTag(Message
,"Filename");
776 if (FileName
.empty() == true)
779 ErrorText
= "Method gave a blank filename";
782 // The files timestamp matches
783 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
786 if (FileName
== DestFile
)
791 string compExt
= flExtension(flNotDir(URI(Desc
.URI
).Path
));
794 // get the binary name for your used compression type
795 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
796 if(decompProg
.empty() == false);
797 // flExtensions returns the full name if no extension is found
798 // this is why we have this complicated compare operation here
799 // FIMXE: add a new flJustExtension() that return "" if no
800 // extension is found and use that above so that it can
801 // be tested against ""
802 else if(compExt
== flNotDir(URI(Desc
.URI
).Path
))
805 _error
->Error("Unsupported extension: %s", compExt
.c_str());
809 Decompression
= true;
810 DestFile
+= ".decomp";
811 Desc
.URI
= decompProg
+ ":" + FileName
;
813 Mode
= decompProg
.c_str();
816 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
817 // ---------------------------------------------------------------------
818 /* The Translation file is added to the queue */
819 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
820 string URI
,string URIDesc
,string ShortDesc
)
821 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
825 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
826 // ---------------------------------------------------------------------
828 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
830 if (Cnf
->LocalOnly
== true ||
831 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
840 Item::Failed(Message
,Cnf
);
843 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
844 string URI
,string URIDesc
,string ShortDesc
,
845 string MetaIndexURI
, string MetaIndexURIDesc
,
846 string MetaIndexShortDesc
,
847 const vector
<IndexTarget
*>* IndexTargets
,
848 indexRecords
* MetaIndexParser
) :
849 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
850 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
851 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
853 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
854 DestFile
+= URItoFileName(URI
);
856 // remove any partial downloaded sig-file in partial/.
857 // it may confuse proxies and is too small to warrant a
858 // partial download anyway
859 unlink(DestFile
.c_str());
862 Desc
.Description
= URIDesc
;
864 Desc
.ShortDesc
= ShortDesc
;
867 string Final
= _config
->FindDir("Dir::State::lists");
868 Final
+= URItoFileName(RealURI
);
870 if (stat(Final
.c_str(),&Buf
) == 0)
872 // File was already in place. It needs to be re-downloaded/verified
873 // because Release might have changed, we do give it a differnt
874 // name than DestFile because otherwise the http method will
875 // send If-Range requests and there are too many broken servers
876 // out there that do not understand them
877 LastGoodSig
= DestFile
+".reverify";
878 Rename(Final
,LastGoodSig
);
884 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
885 // ---------------------------------------------------------------------
886 /* The only header we use is the last-modified header. */
887 string
pkgAcqMetaSig::Custom600Headers()
890 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
891 return "\nIndex-File: true";
893 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
896 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
897 pkgAcquire::MethodConfig
*Cfg
)
899 Item::Done(Message
,Size
,MD5
,Cfg
);
901 string FileName
= LookupTag(Message
,"Filename");
902 if (FileName
.empty() == true)
905 ErrorText
= "Method gave a blank filename";
909 if (FileName
!= DestFile
)
911 // We have to copy it into place
913 Desc
.URI
= "copy:" + FileName
;
920 // put the last known good file back on i-m-s hit (it will
921 // be re-verified again)
922 // Else do nothing, we have the new file in DestFile then
923 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
924 Rename(LastGoodSig
, DestFile
);
926 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
927 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
928 MetaIndexShortDesc
, DestFile
, IndexTargets
,
933 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
935 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
937 // if we get a network error we fail gracefully
938 if(Status
== StatTransientNetworkError
)
940 Item::Failed(Message
,Cnf
);
941 // move the sigfile back on transient network failures
942 if(FileExists(LastGoodSig
))
943 Rename(LastGoodSig
,Final
);
945 // set the status back to , Item::Failed likes to reset it
946 Status
= pkgAcquire::Item::StatTransientNetworkError
;
950 // Delete any existing sigfile when the acquire failed
951 unlink(Final
.c_str());
953 // queue a pkgAcqMetaIndex with no sigfile
954 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
955 "", IndexTargets
, MetaIndexParser
);
957 if (Cnf
->LocalOnly
== true ||
958 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
967 Item::Failed(Message
,Cnf
);
970 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
971 string URI
,string URIDesc
,string ShortDesc
,
973 const vector
<struct IndexTarget
*>* IndexTargets
,
974 indexRecords
* MetaIndexParser
) :
975 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
976 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
978 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
979 DestFile
+= URItoFileName(URI
);
982 Desc
.Description
= URIDesc
;
984 Desc
.ShortDesc
= ShortDesc
;
990 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
991 // ---------------------------------------------------------------------
992 /* The only header we use is the last-modified header. */
993 string
pkgAcqMetaIndex::Custom600Headers()
995 string Final
= _config
->FindDir("Dir::State::lists");
996 Final
+= URItoFileName(RealURI
);
999 if (stat(Final
.c_str(),&Buf
) != 0)
1000 return "\nIndex-File: true";
1002 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1005 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string Hash
, /*{{{*/
1006 pkgAcquire::MethodConfig
*Cfg
)
1008 Item::Done(Message
,Size
,Hash
,Cfg
);
1010 // MetaIndexes are done in two passes: one to download the
1011 // metaindex with an appropriate method, and a second to verify it
1012 // with the gpgv method
1014 if (AuthPass
== true)
1018 // all cool, move Release file into place
1021 string FinalFile
= _config
->FindDir("Dir::State::lists");
1022 FinalFile
+= URItoFileName(RealURI
);
1023 Rename(DestFile
,FinalFile
);
1024 chmod(FinalFile
.c_str(),0644);
1025 DestFile
= FinalFile
;
1029 RetrievalDone(Message
);
1031 // Still more retrieving to do
1036 // There was no signature file, so we are finished. Download
1037 // the indexes without verification.
1038 QueueIndexes(false);
1042 // There was a signature file, so pass it to gpgv for
1045 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1046 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1047 << SigFile
<< "," << DestFile
<< ")\n";
1049 Desc
.URI
= "gpgv:" + SigFile
;
1056 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1058 // We have just finished downloading a Release file (it is not
1061 string FileName
= LookupTag(Message
,"Filename");
1062 if (FileName
.empty() == true)
1065 ErrorText
= "Method gave a blank filename";
1069 if (FileName
!= DestFile
)
1072 Desc
.URI
= "copy:" + FileName
;
1077 // make sure to verify against the right file on I-M-S hit
1078 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1081 string FinalFile
= _config
->FindDir("Dir::State::lists");
1082 FinalFile
+= URItoFileName(RealURI
);
1083 DestFile
= FinalFile
;
1088 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1090 // At this point, the gpgv method has succeeded, so there is a
1091 // valid signature from a key in the trusted keyring. We
1092 // perform additional verification of its contents, and use them
1093 // to verify the indexes we are about to download
1095 if (!MetaIndexParser
->Load(DestFile
))
1097 Status
= StatAuthError
;
1098 ErrorText
= MetaIndexParser
->ErrorText
;
1102 if (!VerifyVendor(Message
))
1107 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1108 std::cerr
<< "Signature verification succeeded: "
1109 << DestFile
<< std::endl
;
1111 // Download further indexes with verification
1114 // Done, move signature file into position
1115 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1116 URItoFileName(RealURI
) + ".gpg";
1117 Rename(SigFile
,VerifiedSigFile
);
1118 chmod(VerifiedSigFile
.c_str(),0644);
1121 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1123 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1124 Target
!= IndexTargets
->end();
1127 HashString ExpectedIndexHash
;
1130 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1133 Status
= StatAuthError
;
1134 ErrorText
= "Unable to find expected entry "
1135 + (*Target
)->MetaKey
+ " in Meta-index file (malformed Release file?)";
1138 ExpectedIndexHash
= Record
->Hash
;
1139 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1141 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1142 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1144 if (ExpectedIndexHash
.empty())
1146 Status
= StatAuthError
;
1147 ErrorText
= "Unable to find hash sum for "
1148 + (*Target
)->MetaKey
+ " in Meta-index file";
1153 // Queue Packages file (either diff or full packages files, depending
1154 // on the users option)
1155 if(_config
->FindB("Acquire::PDiffs",false) == true)
1156 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1157 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1159 new pkgAcqIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1160 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1164 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1166 // // Maybe this should be made available from above so we don't have
1167 // // to read and parse it every time?
1168 // pkgVendorList List;
1169 // List.ReadMainList();
1171 // const Vendor* Vndr = NULL;
1172 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1174 // string::size_type pos = (*I).find("VALIDSIG ");
1175 // if (_config->FindB("Debug::Vendor", false))
1176 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1178 // if (pos != std::string::npos)
1180 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1181 // if (_config->FindB("Debug::Vendor", false))
1182 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1184 // Vndr = List.FindVendor(Fingerprint) != "";
1185 // if (Vndr != NULL);
1189 string::size_type pos
;
1191 // check for missing sigs (that where not fatal because otherwise we had
1194 string msg
= _("There is no public key available for the "
1195 "following key IDs:\n");
1196 pos
= Message
.find("NO_PUBKEY ");
1197 if (pos
!= std::string::npos
)
1199 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1200 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1201 missingkeys
+= (Fingerprint
);
1203 if(!missingkeys
.empty())
1204 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1206 string Transformed
= MetaIndexParser
->GetExpectedDist();
1208 if (Transformed
== "../project/experimental")
1210 Transformed
= "experimental";
1213 pos
= Transformed
.rfind('/');
1214 if (pos
!= string::npos
)
1216 Transformed
= Transformed
.substr(0, pos
);
1219 if (Transformed
== ".")
1224 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1226 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1227 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1228 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1231 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1233 // This might become fatal one day
1234 // Status = StatAuthError;
1235 // ErrorText = "Conflicting distribution; expected "
1236 // + MetaIndexParser->GetExpectedDist() + " but got "
1237 // + MetaIndexParser->GetDist();
1239 if (!Transformed
.empty())
1241 _error
->Warning("Conflicting distribution: %s (expected %s but got %s)",
1242 Desc
.Description
.c_str(),
1243 Transformed
.c_str(),
1244 MetaIndexParser
->GetDist().c_str());
1251 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1252 // ---------------------------------------------------------------------
1254 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1256 if (AuthPass
== true)
1258 // gpgv method failed, if we have a good signature
1259 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists") +
1260 "partial/" + URItoFileName(RealURI
) + ".gpg.reverify";
1261 if(FileExists(LastGoodSigFile
))
1263 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1264 URItoFileName(RealURI
) + ".gpg";
1265 Rename(LastGoodSigFile
,VerifiedSigFile
);
1266 Status
= StatTransientNetworkError
;
1267 _error
->Warning(_("A error occurred during the signature "
1268 "verification. The repository is not updated "
1269 "and the previous index files will be used."
1270 "GPG error: %s: %s\n"),
1271 Desc
.Description
.c_str(),
1272 LookupTag(Message
,"Message").c_str());
1273 RunScripts("APT::Update::Auth-Failure");
1276 _error
->Warning(_("GPG error: %s: %s"),
1277 Desc
.Description
.c_str(),
1278 LookupTag(Message
,"Message").c_str());
1280 // gpgv method failed
1281 ReportMirrorFailure("GPGFailure");
1284 // No Release file was present, or verification failed, so fall
1285 // back to queueing Packages files without verification
1286 QueueIndexes(false);
1289 // AcqArchive::AcqArchive - Constructor /*{{{*/
1290 // ---------------------------------------------------------------------
1291 /* This just sets up the initial fetch environment and queues the first
1293 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1294 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1295 string
&StoreFilename
) :
1296 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1297 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1300 Retries
= _config
->FindI("Acquire::Retries",0);
1302 if (Version
.Arch() == 0)
1304 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1305 "This might mean you need to manually fix this package. "
1306 "(due to missing arch)"),
1307 Version
.ParentPkg().Name());
1311 /* We need to find a filename to determine the extension. We make the
1312 assumption here that all the available sources for this version share
1313 the same extension.. */
1314 // Skip not source sources, they do not have file fields.
1315 for (; Vf
.end() == false; Vf
++)
1317 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1322 // Does not really matter here.. we are going to fail out below
1323 if (Vf
.end() != true)
1325 // If this fails to get a file name we will bomb out below.
1326 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1327 if (_error
->PendingError() == true)
1330 // Generate the final file name as: package_version_arch.foo
1331 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1332 QuoteString(Version
.VerStr(),"_:") + '_' +
1333 QuoteString(Version
.Arch(),"_:.") +
1334 "." + flExtension(Parse
.FileName());
1337 // check if we have one trusted source for the package. if so, switch
1338 // to "TrustedOnly" mode
1339 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1341 pkgIndexFile
*Index
;
1342 if (Sources
->FindIndex(i
.File(),Index
) == false)
1344 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1346 std::cerr
<< "Checking index: " << Index
->Describe()
1347 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1349 if (Index
->IsTrusted()) {
1355 // "allow-unauthenticated" restores apts old fetching behaviour
1356 // that means that e.g. unauthenticated file:// uris are higher
1357 // priority than authenticated http:// uris
1358 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1362 if (QueueNext() == false && _error
->PendingError() == false)
1363 _error
->Error(_("I wasn't able to locate file for the %s package. "
1364 "This might mean you need to manually fix this package."),
1365 Version
.ParentPkg().Name());
1368 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1369 // ---------------------------------------------------------------------
1370 /* This queues the next available file version for download. It checks if
1371 the archive is already available in the cache and stashs the MD5 for
1373 bool pkgAcqArchive::QueueNext()
1375 for (; Vf
.end() == false; Vf
++)
1377 // Ignore not source sources
1378 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1381 // Try to cross match against the source list
1382 pkgIndexFile
*Index
;
1383 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1386 // only try to get a trusted package from another source if that source
1388 if(Trusted
&& !Index
->IsTrusted())
1391 // Grab the text package record
1392 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1393 if (_error
->PendingError() == true)
1396 string PkgFile
= Parse
.FileName();
1397 if(Parse
.SHA256Hash() != "")
1398 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1399 else if (Parse
.SHA1Hash() != "")
1400 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1402 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1403 if (PkgFile
.empty() == true)
1404 return _error
->Error(_("The package index files are corrupted. No Filename: "
1405 "field for package %s."),
1406 Version
.ParentPkg().Name());
1408 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1409 Desc
.Description
= Index
->ArchiveInfo(Version
);
1411 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1413 // See if we already have the file. (Legacy filenames)
1414 FileSize
= Version
->Size
;
1415 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1417 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1419 // Make sure the size matches
1420 if ((unsigned)Buf
.st_size
== Version
->Size
)
1425 StoreFilename
= DestFile
= FinalFile
;
1429 /* Hmm, we have a file and its size does not match, this means it is
1430 an old style mismatched arch */
1431 unlink(FinalFile
.c_str());
1434 // Check it again using the new style output filenames
1435 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1436 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1438 // Make sure the size matches
1439 if ((unsigned)Buf
.st_size
== Version
->Size
)
1444 StoreFilename
= DestFile
= FinalFile
;
1448 /* Hmm, we have a file and its size does not match, this shouldnt
1450 unlink(FinalFile
.c_str());
1453 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1455 // Check the destination file
1456 if (stat(DestFile
.c_str(),&Buf
) == 0)
1458 // Hmm, the partial file is too big, erase it
1459 if ((unsigned)Buf
.st_size
> Version
->Size
)
1460 unlink(DestFile
.c_str());
1462 PartialSize
= Buf
.st_size
;
1467 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1468 Desc
.Description
= Index
->ArchiveInfo(Version
);
1470 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1479 // AcqArchive::Done - Finished fetching /*{{{*/
1480 // ---------------------------------------------------------------------
1482 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string CalcHash
,
1483 pkgAcquire::MethodConfig
*Cfg
)
1485 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1488 if (Size
!= Version
->Size
)
1491 ErrorText
= _("Size mismatch");
1496 if(ExpectedHash
.toStr() != CalcHash
)
1499 ErrorText
= _("Hash Sum mismatch");
1500 if(FileExists(DestFile
))
1501 Rename(DestFile
,DestFile
+ ".FAILED");
1505 // Grab the output filename
1506 string FileName
= LookupTag(Message
,"Filename");
1507 if (FileName
.empty() == true)
1510 ErrorText
= "Method gave a blank filename";
1516 // Reference filename
1517 if (FileName
!= DestFile
)
1519 StoreFilename
= DestFile
= FileName
;
1524 // Done, move it into position
1525 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1526 FinalFile
+= flNotDir(StoreFilename
);
1527 Rename(DestFile
,FinalFile
);
1529 StoreFilename
= DestFile
= FinalFile
;
1533 // AcqArchive::Failed - Failure handler /*{{{*/
1534 // ---------------------------------------------------------------------
1535 /* Here we try other sources */
1536 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1538 ErrorText
= LookupTag(Message
,"Message");
1540 /* We don't really want to retry on failed media swaps, this prevents
1541 that. An interesting observation is that permanent failures are not
1543 if (Cnf
->Removable
== true &&
1544 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1546 // Vf = Version.FileList();
1547 while (Vf
.end() == false) Vf
++;
1548 StoreFilename
= string();
1549 Item::Failed(Message
,Cnf
);
1553 if (QueueNext() == false)
1555 // This is the retry counter
1557 Cnf
->LocalOnly
== false &&
1558 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1561 Vf
= Version
.FileList();
1562 if (QueueNext() == true)
1566 StoreFilename
= string();
1567 Item::Failed(Message
,Cnf
);
1571 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1572 // ---------------------------------------------------------------------
1573 bool pkgAcqArchive::IsTrusted()
1578 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1579 // ---------------------------------------------------------------------
1581 void pkgAcqArchive::Finished()
1583 if (Status
== pkgAcquire::Item::StatDone
&&
1586 StoreFilename
= string();
1589 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1590 // ---------------------------------------------------------------------
1591 /* The file is added to the queue */
1592 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1593 unsigned long Size
,string Dsc
,string ShortDesc
,
1594 const string
&DestDir
, const string
&DestFilename
) :
1595 Item(Owner
), ExpectedHash(Hash
)
1597 Retries
= _config
->FindI("Acquire::Retries",0);
1599 if(!DestFilename
.empty())
1600 DestFile
= DestFilename
;
1601 else if(!DestDir
.empty())
1602 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1604 DestFile
= flNotDir(URI
);
1608 Desc
.Description
= Dsc
;
1611 // Set the short description to the archive component
1612 Desc
.ShortDesc
= ShortDesc
;
1614 // Get the transfer sizes
1617 if (stat(DestFile
.c_str(),&Buf
) == 0)
1619 // Hmm, the partial file is too big, erase it
1620 if ((unsigned)Buf
.st_size
> Size
)
1621 unlink(DestFile
.c_str());
1623 PartialSize
= Buf
.st_size
;
1629 // AcqFile::Done - Item downloaded OK /*{{{*/
1630 // ---------------------------------------------------------------------
1632 void pkgAcqFile::Done(string Message
,unsigned long Size
,string CalcHash
,
1633 pkgAcquire::MethodConfig
*Cnf
)
1635 Item::Done(Message
,Size
,CalcHash
,Cnf
);
1638 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
1641 ErrorText
= "Hash Sum mismatch";
1642 Rename(DestFile
,DestFile
+ ".FAILED");
1646 string FileName
= LookupTag(Message
,"Filename");
1647 if (FileName
.empty() == true)
1650 ErrorText
= "Method gave a blank filename";
1656 // The files timestamp matches
1657 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1660 // We have to copy it into place
1661 if (FileName
!= DestFile
)
1664 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1665 Cnf
->Removable
== true)
1667 Desc
.URI
= "copy:" + FileName
;
1672 // Erase the file if it is a symlink so we can overwrite it
1674 if (lstat(DestFile
.c_str(),&St
) == 0)
1676 if (S_ISLNK(St
.st_mode
) != 0)
1677 unlink(DestFile
.c_str());
1681 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1683 ErrorText
= "Link to " + DestFile
+ " failure ";
1690 // AcqFile::Failed - Failure handler /*{{{*/
1691 // ---------------------------------------------------------------------
1692 /* Here we try other sources */
1693 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1695 ErrorText
= LookupTag(Message
,"Message");
1697 // This is the retry counter
1699 Cnf
->LocalOnly
== false &&
1700 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1707 Item::Failed(Message
,Cnf
);