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
,
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());
186 // AcqDiffIndex::AcqDiffIndex - Constructor
187 // ---------------------------------------------------------------------
188 /* Get the DiffIndex file first and see if there are patches availabe
189 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
190 * patches. If anything goes wrong in that process, it will fall back to
191 * the original packages file
193 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
194 string URI
,string URIDesc
,string ShortDesc
,
196 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
), Description(URIDesc
)
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
);
256 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
)
259 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
264 vector
<DiffInfo
> available_patches
;
266 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
268 if (_error
->PendingError() == true)
271 if(TF
.Step(Tags
) == true)
278 string tmp
= Tags
.FindS("SHA1-Current");
279 std::stringstream
ss(tmp
);
282 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
284 SHA1
.AddFD(fd
.Fd(), fd
.Size());
285 local_sha1
= string(SHA1
.Result());
287 if(local_sha1
== ServerSha1
)
289 // we have the same sha1 as the server
291 std::clog
<< "Package file is up-to-date" << std::endl
;
292 // set found to true, this will queue a pkgAcqIndexDiffs with
293 // a empty availabe_patches
299 std::clog
<< "SHA1-Current: " << ServerSha1
<< std::endl
;
301 // check the historie and see what patches we need
302 string history
= Tags
.FindS("SHA1-History");
303 std::stringstream
hist(history
);
304 while(hist
>> d
.sha1
>> size
>> d
.file
)
306 d
.size
= atoi(size
.c_str());
307 // read until the first match is found
308 if(d
.sha1
== local_sha1
)
310 // from that point on, we probably need all diffs
314 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
315 available_patches
.push_back(d
);
320 // we have something, queue the next diff
324 unsigned int last_space
= Description
.rfind(" ");
325 if(last_space
!= string::npos
)
326 Description
.erase(last_space
, Description
.size()-last_space
);
327 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
328 ExpectedMD5
, available_patches
);
336 // Nothing found, report and return false
337 // Failing here is ok, if we return false later, the full
338 // IndexFile is queued
340 std::clog
<< "Can't find a patch in the index file" << std::endl
;
344 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
347 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
348 << "Falling back to normal index file aquire" << std::endl
;
350 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
358 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
,
359 pkgAcquire::MethodConfig
*Cnf
)
362 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
364 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
367 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
369 // sucess in downloading the index
371 FinalFile
+= string(".IndexDiff");
373 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
375 Rename(DestFile
,FinalFile
);
376 chmod(FinalFile
.c_str(),0644);
377 DestFile
= FinalFile
;
379 if(!ParseDiffIndex(DestFile
))
380 return Failed("", NULL
);
390 // AcqIndexDiffs::AcqIndexDiffs - Constructor
391 // ---------------------------------------------------------------------
392 /* The package diff is added to the queue. one object is constructed
393 * for each diff and the index
395 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
396 string URI
,string URIDesc
,string ShortDesc
,
397 string ExpectedMD5
, vector
<DiffInfo
> diffs
)
398 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
),
399 available_patches(diffs
)
402 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
403 DestFile
+= URItoFileName(URI
);
405 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
407 Description
= URIDesc
;
409 Desc
.ShortDesc
= ShortDesc
;
411 if(available_patches
.size() == 0)
413 // we are done (yeah!)
419 State
= StateFetchDiff
;
425 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
428 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
429 << "Falling back to normal index file aquire" << std::endl
;
430 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
436 // helper that cleans the item out of the fetcher queue
437 void pkgAcqIndexDiffs::Finish(bool allDone
)
439 // we restore the original name, this is required, otherwise
440 // the file will be cleaned
443 DestFile
= _config
->FindDir("Dir::State::lists");
444 DestFile
+= URItoFileName(RealURI
);
446 // do the final md5sum checking
448 FileFd
Fd(DestFile
, FileFd::ReadOnly
);
449 sum
.AddFD(Fd
.Fd(), Fd
.Size());
451 string MD5
= (string
)sum
.Result();
453 if (!ExpectedMD5
.empty() && MD5
!= ExpectedMD5
)
455 Status
= StatAuthError
;
456 ErrorText
= _("MD5Sum mismatch");
457 Rename(DestFile
,DestFile
+ ".FAILED");
462 // this is for the "real" finish
467 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
472 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
481 bool pkgAcqIndexDiffs::QueueNextDiff()
484 // calc sha1 of the just patched file
485 string FinalFile
= _config
->FindDir("Dir::State::lists");
486 FinalFile
+= URItoFileName(RealURI
);
488 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
490 SHA1
.AddFD(fd
.Fd(), fd
.Size());
491 string local_sha1
= string(SHA1
.Result());
493 std::clog
<< "QueueNextDiff: "
494 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
496 // remove all patches until the next matching patch is found
497 // this requires the Index file to be ordered
498 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
499 available_patches
.size() > 0 &&
500 I
!= available_patches
.end() &&
501 (*I
).sha1
!= local_sha1
;
504 available_patches
.erase(I
);
507 // error checking and falling back if no patch was found
508 if(available_patches
.size() == 0)
514 // queue the right diff
515 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
516 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
517 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
518 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
521 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
530 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
,
531 pkgAcquire::MethodConfig
*Cnf
)
534 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
536 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
539 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
541 // sucess in downloading a diff, enter ApplyDiff state
542 if(State
== StateFetchDiff
)
546 std::clog
<< "Sending to gzip method: " << FinalFile
<< std::endl
;
548 string FileName
= LookupTag(Message
,"Filename");
549 State
= StateUnzipDiff
;
551 Desc
.URI
= "gzip:" + FileName
;
552 DestFile
+= ".decomp";
558 // sucess in downloading a diff, enter ApplyDiff state
559 if(State
== StateUnzipDiff
)
562 // rred excepts the patch as $FinalFile.ed
563 Rename(DestFile
,FinalFile
+".ed");
566 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
568 State
= StateApplyDiff
;
570 Desc
.URI
= "rred:" + FinalFile
;
577 // success in download/apply a diff, queue next (if needed)
578 if(State
== StateApplyDiff
)
580 // remove the just applied patch
581 available_patches
.erase(available_patches
.begin());
586 std::clog
<< "Moving patched file in place: " << std::endl
587 << DestFile
<< " -> " << FinalFile
<< std::endl
;
589 Rename(DestFile
,FinalFile
);
590 chmod(FinalFile
.c_str(),0644);
592 // see if there is more to download
593 if(available_patches
.size() > 0) {
594 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
595 ExpectedMD5
, available_patches
);
603 // AcqIndex::AcqIndex - Constructor /*{{{*/
604 // ---------------------------------------------------------------------
605 /* The package file is added to the queue and a second class is
606 instantiated to fetch the revision file */
607 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
608 string URI
,string URIDesc
,string ShortDesc
,
609 string ExpectedMD5
, string comprExt
)
610 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
)
612 Decompression
= false;
615 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
616 DestFile
+= URItoFileName(URI
);
620 // autoselect the compression method
621 if(FileExists("/bin/bzip2"))
622 CompressionExtension
= ".bz2";
624 CompressionExtension
= ".gz";
626 CompressionExtension
= comprExt
;
628 Desc
.URI
= URI
+ CompressionExtension
;
630 Desc
.Description
= URIDesc
;
632 Desc
.ShortDesc
= ShortDesc
;
637 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
638 // ---------------------------------------------------------------------
639 /* The only header we use is the last-modified header. */
640 string
pkgAcqIndex::Custom600Headers()
642 string Final
= _config
->FindDir("Dir::State::lists");
643 Final
+= URItoFileName(RealURI
);
646 if (stat(Final
.c_str(),&Buf
) != 0)
647 return "\nIndex-File: true";
648 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
652 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
654 // no .bz2 found, retry with .gz
655 if(Desc
.URI
.substr(Desc
.URI
.size()-3) == "bz2") {
656 Desc
.URI
= Desc
.URI
.substr(0,Desc
.URI
.size()-3) + "gz";
658 // retry with a gzip one
659 new pkgAcqIndex(Owner
, RealURI
, Desc
.Description
,Desc
.ShortDesc
,
660 ExpectedMD5
, string(".gz"));
667 // on decompression failure, remove bad versions in partial/
668 if(Decompression
&& Erase
) {
669 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
670 s
+= URItoFileName(RealURI
);
674 Item::Failed(Message
,Cnf
);
678 // AcqIndex::Done - Finished a fetch /*{{{*/
679 // ---------------------------------------------------------------------
680 /* This goes through a number of states.. On the initial fetch the
681 method could possibly return an alternate filename which points
682 to the uncompressed version of the file. If this is so the file
683 is copied into the partial directory. In all other cases the file
684 is decompressed with a gzip uri. */
685 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
,
686 pkgAcquire::MethodConfig
*Cfg
)
688 Item::Done(Message
,Size
,MD5
,Cfg
);
690 if (Decompression
== true)
692 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
694 std::cerr
<< std::endl
<< RealURI
<< ": Computed MD5: " << MD5
;
695 std::cerr
<< " Expected MD5: " << ExpectedMD5
<< std::endl
;
701 FileFd
Fd(DestFile
, FileFd::ReadOnly
);
702 sum
.AddFD(Fd
.Fd(), Fd
.Size());
704 MD5
= (string
)sum
.Result();
707 if (!ExpectedMD5
.empty() && MD5
!= ExpectedMD5
)
709 Status
= StatAuthError
;
710 ErrorText
= _("MD5Sum mismatch");
711 Rename(DestFile
,DestFile
+ ".FAILED");
712 ReportMirrorFailure("HashChecksumFailure");
715 // Done, move it into position
716 string FinalFile
= _config
->FindDir("Dir::State::lists");
717 FinalFile
+= URItoFileName(RealURI
);
718 Rename(DestFile
,FinalFile
);
719 chmod(FinalFile
.c_str(),0644);
721 /* We restore the original name to DestFile so that the clean operation
723 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
724 DestFile
+= URItoFileName(RealURI
);
726 // Remove the compressed version.
728 unlink(DestFile
.c_str());
735 // Handle the unzipd case
736 string FileName
= LookupTag(Message
,"Alt-Filename");
737 if (FileName
.empty() == false)
739 // The files timestamp matches
740 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
743 Decompression
= true;
745 DestFile
+= ".decomp";
746 Desc
.URI
= "copy:" + FileName
;
752 FileName
= LookupTag(Message
,"Filename");
753 if (FileName
.empty() == true)
756 ErrorText
= "Method gave a blank filename";
759 // The files timestamp matches
760 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
763 if (FileName
== DestFile
)
768 string compExt
= Desc
.URI
.substr(Desc
.URI
.size()-3);
771 decompProg
= "bzip2";
772 else if(compExt
== ".gz")
775 _error
->Error("Unsupported extension: %s", compExt
.c_str());
779 Decompression
= true;
780 DestFile
+= ".decomp";
781 Desc
.URI
= string(decompProg
) + ":" + FileName
;
786 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
787 // ---------------------------------------------------------------------
788 /* The Translation file is added to the queue */
789 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
790 string URI
,string URIDesc
,string ShortDesc
) :
791 pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", "")
796 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
797 // ---------------------------------------------------------------------
799 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
801 if (Cnf
->LocalOnly
== true ||
802 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
811 Item::Failed(Message
,Cnf
);
815 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
816 string URI
,string URIDesc
,string ShortDesc
,
817 string MetaIndexURI
, string MetaIndexURIDesc
,
818 string MetaIndexShortDesc
,
819 const vector
<IndexTarget
*>* IndexTargets
,
820 indexRecords
* MetaIndexParser
) :
821 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
822 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
823 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
825 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
826 DestFile
+= URItoFileName(URI
);
828 // remove any partial downloaded sig-file in partial/.
829 // it may confuse proxies and is too small to warrant a
830 // partial download anyway
831 unlink(DestFile
.c_str());
834 Desc
.Description
= URIDesc
;
836 Desc
.ShortDesc
= ShortDesc
;
840 string Final
= _config
->FindDir("Dir::State::lists");
841 Final
+= URItoFileName(RealURI
);
843 if (stat(Final
.c_str(),&Buf
) == 0)
845 // File was already in place. It needs to be re-verified
846 // because Release might have changed, so Move it into partial
847 Rename(Final
,DestFile
);
853 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
854 // ---------------------------------------------------------------------
855 /* The only header we use is the last-modified header. */
856 string
pkgAcqMetaSig::Custom600Headers()
859 if (stat(DestFile
.c_str(),&Buf
) != 0)
860 return "\nIndex-File: true";
862 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
865 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
866 pkgAcquire::MethodConfig
*Cfg
)
868 Item::Done(Message
,Size
,MD5
,Cfg
);
870 string FileName
= LookupTag(Message
,"Filename");
871 if (FileName
.empty() == true)
874 ErrorText
= "Method gave a blank filename";
878 if (FileName
!= DestFile
)
880 // We have to copy it into place
882 Desc
.URI
= "copy:" + FileName
;
889 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
890 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
891 DestFile
, IndexTargets
, MetaIndexParser
);
895 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
897 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
899 // if we get a network error we fail gracefully
900 if(Status
== StatTransientNetworkError
)
902 Item::Failed(Message
,Cnf
);
903 // move the sigfile back on transient network failures
904 if(FileExists(DestFile
))
905 Rename(DestFile
,Final
);
907 // set the status back to , Item::Failed likes to reset it
908 Status
= pkgAcquire::Item::StatTransientNetworkError
;
912 // Delete any existing sigfile when the acquire failed
913 unlink(Final
.c_str());
915 // queue a pkgAcqMetaIndex with no sigfile
916 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
917 "", IndexTargets
, MetaIndexParser
);
919 if (Cnf
->LocalOnly
== true ||
920 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
929 Item::Failed(Message
,Cnf
);
932 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
,
933 string URI
,string URIDesc
,string ShortDesc
,
935 const vector
<struct IndexTarget
*>* IndexTargets
,
936 indexRecords
* MetaIndexParser
) :
937 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
938 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
940 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
941 DestFile
+= URItoFileName(URI
);
944 Desc
.Description
= URIDesc
;
946 Desc
.ShortDesc
= ShortDesc
;
953 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
954 // ---------------------------------------------------------------------
955 /* The only header we use is the last-modified header. */
956 string
pkgAcqMetaIndex::Custom600Headers()
958 string Final
= _config
->FindDir("Dir::State::lists");
959 Final
+= URItoFileName(RealURI
);
962 if (stat(Final
.c_str(),&Buf
) != 0)
963 return "\nIndex-File: true";
965 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
968 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string MD5
,
969 pkgAcquire::MethodConfig
*Cfg
)
971 Item::Done(Message
,Size
,MD5
,Cfg
);
973 // MetaIndexes are done in two passes: one to download the
974 // metaindex with an appropriate method, and a second to verify it
975 // with the gpgv method
977 if (AuthPass
== true)
983 RetrievalDone(Message
);
985 // Still more retrieving to do
990 // There was no signature file, so we are finished. Download
991 // the indexes without verification.
996 // There was a signature file, so pass it to gpgv for
999 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1000 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1001 << SigFile
<< "," << DestFile
<< ")\n";
1003 Desc
.URI
= "gpgv:" + SigFile
;
1010 void pkgAcqMetaIndex::RetrievalDone(string Message
)
1012 // We have just finished downloading a Release file (it is not
1015 string FileName
= LookupTag(Message
,"Filename");
1016 if (FileName
.empty() == true)
1019 ErrorText
= "Method gave a blank filename";
1023 if (FileName
!= DestFile
)
1026 Desc
.URI
= "copy:" + FileName
;
1031 // see if the download was a IMSHit
1032 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1036 string FinalFile
= _config
->FindDir("Dir::State::lists");
1037 FinalFile
+= URItoFileName(RealURI
);
1039 // The files timestamp matches
1040 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == false)
1042 // Move it into position
1043 Rename(DestFile
,FinalFile
);
1045 chmod(FinalFile
.c_str(),0644);
1046 DestFile
= FinalFile
;
1049 void pkgAcqMetaIndex::AuthDone(string Message
)
1051 // At this point, the gpgv method has succeeded, so there is a
1052 // valid signature from a key in the trusted keyring. We
1053 // perform additional verification of its contents, and use them
1054 // to verify the indexes we are about to download
1056 if (!MetaIndexParser
->Load(DestFile
))
1058 Status
= StatAuthError
;
1059 ErrorText
= MetaIndexParser
->ErrorText
;
1063 if (!VerifyVendor(Message
))
1068 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1069 std::cerr
<< "Signature verification succeeded: "
1070 << DestFile
<< std::endl
;
1072 // Download further indexes with verification
1075 // Done, move signature file into position
1077 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1078 URItoFileName(RealURI
) + ".gpg";
1079 Rename(SigFile
,VerifiedSigFile
);
1080 chmod(VerifiedSigFile
.c_str(),0644);
1083 void pkgAcqMetaIndex::QueueIndexes(bool verify
)
1085 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1086 Target
!= IndexTargets
->end();
1089 string ExpectedIndexMD5
;
1092 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1095 Status
= StatAuthError
;
1096 ErrorText
= "Unable to find expected entry "
1097 + (*Target
)->MetaKey
+ " in Meta-index file (malformed Release file?)";
1100 ExpectedIndexMD5
= Record
->MD5Hash
;
1101 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1103 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1104 std::cerr
<< "Expected MD5: " << ExpectedIndexMD5
<< std::endl
;
1106 if (ExpectedIndexMD5
.empty())
1108 Status
= StatAuthError
;
1109 ErrorText
= "Unable to find MD5 sum for "
1110 + (*Target
)->MetaKey
+ " in Meta-index file";
1115 // Queue Packages file (either diff or full packages files, depending
1116 // on the users option)
1117 if(_config
->FindB("Acquire::PDiffs",false) == true)
1118 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1119 (*Target
)->ShortDesc
, ExpectedIndexMD5
);
1121 new pkgAcqIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1122 (*Target
)->ShortDesc
, ExpectedIndexMD5
);
1126 bool pkgAcqMetaIndex::VerifyVendor(string Message
)
1128 // // Maybe this should be made available from above so we don't have
1129 // // to read and parse it every time?
1130 // pkgVendorList List;
1131 // List.ReadMainList();
1133 // const Vendor* Vndr = NULL;
1134 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1136 // string::size_type pos = (*I).find("VALIDSIG ");
1137 // if (_config->FindB("Debug::Vendor", false))
1138 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1140 // if (pos != std::string::npos)
1142 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1143 // if (_config->FindB("Debug::Vendor", false))
1144 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1146 // Vndr = List.FindVendor(Fingerprint) != "";
1147 // if (Vndr != NULL);
1151 string::size_type pos
;
1153 // check for missing sigs (that where not fatal because otherwise we had
1156 string msg
= _("There is no public key available for the "
1157 "following key IDs:\n");
1158 pos
= Message
.find("NO_PUBKEY ");
1159 if (pos
!= std::string::npos
)
1161 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1162 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1163 missingkeys
+= (Fingerprint
);
1165 if(!missingkeys
.empty())
1166 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1168 string Transformed
= MetaIndexParser
->GetExpectedDist();
1170 if (Transformed
== "../project/experimental")
1172 Transformed
= "experimental";
1175 pos
= Transformed
.rfind('/');
1176 if (pos
!= string::npos
)
1178 Transformed
= Transformed
.substr(0, pos
);
1181 if (Transformed
== ".")
1186 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1188 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1189 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1190 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1193 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1195 // This might become fatal one day
1196 // Status = StatAuthError;
1197 // ErrorText = "Conflicting distribution; expected "
1198 // + MetaIndexParser->GetExpectedDist() + " but got "
1199 // + MetaIndexParser->GetDist();
1201 if (!Transformed
.empty())
1203 _error
->Warning("Conflicting distribution: %s (expected %s but got %s)",
1204 Desc
.Description
.c_str(),
1205 Transformed
.c_str(),
1206 MetaIndexParser
->GetDist().c_str());
1213 // pkgAcqMetaIndex::Failed - no Release file present or no signature
1214 // file present /*{{{*/
1215 // ---------------------------------------------------------------------
1217 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1219 if (AuthPass
== true)
1221 // if we fail the authentication but got the file via a IMS-Hit
1222 // this means that the file wasn't downloaded and that it might be
1223 // just stale (server problem, proxy etc). we delete what we have
1224 // queue it again without i-m-s
1225 // alternatively we could just unlink the file and let the user try again
1231 unlink(DestFile
.c_str());
1233 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1234 DestFile
+= URItoFileName(RealURI
);
1240 // gpgv method failed
1241 ReportMirrorFailure("GPGFailure");
1242 _error
->Warning("GPG error: %s: %s",
1243 Desc
.Description
.c_str(),
1244 LookupTag(Message
,"Message").c_str());
1248 // No Release file was present, or verification failed, so fall
1249 // back to queueing Packages files without verification
1250 QueueIndexes(false);
1255 // AcqArchive::AcqArchive - Constructor /*{{{*/
1256 // ---------------------------------------------------------------------
1257 /* This just sets up the initial fetch environment and queues the first
1259 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1260 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1261 string
&StoreFilename
) :
1262 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1263 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1266 Retries
= _config
->FindI("Acquire::Retries",0);
1268 if (Version
.Arch() == 0)
1270 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1271 "This might mean you need to manually fix this package. "
1272 "(due to missing arch)"),
1273 Version
.ParentPkg().Name());
1277 /* We need to find a filename to determine the extension. We make the
1278 assumption here that all the available sources for this version share
1279 the same extension.. */
1280 // Skip not source sources, they do not have file fields.
1281 for (; Vf
.end() == false; Vf
++)
1283 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1288 // Does not really matter here.. we are going to fail out below
1289 if (Vf
.end() != true)
1291 // If this fails to get a file name we will bomb out below.
1292 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1293 if (_error
->PendingError() == true)
1296 // Generate the final file name as: package_version_arch.foo
1297 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1298 QuoteString(Version
.VerStr(),"_:") + '_' +
1299 QuoteString(Version
.Arch(),"_:.") +
1300 "." + flExtension(Parse
.FileName());
1303 // check if we have one trusted source for the package. if so, switch
1304 // to "TrustedOnly" mode
1305 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1307 pkgIndexFile
*Index
;
1308 if (Sources
->FindIndex(i
.File(),Index
) == false)
1310 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1312 std::cerr
<< "Checking index: " << Index
->Describe()
1313 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1315 if (Index
->IsTrusted()) {
1321 // "allow-unauthenticated" restores apts old fetching behaviour
1322 // that means that e.g. unauthenticated file:// uris are higher
1323 // priority than authenticated http:// uris
1324 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1328 if (QueueNext() == false && _error
->PendingError() == false)
1329 _error
->Error(_("I wasn't able to locate file for the %s package. "
1330 "This might mean you need to manually fix this package."),
1331 Version
.ParentPkg().Name());
1334 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1335 // ---------------------------------------------------------------------
1336 /* This queues the next available file version for download. It checks if
1337 the archive is already available in the cache and stashs the MD5 for
1339 bool pkgAcqArchive::QueueNext()
1341 for (; Vf
.end() == false; Vf
++)
1343 // Ignore not source sources
1344 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1347 // Try to cross match against the source list
1348 pkgIndexFile
*Index
;
1349 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1352 // only try to get a trusted package from another source if that source
1354 if(Trusted
&& !Index
->IsTrusted())
1357 // Grab the text package record
1358 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1359 if (_error
->PendingError() == true)
1362 string PkgFile
= Parse
.FileName();
1363 MD5
= Parse
.MD5Hash();
1364 if (PkgFile
.empty() == true)
1365 return _error
->Error(_("The package index files are corrupted. No Filename: "
1366 "field for package %s."),
1367 Version
.ParentPkg().Name());
1369 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1370 Desc
.Description
= Index
->ArchiveInfo(Version
);
1372 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1374 // See if we already have the file. (Legacy filenames)
1375 FileSize
= Version
->Size
;
1376 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1378 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1380 // Make sure the size matches
1381 if ((unsigned)Buf
.st_size
== Version
->Size
)
1386 StoreFilename
= DestFile
= FinalFile
;
1390 /* Hmm, we have a file and its size does not match, this means it is
1391 an old style mismatched arch */
1392 unlink(FinalFile
.c_str());
1395 // Check it again using the new style output filenames
1396 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1397 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1399 // Make sure the size matches
1400 if ((unsigned)Buf
.st_size
== Version
->Size
)
1405 StoreFilename
= DestFile
= FinalFile
;
1409 /* Hmm, we have a file and its size does not match, this shouldnt
1411 unlink(FinalFile
.c_str());
1414 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1416 // Check the destination file
1417 if (stat(DestFile
.c_str(),&Buf
) == 0)
1419 // Hmm, the partial file is too big, erase it
1420 if ((unsigned)Buf
.st_size
> Version
->Size
)
1421 unlink(DestFile
.c_str());
1423 PartialSize
= Buf
.st_size
;
1428 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1429 Desc
.Description
= Index
->ArchiveInfo(Version
);
1431 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1440 // AcqArchive::Done - Finished fetching /*{{{*/
1441 // ---------------------------------------------------------------------
1443 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
,
1444 pkgAcquire::MethodConfig
*Cfg
)
1446 Item::Done(Message
,Size
,Md5Hash
,Cfg
);
1449 if (Size
!= Version
->Size
)
1452 ErrorText
= _("Size mismatch");
1457 if (Md5Hash
.empty() == false && MD5
.empty() == false)
1462 ErrorText
= _("MD5Sum mismatch");
1463 if(FileExists(DestFile
))
1464 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
1536 // trusted source /*{{{*/
1537 // ---------------------------------------------------------------------
1538 bool pkgAcqArchive::IsTrusted()
1543 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1544 // ---------------------------------------------------------------------
1546 void pkgAcqArchive::Finished()
1548 if (Status
== pkgAcquire::Item::StatDone
&&
1551 StoreFilename
= string();
1555 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1556 // ---------------------------------------------------------------------
1557 /* The file is added to the queue */
1558 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string MD5
,
1559 unsigned long Size
,string Dsc
,string ShortDesc
,
1560 const string
&DestDir
, const string
&DestFilename
) :
1561 Item(Owner
), Md5Hash(MD5
)
1563 Retries
= _config
->FindI("Acquire::Retries",0);
1565 if(!DestFilename
.empty())
1566 DestFile
= DestFilename
;
1567 else if(!DestDir
.empty())
1568 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1570 DestFile
= flNotDir(URI
);
1574 Desc
.Description
= Dsc
;
1577 // Set the short description to the archive component
1578 Desc
.ShortDesc
= ShortDesc
;
1580 // Get the transfer sizes
1583 if (stat(DestFile
.c_str(),&Buf
) == 0)
1585 // Hmm, the partial file is too big, erase it
1586 if ((unsigned)Buf
.st_size
> Size
)
1587 unlink(DestFile
.c_str());
1589 PartialSize
= Buf
.st_size
;
1595 // AcqFile::Done - Item downloaded OK /*{{{*/
1596 // ---------------------------------------------------------------------
1598 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
,
1599 pkgAcquire::MethodConfig
*Cnf
)
1602 if (Md5Hash
.empty() == false && MD5
.empty() == false)
1607 ErrorText
= "MD5Sum mismatch";
1608 Rename(DestFile
,DestFile
+ ".FAILED");
1613 Item::Done(Message
,Size
,MD5
,Cnf
);
1615 string FileName
= LookupTag(Message
,"Filename");
1616 if (FileName
.empty() == true)
1619 ErrorText
= "Method gave a blank filename";
1625 // The files timestamp matches
1626 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1629 // We have to copy it into place
1630 if (FileName
!= DestFile
)
1633 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1634 Cnf
->Removable
== true)
1636 Desc
.URI
= "copy:" + FileName
;
1641 // Erase the file if it is a symlink so we can overwrite it
1643 if (lstat(DestFile
.c_str(),&St
) == 0)
1645 if (S_ISLNK(St
.st_mode
) != 0)
1646 unlink(DestFile
.c_str());
1650 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1652 ErrorText
= "Link to " + DestFile
+ " failure ";
1659 // AcqFile::Failed - Failure handler /*{{{*/
1660 // ---------------------------------------------------------------------
1661 /* Here we try other sources */
1662 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1664 ErrorText
= LookupTag(Message
,"Message");
1666 // This is the retry counter
1668 Cnf
->LocalOnly
== false &&
1669 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1676 Item::Failed(Message
,Cnf
);