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/sourcelist.h>
19 #include <apt-pkg/vendorlist.h>
20 #include <apt-pkg/error.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/fileutl.h>
23 #include <apt-pkg/md5.h>
24 #include <apt-pkg/sha1.h>
25 #include <apt-pkg/tagfile.h>
39 // Acquire::Item::Item - Constructor /*{{{*/
40 // ---------------------------------------------------------------------
42 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
43 PartialSize(0), Mode(0), ID(0), Complete(false),
44 Local(false), QueueCounter(0)
50 // Acquire::Item::~Item - Destructor /*{{{*/
51 // ---------------------------------------------------------------------
53 pkgAcquire::Item::~Item()
58 // Acquire::Item::Failed - Item failed to download /*{{{*/
59 // ---------------------------------------------------------------------
60 /* We return to an idle state if there are still other queues that could
62 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
65 ErrorText
= LookupTag(Message
,"Message");
66 UsedMirror
= LookupTag(Message
,"UsedMirror");
67 if (QueueCounter
<= 1)
69 /* This indicates that the file is not available right now but might
70 be sometime later. If we do a retry cycle then this should be
72 if (Cnf
->LocalOnly
== true &&
73 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
84 // report mirror failure back to LP if we actually use a mirror
85 string FailReason
= LookupTag(Message
, "FailReason");
86 if(FailReason
.size() != 0)
87 ReportMirrorFailure(FailReason
);
89 ReportMirrorFailure(ErrorText
);
92 // Acquire::Item::Start - Item has begun to download /*{{{*/
93 // ---------------------------------------------------------------------
94 /* Stash status and the file size. Note that setting Complete means
95 sub-phases of the acquire process such as decompresion are operating */
96 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long Size
)
98 Status
= StatFetching
;
99 if (FileSize
== 0 && Complete
== false)
103 // Acquire::Item::Done - Item downloaded OK /*{{{*/
104 // ---------------------------------------------------------------------
106 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string Hash
,
107 pkgAcquire::MethodConfig
*Cnf
)
109 // We just downloaded something..
110 string FileName
= LookupTag(Message
,"Filename");
111 UsedMirror
= LookupTag(Message
,"UsedMirror");
112 if (Complete
== false && !Local
&& FileName
== DestFile
)
115 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
121 ErrorText
= string();
122 Owner
->Dequeue(this);
125 // Acquire::Item::Rename - Rename a file /*{{{*/
126 // ---------------------------------------------------------------------
127 /* This helper function is used by alot of item methods as thier final
129 void pkgAcquire::Item::Rename(string From
,string To
)
131 if (rename(From
.c_str(),To
.c_str()) != 0)
134 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
135 From
.c_str(),To
.c_str());
142 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
144 // we only act if a mirror was used at all
145 if(UsedMirror
.empty())
148 std::cerr
<< "\nReportMirrorFailure: "
150 << " Uri: " << DescURI()
152 << FailCode
<< std::endl
;
154 const char *Args
[40];
156 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
157 "/usr/lib/apt/apt-report-mirror-failure");
158 if(!FileExists(report
))
160 Args
[i
++] = report
.c_str();
161 Args
[i
++] = UsedMirror
.c_str();
162 Args
[i
++] = DescURI().c_str();
163 Args
[i
++] = FailCode
.c_str();
165 pid_t pid
= ExecFork();
168 _error
->Error("ReportMirrorFailure Fork failed");
173 execvp(Args
[0], (char**)Args
);
174 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
177 if(!ExecWait(pid
, "report-mirror-failure"))
179 _error
->Warning("Couldn't report problem to '%s'",
180 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
184 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
185 // ---------------------------------------------------------------------
186 /* Get the DiffIndex file first and see if there are patches availabe
187 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
188 * patches. If anything goes wrong in that process, it will fall back to
189 * the original packages file
191 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
192 string URI
,string URIDesc
,string ShortDesc
,
193 HashString ExpectedHash
)
194 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
198 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
200 Desc
.Description
= URIDesc
+ "/DiffIndex";
202 Desc
.ShortDesc
= ShortDesc
;
203 Desc
.URI
= URI
+ ".diff/Index";
205 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
206 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
209 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
211 // look for the current package file
212 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
213 CurrentPackagesFile
+= URItoFileName(RealURI
);
215 // FIXME: this file:/ check is a hack to prevent fetching
216 // from local sources. this is really silly, and
217 // should be fixed cleanly as soon as possible
218 if(!FileExists(CurrentPackagesFile
) ||
219 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
221 // we don't have a pkg file or we don't want to queue
223 std::clog
<< "No index file, local or canceld by user" << std::endl
;
229 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
230 << CurrentPackagesFile
<< std::endl
;
236 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
237 // ---------------------------------------------------------------------
238 /* The only header we use is the last-modified header. */
239 string
pkgAcqDiffIndex::Custom600Headers()
241 string Final
= _config
->FindDir("Dir::State::lists");
242 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
245 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
248 if (stat(Final
.c_str(),&Buf
) != 0)
249 return "\nIndex-File: true";
251 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
254 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
257 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
262 vector
<DiffInfo
> available_patches
;
264 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
266 if (_error
->PendingError() == true)
269 if(TF
.Step(Tags
) == true)
276 string tmp
= Tags
.FindS("SHA1-Current");
277 std::stringstream
ss(tmp
);
280 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
282 SHA1
.AddFD(fd
.Fd(), fd
.Size());
283 local_sha1
= string(SHA1
.Result());
285 if(local_sha1
== ServerSha1
)
287 // we have the same sha1 as the server
289 std::clog
<< "Package file is up-to-date" << std::endl
;
290 // set found to true, this will queue a pkgAcqIndexDiffs with
291 // a empty availabe_patches
297 std::clog
<< "SHA1-Current: " << ServerSha1
<< std::endl
;
299 // check the historie and see what patches we need
300 string history
= Tags
.FindS("SHA1-History");
301 std::stringstream
hist(history
);
302 while(hist
>> d
.sha1
>> size
>> d
.file
)
304 d
.size
= atoi(size
.c_str());
305 // read until the first match is found
306 if(d
.sha1
== local_sha1
)
308 // from that point on, we probably need all diffs
312 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
313 available_patches
.push_back(d
);
318 // we have something, queue the next diff
322 string::size_type last_space
= Description
.rfind(" ");
323 if(last_space
!= string::npos
)
324 Description
.erase(last_space
, Description
.size()-last_space
);
325 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
326 ExpectedHash
, available_patches
);
334 // Nothing found, report and return false
335 // Failing here is ok, if we return false later, the full
336 // IndexFile is queued
338 std::clog
<< "Can't find a patch in the index file" << std::endl
;
342 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
345 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
346 << "Falling back to normal index file aquire" << std::endl
;
348 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
356 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
357 pkgAcquire::MethodConfig
*Cnf
)
360 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
362 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
365 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
367 // sucess in downloading the index
369 FinalFile
+= string(".IndexDiff");
371 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
373 Rename(DestFile
,FinalFile
);
374 chmod(FinalFile
.c_str(),0644);
375 DestFile
= FinalFile
;
377 if(!ParseDiffIndex(DestFile
))
378 return Failed("", NULL
);
386 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
387 // ---------------------------------------------------------------------
388 /* The package diff is added to the queue. one object is constructed
389 * for each diff and the index
391 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
392 string URI
,string URIDesc
,string ShortDesc
,
393 HashString ExpectedHash
,
394 vector
<DiffInfo
> diffs
)
395 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
396 available_patches(diffs
)
399 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
400 DestFile
+= URItoFileName(URI
);
402 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
404 Description
= URIDesc
;
406 Desc
.ShortDesc
= ShortDesc
;
408 if(available_patches
.size() == 0)
410 // we are done (yeah!)
416 State
= StateFetchDiff
;
421 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
424 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
425 << "Falling back to normal index file aquire" << std::endl
;
426 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
431 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
432 void pkgAcqIndexDiffs::Finish(bool allDone
)
434 // we restore the original name, this is required, otherwise
435 // the file will be cleaned
438 DestFile
= _config
->FindDir("Dir::State::lists");
439 DestFile
+= URItoFileName(RealURI
);
441 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
443 Status
= StatAuthError
;
444 ErrorText
= _("MD5Sum mismatch");
445 Rename(DestFile
,DestFile
+ ".FAILED");
450 // this is for the "real" finish
455 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
460 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
467 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
470 // calc sha1 of the just patched file
471 string FinalFile
= _config
->FindDir("Dir::State::lists");
472 FinalFile
+= URItoFileName(RealURI
);
474 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
476 SHA1
.AddFD(fd
.Fd(), fd
.Size());
477 string local_sha1
= string(SHA1
.Result());
479 std::clog
<< "QueueNextDiff: "
480 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
482 // remove all patches until the next matching patch is found
483 // this requires the Index file to be ordered
484 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
485 available_patches
.size() > 0 &&
486 I
!= available_patches
.end() &&
487 (*I
).sha1
!= local_sha1
;
490 available_patches
.erase(I
);
493 // error checking and falling back if no patch was found
494 if(available_patches
.size() == 0)
500 // queue the right diff
501 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
502 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
503 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
504 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
507 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
514 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
515 pkgAcquire::MethodConfig
*Cnf
)
518 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
520 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
523 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
525 // sucess in downloading a diff, enter ApplyDiff state
526 if(State
== StateFetchDiff
)
530 std::clog
<< "Sending to gzip method: " << FinalFile
<< std::endl
;
532 string FileName
= LookupTag(Message
,"Filename");
533 State
= StateUnzipDiff
;
535 Desc
.URI
= "gzip:" + FileName
;
536 DestFile
+= ".decomp";
542 // sucess in downloading a diff, enter ApplyDiff state
543 if(State
== StateUnzipDiff
)
546 // rred excepts the patch as $FinalFile.ed
547 Rename(DestFile
,FinalFile
+".ed");
550 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
552 State
= StateApplyDiff
;
554 Desc
.URI
= "rred:" + FinalFile
;
561 // success in download/apply a diff, queue next (if needed)
562 if(State
== StateApplyDiff
)
564 // remove the just applied patch
565 available_patches
.erase(available_patches
.begin());
570 std::clog
<< "Moving patched file in place: " << std::endl
571 << DestFile
<< " -> " << FinalFile
<< std::endl
;
573 Rename(DestFile
,FinalFile
);
574 chmod(FinalFile
.c_str(),0644);
576 // see if there is more to download
577 if(available_patches
.size() > 0) {
578 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
579 ExpectedHash
, available_patches
);
586 // AcqIndex::AcqIndex - Constructor /*{{{*/
587 // ---------------------------------------------------------------------
588 /* The package file is added to the queue and a second class is
589 instantiated to fetch the revision file */
590 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
591 string URI
,string URIDesc
,string ShortDesc
,
592 HashString ExpectedHash
, string comprExt
)
593 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
595 Decompression
= false;
598 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
599 DestFile
+= URItoFileName(URI
);
603 // autoselect the compression method
604 if(FileExists("/bin/bzip2"))
605 CompressionExtension
= ".bz2";
607 CompressionExtension
= ".gz";
609 CompressionExtension
= (comprExt
== "plain" ? "" : comprExt
);
611 Desc
.URI
= URI
+ CompressionExtension
;
613 Desc
.Description
= URIDesc
;
615 Desc
.ShortDesc
= ShortDesc
;
620 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
621 // ---------------------------------------------------------------------
622 /* The only header we use is the last-modified header. */
623 string
pkgAcqIndex::Custom600Headers()
625 string Final
= _config
->FindDir("Dir::State::lists");
626 Final
+= URItoFileName(RealURI
);
629 if (stat(Final
.c_str(),&Buf
) != 0)
630 return "\nIndex-File: true";
631 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
634 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
636 bool descChanged
= false;
637 // no .bz2 found, retry with .gz
638 if(Desc
.URI
.substr(Desc
.URI
.size()-3) == "bz2") {
639 Desc
.URI
= Desc
.URI
.substr(0,Desc
.URI
.size()-3) + "gz";
641 new pkgAcqIndex(Owner
, RealURI
, Desc
.Description
,Desc
.ShortDesc
,
642 ExpectedHash
, string(".gz"));
645 // no .gz found, retry with uncompressed
646 else if(Desc
.URI
.substr(Desc
.URI
.size()-2) == "gz") {
647 Desc
.URI
= Desc
.URI
.substr(0,Desc
.URI
.size()-2);
649 new pkgAcqIndex(Owner
, RealURI
, Desc
.Description
,Desc
.ShortDesc
,
650 ExpectedHash
, string("plain"));
660 // on decompression failure, remove bad versions in partial/
661 if(Decompression
&& Erase
) {
662 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
663 s
+= URItoFileName(RealURI
);
667 Item::Failed(Message
,Cnf
);
670 // AcqIndex::Done - Finished a fetch /*{{{*/
671 // ---------------------------------------------------------------------
672 /* This goes through a number of states.. On the initial fetch the
673 method could possibly return an alternate filename which points
674 to the uncompressed version of the file. If this is so the file
675 is copied into the partial directory. In all other cases the file
676 is decompressed with a gzip uri. */
677 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string Hash
,
678 pkgAcquire::MethodConfig
*Cfg
)
680 Item::Done(Message
,Size
,Hash
,Cfg
);
682 if (Decompression
== true)
684 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
686 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
687 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
690 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
692 Status
= StatAuthError
;
693 ErrorText
= _("Hash Sum mismatch");
694 Rename(DestFile
,DestFile
+ ".FAILED");
695 ReportMirrorFailure("HashChecksumFailure");
698 // Done, move it into position
699 string FinalFile
= _config
->FindDir("Dir::State::lists");
700 FinalFile
+= URItoFileName(RealURI
);
701 Rename(DestFile
,FinalFile
);
702 chmod(FinalFile
.c_str(),0644);
704 /* We restore the original name to DestFile so that the clean operation
706 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
707 DestFile
+= URItoFileName(RealURI
);
709 // Remove the compressed version.
711 unlink(DestFile
.c_str());
718 // Handle the unzipd case
719 string FileName
= LookupTag(Message
,"Alt-Filename");
720 if (FileName
.empty() == false)
722 // The files timestamp matches
723 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
725 Decompression
= true;
727 DestFile
+= ".decomp";
728 Desc
.URI
= "copy:" + FileName
;
734 FileName
= LookupTag(Message
,"Filename");
735 if (FileName
.empty() == true)
738 ErrorText
= "Method gave a blank filename";
741 // The files timestamp matches
742 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
745 if (FileName
== DestFile
)
750 string compExt
= flExtension(flNotDir(URI(Desc
.URI
).Path
));
751 const char *decompProg
;
753 decompProg
= "bzip2";
754 else if(compExt
== "gz")
756 // flExtensions returns the full name if no extension is found
757 // this is why we have this complicated compare operation here
758 // FIMXE: add a new flJustExtension() that return "" if no
759 // extension is found and use that above so that it can
760 // be tested against ""
761 else if(compExt
== flNotDir(URI(Desc
.URI
).Path
))
764 _error
->Error("Unsupported extension: %s", compExt
.c_str());
768 Decompression
= true;
769 DestFile
+= ".decomp";
770 Desc
.URI
= string(decompProg
) + ":" + FileName
;
775 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
776 // ---------------------------------------------------------------------
777 /* The Translation file is added to the queue */
778 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
779 string URI
,string URIDesc
,string ShortDesc
)
780 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
784 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
785 // ---------------------------------------------------------------------
787 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
789 if (Cnf
->LocalOnly
== true ||
790 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
799 Item::Failed(Message
,Cnf
);
802 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
803 string URI
,string URIDesc
,string ShortDesc
,
804 string MetaIndexURI
, string MetaIndexURIDesc
,
805 string MetaIndexShortDesc
,
806 const vector
<IndexTarget
*>* IndexTargets
,
807 indexRecords
* MetaIndexParser
) :
808 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
809 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
810 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
812 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
813 DestFile
+= URItoFileName(URI
);
815 // remove any partial downloaded sig-file in partial/.
816 // it may confuse proxies and is too small to warrant a
817 // partial download anyway
818 unlink(DestFile
.c_str());
821 Desc
.Description
= URIDesc
;
823 Desc
.ShortDesc
= ShortDesc
;
826 string Final
= _config
->FindDir("Dir::State::lists");
827 Final
+= URItoFileName(RealURI
);
829 if (stat(Final
.c_str(),&Buf
) == 0)
831 // File was already in place. It needs to be re-downloaded/verified
832 // because Release might have changed, we do give it a differnt
833 // name than DestFile because otherwise the http method will
834 // send If-Range requests and there are too many broken servers
835 // out there that do not understand them
836 LastGoodSig
= DestFile
+".reverify";
837 Rename(Final
,LastGoodSig
);
843 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
844 // ---------------------------------------------------------------------
845 /* The only header we use is the last-modified header. */
846 string
pkgAcqMetaSig::Custom600Headers()
849 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
850 return "\nIndex-File: true";
852 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
855 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
856 pkgAcquire::MethodConfig
*Cfg
)
858 Item::Done(Message
,Size
,MD5
,Cfg
);
860 string FileName
= LookupTag(Message
,"Filename");
861 if (FileName
.empty() == true)
864 ErrorText
= "Method gave a blank filename";
868 if (FileName
!= DestFile
)
870 // We have to copy it into place
872 Desc
.URI
= "copy:" + FileName
;
879 // put the last known good file back on i-m-s hit (it will
880 // be re-verified again)
881 // Else do nothing, we have the new file in DestFile then
882 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
883 Rename(LastGoodSig
, DestFile
);
885 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
886 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
887 MetaIndexShortDesc
, DestFile
, IndexTargets
,
892 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
894 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
896 // if we get a network error we fail gracefully
897 if(Status
== StatTransientNetworkError
)
899 Item::Failed(Message
,Cnf
);
900 // move the sigfile back on transient network failures
901 if(FileExists(LastGoodSig
))
902 Rename(LastGoodSig
,Final
);
904 // set the status back to , Item::Failed likes to reset it
905 Status
= pkgAcquire::Item::StatTransientNetworkError
;
909 // Delete any existing sigfile when the acquire failed
910 unlink(Final
.c_str());
912 // queue a pkgAcqMetaIndex with no sigfile
913 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
914 "", IndexTargets
, MetaIndexParser
);
916 if (Cnf
->LocalOnly
== true ||
917 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
926 Item::Failed(Message
,Cnf
);
929 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
930 string URI
,string URIDesc
,string ShortDesc
,
932 const vector
<struct IndexTarget
*>* IndexTargets
,
933 indexRecords
* MetaIndexParser
) :
934 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
935 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
937 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
938 DestFile
+= URItoFileName(URI
);
941 Desc
.Description
= URIDesc
;
943 Desc
.ShortDesc
= ShortDesc
;
949 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
950 // ---------------------------------------------------------------------
951 /* The only header we use is the last-modified header. */
952 string
pkgAcqMetaIndex::Custom600Headers()
954 string Final
= _config
->FindDir("Dir::State::lists");
955 Final
+= URItoFileName(RealURI
);
958 if (stat(Final
.c_str(),&Buf
) != 0)
959 return "\nIndex-File: true";
961 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
964 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string Hash
, /*{{{*/
965 pkgAcquire::MethodConfig
*Cfg
)
967 Item::Done(Message
,Size
,Hash
,Cfg
);
969 // MetaIndexes are done in two passes: one to download the
970 // metaindex with an appropriate method, and a second to verify it
971 // with the gpgv method
973 if (AuthPass
== true)
977 // all cool, move Release file into place
980 string FinalFile
= _config
->FindDir("Dir::State::lists");
981 FinalFile
+= URItoFileName(RealURI
);
982 Rename(DestFile
,FinalFile
);
983 chmod(FinalFile
.c_str(),0644);
984 DestFile
= FinalFile
;
988 RetrievalDone(Message
);
990 // Still more retrieving to do
995 // There was no signature file, so we are finished. Download
996 // the indexes without verification.
1001 // There was a signature file, so pass it to gpgv for
1004 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1005 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1006 << SigFile
<< "," << DestFile
<< ")\n";
1008 Desc
.URI
= "gpgv:" + SigFile
;
1015 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1017 // We have just finished downloading a Release file (it is not
1020 string FileName
= LookupTag(Message
,"Filename");
1021 if (FileName
.empty() == true)
1024 ErrorText
= "Method gave a blank filename";
1028 if (FileName
!= DestFile
)
1031 Desc
.URI
= "copy:" + FileName
;
1036 // make sure to verify against the right file on I-M-S hit
1037 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1040 string FinalFile
= _config
->FindDir("Dir::State::lists");
1041 FinalFile
+= URItoFileName(RealURI
);
1042 DestFile
= FinalFile
;
1047 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1049 // At this point, the gpgv method has succeeded, so there is a
1050 // valid signature from a key in the trusted keyring. We
1051 // perform additional verification of its contents, and use them
1052 // to verify the indexes we are about to download
1054 if (!MetaIndexParser
->Load(DestFile
))
1056 Status
= StatAuthError
;
1057 ErrorText
= MetaIndexParser
->ErrorText
;
1061 if (!VerifyVendor(Message
))
1066 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1067 std::cerr
<< "Signature verification succeeded: "
1068 << DestFile
<< std::endl
;
1070 // Download further indexes with verification
1073 // Done, move signature file into position
1074 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1075 URItoFileName(RealURI
) + ".gpg";
1076 Rename(SigFile
,VerifiedSigFile
);
1077 chmod(VerifiedSigFile
.c_str(),0644);
1080 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1082 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1083 Target
!= IndexTargets
->end();
1086 HashString ExpectedIndexHash
;
1089 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1092 Status
= StatAuthError
;
1093 ErrorText
= "Unable to find expected entry "
1094 + (*Target
)->MetaKey
+ " in Meta-index file (malformed Release file?)";
1097 ExpectedIndexHash
= Record
->Hash
;
1098 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1100 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1101 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1103 if (ExpectedIndexHash
.empty())
1105 Status
= StatAuthError
;
1106 ErrorText
= "Unable to find hash sum for "
1107 + (*Target
)->MetaKey
+ " in Meta-index file";
1112 // Queue Packages file (either diff or full packages files, depending
1113 // on the users option)
1114 if(_config
->FindB("Acquire::PDiffs",false) == true)
1115 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1116 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1118 new pkgAcqIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1119 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1123 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1125 // // Maybe this should be made available from above so we don't have
1126 // // to read and parse it every time?
1127 // pkgVendorList List;
1128 // List.ReadMainList();
1130 // const Vendor* Vndr = NULL;
1131 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1133 // string::size_type pos = (*I).find("VALIDSIG ");
1134 // if (_config->FindB("Debug::Vendor", false))
1135 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1137 // if (pos != std::string::npos)
1139 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1140 // if (_config->FindB("Debug::Vendor", false))
1141 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1143 // Vndr = List.FindVendor(Fingerprint) != "";
1144 // if (Vndr != NULL);
1148 string::size_type pos
;
1150 // check for missing sigs (that where not fatal because otherwise we had
1153 string msg
= _("There is no public key available for the "
1154 "following key IDs:\n");
1155 pos
= Message
.find("NO_PUBKEY ");
1156 if (pos
!= std::string::npos
)
1158 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1159 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1160 missingkeys
+= (Fingerprint
);
1162 if(!missingkeys
.empty())
1163 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1165 string Transformed
= MetaIndexParser
->GetExpectedDist();
1167 if (Transformed
== "../project/experimental")
1169 Transformed
= "experimental";
1172 pos
= Transformed
.rfind('/');
1173 if (pos
!= string::npos
)
1175 Transformed
= Transformed
.substr(0, pos
);
1178 if (Transformed
== ".")
1183 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1185 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1186 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1187 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1190 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1192 // This might become fatal one day
1193 // Status = StatAuthError;
1194 // ErrorText = "Conflicting distribution; expected "
1195 // + MetaIndexParser->GetExpectedDist() + " but got "
1196 // + MetaIndexParser->GetDist();
1198 if (!Transformed
.empty())
1200 _error
->Warning("Conflicting distribution: %s (expected %s but got %s)",
1201 Desc
.Description
.c_str(),
1202 Transformed
.c_str(),
1203 MetaIndexParser
->GetDist().c_str());
1210 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1211 // ---------------------------------------------------------------------
1213 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1215 if (AuthPass
== true)
1217 // gpgv method failed, if we have a good signature
1218 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists") +
1219 "partial/" + URItoFileName(RealURI
) + ".gpg.reverify";
1220 if(FileExists(LastGoodSigFile
))
1222 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1223 URItoFileName(RealURI
) + ".gpg";
1224 Rename(LastGoodSigFile
,VerifiedSigFile
);
1225 Status
= StatTransientNetworkError
;
1226 _error
->Warning(_("A error occurred during the signature "
1227 "verification. The repository is not updated "
1228 "and the previous index files will be used."
1229 "GPG error: %s: %s\n"),
1230 Desc
.Description
.c_str(),
1231 LookupTag(Message
,"Message").c_str());
1232 RunScripts("APT::Update::Auth-Failure");
1235 _error
->Warning(_("GPG error: %s: %s"),
1236 Desc
.Description
.c_str(),
1237 LookupTag(Message
,"Message").c_str());
1239 // gpgv method failed
1240 ReportMirrorFailure("GPGFailure");
1243 // No Release file was present, or verification failed, so fall
1244 // back to queueing Packages files without verification
1245 QueueIndexes(false);
1248 // AcqArchive::AcqArchive - Constructor /*{{{*/
1249 // ---------------------------------------------------------------------
1250 /* This just sets up the initial fetch environment and queues the first
1252 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1253 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1254 string
&StoreFilename
) :
1255 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1256 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1259 Retries
= _config
->FindI("Acquire::Retries",0);
1261 if (Version
.Arch() == 0)
1263 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1264 "This might mean you need to manually fix this package. "
1265 "(due to missing arch)"),
1266 Version
.ParentPkg().Name());
1270 /* We need to find a filename to determine the extension. We make the
1271 assumption here that all the available sources for this version share
1272 the same extension.. */
1273 // Skip not source sources, they do not have file fields.
1274 for (; Vf
.end() == false; Vf
++)
1276 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1281 // Does not really matter here.. we are going to fail out below
1282 if (Vf
.end() != true)
1284 // If this fails to get a file name we will bomb out below.
1285 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1286 if (_error
->PendingError() == true)
1289 // Generate the final file name as: package_version_arch.foo
1290 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1291 QuoteString(Version
.VerStr(),"_:") + '_' +
1292 QuoteString(Version
.Arch(),"_:.") +
1293 "." + flExtension(Parse
.FileName());
1296 // check if we have one trusted source for the package. if so, switch
1297 // to "TrustedOnly" mode
1298 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1300 pkgIndexFile
*Index
;
1301 if (Sources
->FindIndex(i
.File(),Index
) == false)
1303 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1305 std::cerr
<< "Checking index: " << Index
->Describe()
1306 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1308 if (Index
->IsTrusted()) {
1314 // "allow-unauthenticated" restores apts old fetching behaviour
1315 // that means that e.g. unauthenticated file:// uris are higher
1316 // priority than authenticated http:// uris
1317 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1321 if (QueueNext() == false && _error
->PendingError() == false)
1322 _error
->Error(_("I wasn't able to locate file for the %s package. "
1323 "This might mean you need to manually fix this package."),
1324 Version
.ParentPkg().Name());
1327 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1328 // ---------------------------------------------------------------------
1329 /* This queues the next available file version for download. It checks if
1330 the archive is already available in the cache and stashs the MD5 for
1332 bool pkgAcqArchive::QueueNext()
1334 for (; Vf
.end() == false; Vf
++)
1336 // Ignore not source sources
1337 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1340 // Try to cross match against the source list
1341 pkgIndexFile
*Index
;
1342 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1345 // only try to get a trusted package from another source if that source
1347 if(Trusted
&& !Index
->IsTrusted())
1350 // Grab the text package record
1351 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1352 if (_error
->PendingError() == true)
1355 string PkgFile
= Parse
.FileName();
1356 if(Parse
.SHA256Hash() != "")
1357 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1358 else if (Parse
.SHA1Hash() != "")
1359 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1361 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1362 if (PkgFile
.empty() == true)
1363 return _error
->Error(_("The package index files are corrupted. No Filename: "
1364 "field for package %s."),
1365 Version
.ParentPkg().Name());
1367 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1368 Desc
.Description
= Index
->ArchiveInfo(Version
);
1370 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1372 // See if we already have the file. (Legacy filenames)
1373 FileSize
= Version
->Size
;
1374 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1376 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1378 // Make sure the size matches
1379 if ((unsigned)Buf
.st_size
== Version
->Size
)
1384 StoreFilename
= DestFile
= FinalFile
;
1388 /* Hmm, we have a file and its size does not match, this means it is
1389 an old style mismatched arch */
1390 unlink(FinalFile
.c_str());
1393 // Check it again using the new style output filenames
1394 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1395 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1397 // Make sure the size matches
1398 if ((unsigned)Buf
.st_size
== Version
->Size
)
1403 StoreFilename
= DestFile
= FinalFile
;
1407 /* Hmm, we have a file and its size does not match, this shouldnt
1409 unlink(FinalFile
.c_str());
1412 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1414 // Check the destination file
1415 if (stat(DestFile
.c_str(),&Buf
) == 0)
1417 // Hmm, the partial file is too big, erase it
1418 if ((unsigned)Buf
.st_size
> Version
->Size
)
1419 unlink(DestFile
.c_str());
1421 PartialSize
= Buf
.st_size
;
1426 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1427 Desc
.Description
= Index
->ArchiveInfo(Version
);
1429 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1438 // AcqArchive::Done - Finished fetching /*{{{*/
1439 // ---------------------------------------------------------------------
1441 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string CalcHash
,
1442 pkgAcquire::MethodConfig
*Cfg
)
1444 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1447 if (Size
!= Version
->Size
)
1450 ErrorText
= _("Size mismatch");
1455 if(ExpectedHash
.toStr() != CalcHash
)
1458 ErrorText
= _("Hash Sum mismatch");
1459 if(FileExists(DestFile
))
1460 Rename(DestFile
,DestFile
+ ".FAILED");
1464 // Grab the output filename
1465 string FileName
= LookupTag(Message
,"Filename");
1466 if (FileName
.empty() == true)
1469 ErrorText
= "Method gave a blank filename";
1475 // Reference filename
1476 if (FileName
!= DestFile
)
1478 StoreFilename
= DestFile
= FileName
;
1483 // Done, move it into position
1484 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1485 FinalFile
+= flNotDir(StoreFilename
);
1486 Rename(DestFile
,FinalFile
);
1488 StoreFilename
= DestFile
= FinalFile
;
1492 // AcqArchive::Failed - Failure handler /*{{{*/
1493 // ---------------------------------------------------------------------
1494 /* Here we try other sources */
1495 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1497 ErrorText
= LookupTag(Message
,"Message");
1499 /* We don't really want to retry on failed media swaps, this prevents
1500 that. An interesting observation is that permanent failures are not
1502 if (Cnf
->Removable
== true &&
1503 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1505 // Vf = Version.FileList();
1506 while (Vf
.end() == false) Vf
++;
1507 StoreFilename
= string();
1508 Item::Failed(Message
,Cnf
);
1512 if (QueueNext() == false)
1514 // This is the retry counter
1516 Cnf
->LocalOnly
== false &&
1517 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1520 Vf
= Version
.FileList();
1521 if (QueueNext() == true)
1525 StoreFilename
= string();
1526 Item::Failed(Message
,Cnf
);
1530 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1531 // ---------------------------------------------------------------------
1532 bool pkgAcqArchive::IsTrusted()
1537 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1538 // ---------------------------------------------------------------------
1540 void pkgAcqArchive::Finished()
1542 if (Status
== pkgAcquire::Item::StatDone
&&
1545 StoreFilename
= string();
1548 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1549 // ---------------------------------------------------------------------
1550 /* The file is added to the queue */
1551 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1552 unsigned long Size
,string Dsc
,string ShortDesc
,
1553 const string
&DestDir
, const string
&DestFilename
) :
1554 Item(Owner
), ExpectedHash(Hash
)
1556 Retries
= _config
->FindI("Acquire::Retries",0);
1558 if(!DestFilename
.empty())
1559 DestFile
= DestFilename
;
1560 else if(!DestDir
.empty())
1561 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1563 DestFile
= flNotDir(URI
);
1567 Desc
.Description
= Dsc
;
1570 // Set the short description to the archive component
1571 Desc
.ShortDesc
= ShortDesc
;
1573 // Get the transfer sizes
1576 if (stat(DestFile
.c_str(),&Buf
) == 0)
1578 // Hmm, the partial file is too big, erase it
1579 if ((unsigned)Buf
.st_size
> Size
)
1580 unlink(DestFile
.c_str());
1582 PartialSize
= Buf
.st_size
;
1588 // AcqFile::Done - Item downloaded OK /*{{{*/
1589 // ---------------------------------------------------------------------
1591 void pkgAcqFile::Done(string Message
,unsigned long Size
,string CalcHash
,
1592 pkgAcquire::MethodConfig
*Cnf
)
1594 Item::Done(Message
,Size
,CalcHash
,Cnf
);
1597 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
1600 ErrorText
= "Hash Sum mismatch";
1601 Rename(DestFile
,DestFile
+ ".FAILED");
1605 string FileName
= LookupTag(Message
,"Filename");
1606 if (FileName
.empty() == true)
1609 ErrorText
= "Method gave a blank filename";
1615 // The files timestamp matches
1616 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1619 // We have to copy it into place
1620 if (FileName
!= DestFile
)
1623 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1624 Cnf
->Removable
== true)
1626 Desc
.URI
= "copy:" + FileName
;
1631 // Erase the file if it is a symlink so we can overwrite it
1633 if (lstat(DestFile
.c_str(),&St
) == 0)
1635 if (S_ISLNK(St
.st_mode
) != 0)
1636 unlink(DestFile
.c_str());
1640 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1642 ErrorText
= "Link to " + DestFile
+ " failure ";
1649 // AcqFile::Failed - Failure handler /*{{{*/
1650 // ---------------------------------------------------------------------
1651 /* Here we try other sources */
1652 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1654 ErrorText
= LookupTag(Message
,"Message");
1656 // This is the retry counter
1658 Cnf
->LocalOnly
== false &&
1659 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1666 Item::Failed(Message
,Cnf
);