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)
277 string tmp
= Tags
.FindS("SHA1-Current");
278 std::stringstream
ss(tmp
);
281 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
283 SHA1
.AddFD(fd
.Fd(), fd
.Size());
284 local_sha1
= string(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 history
= Tags
.FindS("SHA1-History");
302 std::stringstream
hist(history
);
303 while(hist
>> d
.sha1
>> size
>> d
.file
)
305 d
.size
= atoi(size
.c_str());
306 // read until the first match is found
307 if(d
.sha1
== local_sha1
)
309 // from that point on, we probably need all diffs
313 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
314 available_patches
.push_back(d
);
319 // we have something, queue the next diff
323 string::size_type last_space
= Description
.rfind(" ");
324 if(last_space
!= string::npos
)
325 Description
.erase(last_space
, Description
.size()-last_space
);
326 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
327 ExpectedHash
, available_patches
);
335 // Nothing found, report and return false
336 // Failing here is ok, if we return false later, the full
337 // IndexFile is queued
339 std::clog
<< "Can't find a patch in the index file" << std::endl
;
343 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
346 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
347 << "Falling back to normal index file aquire" << std::endl
;
349 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
357 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
358 pkgAcquire::MethodConfig
*Cnf
)
361 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
363 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
366 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
368 // sucess in downloading the index
370 FinalFile
+= string(".IndexDiff");
372 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
374 Rename(DestFile
,FinalFile
);
375 chmod(FinalFile
.c_str(),0644);
376 DestFile
= FinalFile
;
378 if(!ParseDiffIndex(DestFile
))
379 return Failed("", NULL
);
387 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
388 // ---------------------------------------------------------------------
389 /* The package diff is added to the queue. one object is constructed
390 * for each diff and the index
392 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
393 string URI
,string URIDesc
,string ShortDesc
,
394 HashString ExpectedHash
,
395 vector
<DiffInfo
> diffs
)
396 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
397 available_patches(diffs
)
400 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
401 DestFile
+= URItoFileName(URI
);
403 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
405 Description
= URIDesc
;
407 Desc
.ShortDesc
= ShortDesc
;
409 if(available_patches
.size() == 0)
411 // we are done (yeah!)
417 State
= StateFetchDiff
;
422 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
425 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
426 << "Falling back to normal index file aquire" << std::endl
;
427 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
432 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
433 void pkgAcqIndexDiffs::Finish(bool allDone
)
435 // we restore the original name, this is required, otherwise
436 // the file will be cleaned
439 DestFile
= _config
->FindDir("Dir::State::lists");
440 DestFile
+= URItoFileName(RealURI
);
442 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
444 Status
= StatAuthError
;
445 ErrorText
= _("MD5Sum mismatch");
446 Rename(DestFile
,DestFile
+ ".FAILED");
451 // this is for the "real" finish
456 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
461 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
468 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
471 // calc sha1 of the just patched file
472 string FinalFile
= _config
->FindDir("Dir::State::lists");
473 FinalFile
+= URItoFileName(RealURI
);
475 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
477 SHA1
.AddFD(fd
.Fd(), fd
.Size());
478 string local_sha1
= string(SHA1
.Result());
480 std::clog
<< "QueueNextDiff: "
481 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
483 // remove all patches until the next matching patch is found
484 // this requires the Index file to be ordered
485 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
486 available_patches
.size() > 0 &&
487 I
!= available_patches
.end() &&
488 (*I
).sha1
!= local_sha1
;
491 available_patches
.erase(I
);
494 // error checking and falling back if no patch was found
495 if(available_patches
.size() == 0)
501 // queue the right diff
502 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
503 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
504 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
505 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
508 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
515 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
516 pkgAcquire::MethodConfig
*Cnf
)
519 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
521 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
524 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
526 // sucess in downloading a diff, enter ApplyDiff state
527 if(State
== StateFetchDiff
)
531 std::clog
<< "Sending to gzip method: " << FinalFile
<< std::endl
;
533 string FileName
= LookupTag(Message
,"Filename");
534 State
= StateUnzipDiff
;
536 Desc
.URI
= "gzip:" + FileName
;
537 DestFile
+= ".decomp";
543 // sucess in downloading a diff, enter ApplyDiff state
544 if(State
== StateUnzipDiff
)
547 // rred excepts the patch as $FinalFile.ed
548 Rename(DestFile
,FinalFile
+".ed");
551 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
553 State
= StateApplyDiff
;
555 Desc
.URI
= "rred:" + FinalFile
;
562 // success in download/apply a diff, queue next (if needed)
563 if(State
== StateApplyDiff
)
565 // remove the just applied patch
566 available_patches
.erase(available_patches
.begin());
571 std::clog
<< "Moving patched file in place: " << std::endl
572 << DestFile
<< " -> " << FinalFile
<< std::endl
;
574 Rename(DestFile
,FinalFile
);
575 chmod(FinalFile
.c_str(),0644);
577 // see if there is more to download
578 if(available_patches
.size() > 0) {
579 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
580 ExpectedHash
, available_patches
);
587 // AcqIndex::AcqIndex - Constructor /*{{{*/
588 // ---------------------------------------------------------------------
589 /* The package file is added to the queue and a second class is
590 instantiated to fetch the revision file */
591 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
592 string URI
,string URIDesc
,string ShortDesc
,
593 HashString ExpectedHash
, string comprExt
)
594 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
596 Decompression
= false;
599 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
600 DestFile
+= URItoFileName(URI
);
604 // autoselect the compression method
605 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
606 if (types
.empty() == true)
609 comprExt
= "." + types
[0];
611 CompressionExtension
= ((comprExt
== "plain" || comprExt
== ".") ? "" : comprExt
);
613 Desc
.URI
= URI
+ CompressionExtension
;
615 Desc
.Description
= URIDesc
;
617 Desc
.ShortDesc
= ShortDesc
;
622 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
623 // ---------------------------------------------------------------------
624 /* The only header we use is the last-modified header. */
625 string
pkgAcqIndex::Custom600Headers()
627 string Final
= _config
->FindDir("Dir::State::lists");
628 Final
+= URItoFileName(RealURI
);
631 if (stat(Final
.c_str(),&Buf
) != 0)
632 return "\nIndex-File: true";
633 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
636 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
638 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
640 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
641 t
!= types
.end(); t
++)
643 // jump over all already tried compression types
644 const unsigned int nameLen
= Desc
.URI
.size() - (*t
).size();
645 if(Desc
.URI
.substr(nameLen
) != *t
)
648 // we want to try it with the next extension (and make sure to
649 // not skip over the end)
651 if (t
== types
.end())
654 // queue new download
655 Desc
.URI
= Desc
.URI
.substr(0, nameLen
) + *t
;
656 new pkgAcqIndex(Owner
, RealURI
, Desc
.Description
, Desc
.ShortDesc
,
657 ExpectedHash
, string(".").append(*t
));
665 // on decompression failure, remove bad versions in partial/
666 if(Decompression
&& Erase
) {
667 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
668 s
+= URItoFileName(RealURI
);
672 Item::Failed(Message
,Cnf
);
675 // AcqIndex::Done - Finished a fetch /*{{{*/
676 // ---------------------------------------------------------------------
677 /* This goes through a number of states.. On the initial fetch the
678 method could possibly return an alternate filename which points
679 to the uncompressed version of the file. If this is so the file
680 is copied into the partial directory. In all other cases the file
681 is decompressed with a gzip uri. */
682 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string Hash
,
683 pkgAcquire::MethodConfig
*Cfg
)
685 Item::Done(Message
,Size
,Hash
,Cfg
);
687 if (Decompression
== true)
689 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
691 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
692 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
695 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
697 Status
= StatAuthError
;
698 ErrorText
= _("Hash Sum mismatch");
699 Rename(DestFile
,DestFile
+ ".FAILED");
700 ReportMirrorFailure("HashChecksumFailure");
703 // Done, move it into position
704 string FinalFile
= _config
->FindDir("Dir::State::lists");
705 FinalFile
+= URItoFileName(RealURI
);
706 Rename(DestFile
,FinalFile
);
707 chmod(FinalFile
.c_str(),0644);
709 /* We restore the original name to DestFile so that the clean operation
711 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
712 DestFile
+= URItoFileName(RealURI
);
714 // Remove the compressed version.
716 unlink(DestFile
.c_str());
723 // Handle the unzipd case
724 string FileName
= LookupTag(Message
,"Alt-Filename");
725 if (FileName
.empty() == false)
727 // The files timestamp matches
728 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
730 Decompression
= true;
732 DestFile
+= ".decomp";
733 Desc
.URI
= "copy:" + FileName
;
739 FileName
= LookupTag(Message
,"Filename");
740 if (FileName
.empty() == true)
743 ErrorText
= "Method gave a blank filename";
746 // The files timestamp matches
747 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
750 if (FileName
== DestFile
)
755 string compExt
= flExtension(flNotDir(URI(Desc
.URI
).Path
));
758 // get the binary name for your used compression type
759 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
760 if(decompProg
.empty() == false);
761 // flExtensions returns the full name if no extension is found
762 // this is why we have this complicated compare operation here
763 // FIMXE: add a new flJustExtension() that return "" if no
764 // extension is found and use that above so that it can
765 // be tested against ""
766 else if(compExt
== flNotDir(URI(Desc
.URI
).Path
))
769 _error
->Error("Unsupported extension: %s", compExt
.c_str());
773 Decompression
= true;
774 DestFile
+= ".decomp";
775 Desc
.URI
= decompProg
+ ":" + FileName
;
777 Mode
= decompProg
.c_str();
780 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
781 // ---------------------------------------------------------------------
782 /* The Translation file is added to the queue */
783 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
784 string URI
,string URIDesc
,string ShortDesc
)
785 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
789 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
790 // ---------------------------------------------------------------------
792 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
794 if (Cnf
->LocalOnly
== true ||
795 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
804 Item::Failed(Message
,Cnf
);
807 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
808 string URI
,string URIDesc
,string ShortDesc
,
809 string MetaIndexURI
, string MetaIndexURIDesc
,
810 string MetaIndexShortDesc
,
811 const vector
<IndexTarget
*>* IndexTargets
,
812 indexRecords
* MetaIndexParser
) :
813 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
814 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
815 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
817 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
818 DestFile
+= URItoFileName(URI
);
820 // remove any partial downloaded sig-file in partial/.
821 // it may confuse proxies and is too small to warrant a
822 // partial download anyway
823 unlink(DestFile
.c_str());
826 Desc
.Description
= URIDesc
;
828 Desc
.ShortDesc
= ShortDesc
;
831 string Final
= _config
->FindDir("Dir::State::lists");
832 Final
+= URItoFileName(RealURI
);
834 if (stat(Final
.c_str(),&Buf
) == 0)
836 // File was already in place. It needs to be re-downloaded/verified
837 // because Release might have changed, we do give it a differnt
838 // name than DestFile because otherwise the http method will
839 // send If-Range requests and there are too many broken servers
840 // out there that do not understand them
841 LastGoodSig
= DestFile
+".reverify";
842 Rename(Final
,LastGoodSig
);
848 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
849 // ---------------------------------------------------------------------
850 /* The only header we use is the last-modified header. */
851 string
pkgAcqMetaSig::Custom600Headers()
854 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
855 return "\nIndex-File: true";
857 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
860 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
861 pkgAcquire::MethodConfig
*Cfg
)
863 Item::Done(Message
,Size
,MD5
,Cfg
);
865 string FileName
= LookupTag(Message
,"Filename");
866 if (FileName
.empty() == true)
869 ErrorText
= "Method gave a blank filename";
873 if (FileName
!= DestFile
)
875 // We have to copy it into place
877 Desc
.URI
= "copy:" + FileName
;
884 // put the last known good file back on i-m-s hit (it will
885 // be re-verified again)
886 // Else do nothing, we have the new file in DestFile then
887 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
888 Rename(LastGoodSig
, DestFile
);
890 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
891 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
892 MetaIndexShortDesc
, DestFile
, IndexTargets
,
897 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
899 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
901 // if we get a network error we fail gracefully
902 if(Status
== StatTransientNetworkError
)
904 Item::Failed(Message
,Cnf
);
905 // move the sigfile back on transient network failures
906 if(FileExists(LastGoodSig
))
907 Rename(LastGoodSig
,Final
);
909 // set the status back to , Item::Failed likes to reset it
910 Status
= pkgAcquire::Item::StatTransientNetworkError
;
914 // Delete any existing sigfile when the acquire failed
915 unlink(Final
.c_str());
917 // queue a pkgAcqMetaIndex with no sigfile
918 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
919 "", IndexTargets
, MetaIndexParser
);
921 if (Cnf
->LocalOnly
== true ||
922 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
931 Item::Failed(Message
,Cnf
);
934 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
935 string URI
,string URIDesc
,string ShortDesc
,
937 const vector
<struct IndexTarget
*>* IndexTargets
,
938 indexRecords
* MetaIndexParser
) :
939 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
940 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
942 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
943 DestFile
+= URItoFileName(URI
);
946 Desc
.Description
= URIDesc
;
948 Desc
.ShortDesc
= ShortDesc
;
954 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
955 // ---------------------------------------------------------------------
956 /* The only header we use is the last-modified header. */
957 string
pkgAcqMetaIndex::Custom600Headers()
959 string Final
= _config
->FindDir("Dir::State::lists");
960 Final
+= URItoFileName(RealURI
);
963 if (stat(Final
.c_str(),&Buf
) != 0)
964 return "\nIndex-File: true";
966 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
969 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string Hash
, /*{{{*/
970 pkgAcquire::MethodConfig
*Cfg
)
972 Item::Done(Message
,Size
,Hash
,Cfg
);
974 // MetaIndexes are done in two passes: one to download the
975 // metaindex with an appropriate method, and a second to verify it
976 // with the gpgv method
978 if (AuthPass
== true)
982 // all cool, move Release file into place
985 string FinalFile
= _config
->FindDir("Dir::State::lists");
986 FinalFile
+= URItoFileName(RealURI
);
987 Rename(DestFile
,FinalFile
);
988 chmod(FinalFile
.c_str(),0644);
989 DestFile
= FinalFile
;
993 RetrievalDone(Message
);
995 // Still more retrieving to do
1000 // There was no signature file, so we are finished. Download
1001 // the indexes without verification.
1002 QueueIndexes(false);
1006 // There was a signature file, so pass it to gpgv for
1009 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1010 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1011 << SigFile
<< "," << DestFile
<< ")\n";
1013 Desc
.URI
= "gpgv:" + SigFile
;
1020 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1022 // We have just finished downloading a Release file (it is not
1025 string FileName
= LookupTag(Message
,"Filename");
1026 if (FileName
.empty() == true)
1029 ErrorText
= "Method gave a blank filename";
1033 if (FileName
!= DestFile
)
1036 Desc
.URI
= "copy:" + FileName
;
1041 // make sure to verify against the right file on I-M-S hit
1042 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1045 string FinalFile
= _config
->FindDir("Dir::State::lists");
1046 FinalFile
+= URItoFileName(RealURI
);
1047 DestFile
= FinalFile
;
1052 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1054 // At this point, the gpgv method has succeeded, so there is a
1055 // valid signature from a key in the trusted keyring. We
1056 // perform additional verification of its contents, and use them
1057 // to verify the indexes we are about to download
1059 if (!MetaIndexParser
->Load(DestFile
))
1061 Status
= StatAuthError
;
1062 ErrorText
= MetaIndexParser
->ErrorText
;
1066 if (!VerifyVendor(Message
))
1071 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1072 std::cerr
<< "Signature verification succeeded: "
1073 << DestFile
<< std::endl
;
1075 // Download further indexes with verification
1078 // Done, move signature file into position
1079 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1080 URItoFileName(RealURI
) + ".gpg";
1081 Rename(SigFile
,VerifiedSigFile
);
1082 chmod(VerifiedSigFile
.c_str(),0644);
1085 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1087 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1088 Target
!= IndexTargets
->end();
1091 HashString ExpectedIndexHash
;
1094 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1097 Status
= StatAuthError
;
1098 ErrorText
= "Unable to find expected entry "
1099 + (*Target
)->MetaKey
+ " in Meta-index file (malformed Release file?)";
1102 ExpectedIndexHash
= Record
->Hash
;
1103 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1105 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1106 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1108 if (ExpectedIndexHash
.empty())
1110 Status
= StatAuthError
;
1111 ErrorText
= "Unable to find hash sum for "
1112 + (*Target
)->MetaKey
+ " in Meta-index file";
1117 // Queue Packages file (either diff or full packages files, depending
1118 // on the users option)
1119 if(_config
->FindB("Acquire::PDiffs",false) == true)
1120 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1121 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1123 new pkgAcqIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1124 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1128 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1130 // // Maybe this should be made available from above so we don't have
1131 // // to read and parse it every time?
1132 // pkgVendorList List;
1133 // List.ReadMainList();
1135 // const Vendor* Vndr = NULL;
1136 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1138 // string::size_type pos = (*I).find("VALIDSIG ");
1139 // if (_config->FindB("Debug::Vendor", false))
1140 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1142 // if (pos != std::string::npos)
1144 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1145 // if (_config->FindB("Debug::Vendor", false))
1146 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1148 // Vndr = List.FindVendor(Fingerprint) != "";
1149 // if (Vndr != NULL);
1153 string::size_type pos
;
1155 // check for missing sigs (that where not fatal because otherwise we had
1158 string msg
= _("There is no public key available for the "
1159 "following key IDs:\n");
1160 pos
= Message
.find("NO_PUBKEY ");
1161 if (pos
!= std::string::npos
)
1163 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1164 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1165 missingkeys
+= (Fingerprint
);
1167 if(!missingkeys
.empty())
1168 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1170 string Transformed
= MetaIndexParser
->GetExpectedDist();
1172 if (Transformed
== "../project/experimental")
1174 Transformed
= "experimental";
1177 pos
= Transformed
.rfind('/');
1178 if (pos
!= string::npos
)
1180 Transformed
= Transformed
.substr(0, pos
);
1183 if (Transformed
== ".")
1188 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1190 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1191 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1192 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1195 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1197 // This might become fatal one day
1198 // Status = StatAuthError;
1199 // ErrorText = "Conflicting distribution; expected "
1200 // + MetaIndexParser->GetExpectedDist() + " but got "
1201 // + MetaIndexParser->GetDist();
1203 if (!Transformed
.empty())
1205 _error
->Warning("Conflicting distribution: %s (expected %s but got %s)",
1206 Desc
.Description
.c_str(),
1207 Transformed
.c_str(),
1208 MetaIndexParser
->GetDist().c_str());
1215 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1216 // ---------------------------------------------------------------------
1218 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1220 if (AuthPass
== true)
1222 // gpgv method failed, if we have a good signature
1223 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists") +
1224 "partial/" + URItoFileName(RealURI
) + ".gpg.reverify";
1225 if(FileExists(LastGoodSigFile
))
1227 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1228 URItoFileName(RealURI
) + ".gpg";
1229 Rename(LastGoodSigFile
,VerifiedSigFile
);
1230 Status
= StatTransientNetworkError
;
1231 _error
->Warning(_("A error occurred during the signature "
1232 "verification. The repository is not updated "
1233 "and the previous index files will be used."
1234 "GPG error: %s: %s\n"),
1235 Desc
.Description
.c_str(),
1236 LookupTag(Message
,"Message").c_str());
1237 RunScripts("APT::Update::Auth-Failure");
1240 _error
->Warning(_("GPG error: %s: %s"),
1241 Desc
.Description
.c_str(),
1242 LookupTag(Message
,"Message").c_str());
1244 // gpgv method failed
1245 ReportMirrorFailure("GPGFailure");
1248 // No Release file was present, or verification failed, so fall
1249 // back to queueing Packages files without verification
1250 QueueIndexes(false);
1253 // AcqArchive::AcqArchive - Constructor /*{{{*/
1254 // ---------------------------------------------------------------------
1255 /* This just sets up the initial fetch environment and queues the first
1257 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1258 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1259 string
&StoreFilename
) :
1260 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1261 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1264 Retries
= _config
->FindI("Acquire::Retries",0);
1266 if (Version
.Arch() == 0)
1268 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1269 "This might mean you need to manually fix this package. "
1270 "(due to missing arch)"),
1271 Version
.ParentPkg().Name());
1275 /* We need to find a filename to determine the extension. We make the
1276 assumption here that all the available sources for this version share
1277 the same extension.. */
1278 // Skip not source sources, they do not have file fields.
1279 for (; Vf
.end() == false; Vf
++)
1281 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1286 // Does not really matter here.. we are going to fail out below
1287 if (Vf
.end() != true)
1289 // If this fails to get a file name we will bomb out below.
1290 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1291 if (_error
->PendingError() == true)
1294 // Generate the final file name as: package_version_arch.foo
1295 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1296 QuoteString(Version
.VerStr(),"_:") + '_' +
1297 QuoteString(Version
.Arch(),"_:.") +
1298 "." + flExtension(Parse
.FileName());
1301 // check if we have one trusted source for the package. if so, switch
1302 // to "TrustedOnly" mode
1303 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1305 pkgIndexFile
*Index
;
1306 if (Sources
->FindIndex(i
.File(),Index
) == false)
1308 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1310 std::cerr
<< "Checking index: " << Index
->Describe()
1311 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1313 if (Index
->IsTrusted()) {
1319 // "allow-unauthenticated" restores apts old fetching behaviour
1320 // that means that e.g. unauthenticated file:// uris are higher
1321 // priority than authenticated http:// uris
1322 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1326 if (QueueNext() == false && _error
->PendingError() == false)
1327 _error
->Error(_("I wasn't able to locate file for the %s package. "
1328 "This might mean you need to manually fix this package."),
1329 Version
.ParentPkg().Name());
1332 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1333 // ---------------------------------------------------------------------
1334 /* This queues the next available file version for download. It checks if
1335 the archive is already available in the cache and stashs the MD5 for
1337 bool pkgAcqArchive::QueueNext()
1339 for (; Vf
.end() == false; Vf
++)
1341 // Ignore not source sources
1342 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1345 // Try to cross match against the source list
1346 pkgIndexFile
*Index
;
1347 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1350 // only try to get a trusted package from another source if that source
1352 if(Trusted
&& !Index
->IsTrusted())
1355 // Grab the text package record
1356 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1357 if (_error
->PendingError() == true)
1360 string PkgFile
= Parse
.FileName();
1361 if(Parse
.SHA256Hash() != "")
1362 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1363 else if (Parse
.SHA1Hash() != "")
1364 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1366 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1367 if (PkgFile
.empty() == true)
1368 return _error
->Error(_("The package index files are corrupted. No Filename: "
1369 "field for package %s."),
1370 Version
.ParentPkg().Name());
1372 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1373 Desc
.Description
= Index
->ArchiveInfo(Version
);
1375 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1377 // See if we already have the file. (Legacy filenames)
1378 FileSize
= Version
->Size
;
1379 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1381 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1383 // Make sure the size matches
1384 if ((unsigned)Buf
.st_size
== Version
->Size
)
1389 StoreFilename
= DestFile
= FinalFile
;
1393 /* Hmm, we have a file and its size does not match, this means it is
1394 an old style mismatched arch */
1395 unlink(FinalFile
.c_str());
1398 // Check it again using the new style output filenames
1399 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1400 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1402 // Make sure the size matches
1403 if ((unsigned)Buf
.st_size
== Version
->Size
)
1408 StoreFilename
= DestFile
= FinalFile
;
1412 /* Hmm, we have a file and its size does not match, this shouldnt
1414 unlink(FinalFile
.c_str());
1417 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1419 // Check the destination file
1420 if (stat(DestFile
.c_str(),&Buf
) == 0)
1422 // Hmm, the partial file is too big, erase it
1423 if ((unsigned)Buf
.st_size
> Version
->Size
)
1424 unlink(DestFile
.c_str());
1426 PartialSize
= Buf
.st_size
;
1431 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1432 Desc
.Description
= Index
->ArchiveInfo(Version
);
1434 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1443 // AcqArchive::Done - Finished fetching /*{{{*/
1444 // ---------------------------------------------------------------------
1446 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string CalcHash
,
1447 pkgAcquire::MethodConfig
*Cfg
)
1449 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1452 if (Size
!= Version
->Size
)
1455 ErrorText
= _("Size mismatch");
1460 if(ExpectedHash
.toStr() != CalcHash
)
1463 ErrorText
= _("Hash Sum mismatch");
1464 if(FileExists(DestFile
))
1465 Rename(DestFile
,DestFile
+ ".FAILED");
1469 // Grab the output filename
1470 string FileName
= LookupTag(Message
,"Filename");
1471 if (FileName
.empty() == true)
1474 ErrorText
= "Method gave a blank filename";
1480 // Reference filename
1481 if (FileName
!= DestFile
)
1483 StoreFilename
= DestFile
= FileName
;
1488 // Done, move it into position
1489 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1490 FinalFile
+= flNotDir(StoreFilename
);
1491 Rename(DestFile
,FinalFile
);
1493 StoreFilename
= DestFile
= FinalFile
;
1497 // AcqArchive::Failed - Failure handler /*{{{*/
1498 // ---------------------------------------------------------------------
1499 /* Here we try other sources */
1500 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1502 ErrorText
= LookupTag(Message
,"Message");
1504 /* We don't really want to retry on failed media swaps, this prevents
1505 that. An interesting observation is that permanent failures are not
1507 if (Cnf
->Removable
== true &&
1508 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1510 // Vf = Version.FileList();
1511 while (Vf
.end() == false) Vf
++;
1512 StoreFilename
= string();
1513 Item::Failed(Message
,Cnf
);
1517 if (QueueNext() == false)
1519 // This is the retry counter
1521 Cnf
->LocalOnly
== false &&
1522 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1525 Vf
= Version
.FileList();
1526 if (QueueNext() == true)
1530 StoreFilename
= string();
1531 Item::Failed(Message
,Cnf
);
1535 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1536 // ---------------------------------------------------------------------
1537 bool pkgAcqArchive::IsTrusted()
1542 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1543 // ---------------------------------------------------------------------
1545 void pkgAcqArchive::Finished()
1547 if (Status
== pkgAcquire::Item::StatDone
&&
1550 StoreFilename
= string();
1553 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1554 // ---------------------------------------------------------------------
1555 /* The file is added to the queue */
1556 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1557 unsigned long Size
,string Dsc
,string ShortDesc
,
1558 const string
&DestDir
, const string
&DestFilename
) :
1559 Item(Owner
), ExpectedHash(Hash
)
1561 Retries
= _config
->FindI("Acquire::Retries",0);
1563 if(!DestFilename
.empty())
1564 DestFile
= DestFilename
;
1565 else if(!DestDir
.empty())
1566 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1568 DestFile
= flNotDir(URI
);
1572 Desc
.Description
= Dsc
;
1575 // Set the short description to the archive component
1576 Desc
.ShortDesc
= ShortDesc
;
1578 // Get the transfer sizes
1581 if (stat(DestFile
.c_str(),&Buf
) == 0)
1583 // Hmm, the partial file is too big, erase it
1584 if ((unsigned)Buf
.st_size
> Size
)
1585 unlink(DestFile
.c_str());
1587 PartialSize
= Buf
.st_size
;
1593 // AcqFile::Done - Item downloaded OK /*{{{*/
1594 // ---------------------------------------------------------------------
1596 void pkgAcqFile::Done(string Message
,unsigned long Size
,string CalcHash
,
1597 pkgAcquire::MethodConfig
*Cnf
)
1599 Item::Done(Message
,Size
,CalcHash
,Cnf
);
1602 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
1605 ErrorText
= "Hash Sum mismatch";
1606 Rename(DestFile
,DestFile
+ ".FAILED");
1610 string FileName
= LookupTag(Message
,"Filename");
1611 if (FileName
.empty() == true)
1614 ErrorText
= "Method gave a blank filename";
1620 // The files timestamp matches
1621 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1624 // We have to copy it into place
1625 if (FileName
!= DestFile
)
1628 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1629 Cnf
->Removable
== true)
1631 Desc
.URI
= "copy:" + FileName
;
1636 // Erase the file if it is a symlink so we can overwrite it
1638 if (lstat(DestFile
.c_str(),&St
) == 0)
1640 if (S_ISLNK(St
.st_mode
) != 0)
1641 unlink(DestFile
.c_str());
1645 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1647 ErrorText
= "Link to " + DestFile
+ " failure ";
1654 // AcqFile::Failed - Failure handler /*{{{*/
1655 // ---------------------------------------------------------------------
1656 /* Here we try other sources */
1657 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1659 ErrorText
= LookupTag(Message
,"Message");
1661 // This is the retry counter
1663 Cnf
->LocalOnly
== false &&
1664 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1671 Item::Failed(Message
,Cnf
);