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 /*{{{*/
17 #pragma implementation "apt-pkg/acquire-item.h"
19 #include <apt-pkg/acquire-item.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/vendorlist.h>
23 #include <apt-pkg/error.h>
24 #include <apt-pkg/strutl.h>
25 #include <apt-pkg/fileutl.h>
26 #include <apt-pkg/md5.h>
27 #include <apt-pkg/sha1.h>
28 #include <apt-pkg/tagfile.h>
42 // Acquire::Item::Item - Constructor /*{{{*/
43 // ---------------------------------------------------------------------
45 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
46 PartialSize(0), Mode(0), ID(0), Complete(false),
47 Local(false), QueueCounter(0)
53 // Acquire::Item::~Item - Destructor /*{{{*/
54 // ---------------------------------------------------------------------
56 pkgAcquire::Item::~Item()
61 // Acquire::Item::Failed - Item failed to download /*{{{*/
62 // ---------------------------------------------------------------------
63 /* We return to an idle state if there are still other queues that could
65 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
68 ErrorText
= LookupTag(Message
,"Message");
69 if (QueueCounter
<= 1)
71 /* This indicates that the file is not available right now but might
72 be sometime later. If we do a retry cycle then this should be
74 if (Cnf
->LocalOnly
== true &&
75 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
87 // Acquire::Item::Start - Item has begun to download /*{{{*/
88 // ---------------------------------------------------------------------
89 /* Stash status and the file size. Note that setting Complete means
90 sub-phases of the acquire process such as decompresion are operating */
91 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long Size
)
93 Status
= StatFetching
;
94 if (FileSize
== 0 && Complete
== false)
98 // Acquire::Item::Done - Item downloaded OK /*{{{*/
99 // ---------------------------------------------------------------------
101 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string
,
102 pkgAcquire::MethodConfig
*Cnf
)
104 // We just downloaded something..
105 string FileName
= LookupTag(Message
,"Filename");
106 if (Complete
== false && FileName
== DestFile
)
109 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
116 ErrorText
= string();
117 Owner
->Dequeue(this);
120 // Acquire::Item::Rename - Rename a file /*{{{*/
121 // ---------------------------------------------------------------------
122 /* This helper function is used by alot of item methods as thier final
124 void pkgAcquire::Item::Rename(string From
,string To
)
126 if (rename(From
.c_str(),To
.c_str()) != 0)
129 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
130 From
.c_str(),To
.c_str());
138 // AcqDiffIndex::AcqDiffIndex - Constructor
139 // ---------------------------------------------------------------------
140 /* Get the DiffIndex file first and see if there are patches availabe
141 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
142 * patches. If anything goes wrong in that process, it will fall back to
143 * the original packages file
145 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
146 string URI
,string URIDesc
,string ShortDesc
,
148 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
), Description(URIDesc
)
151 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
153 Desc
.Description
= URIDesc
+ "/DiffIndex";
155 Desc
.ShortDesc
= ShortDesc
;
156 Desc
.URI
= URI
+ ".diff/Index";
158 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
159 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
162 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
164 // look for the current package file
165 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
166 CurrentPackagesFile
+= URItoFileName(RealURI
);
168 if(!FileExists(CurrentPackagesFile
) ||
169 !_config
->FindB("Acquire::Diffs",true)) {
170 // we don't have a pkg file or we don't want to queue
172 std::clog
<< "No index file or canceld by user" << std::endl
;
178 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
179 << CurrentPackagesFile
<< std::endl
;
186 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
187 // ---------------------------------------------------------------------
188 /* The only header we use is the last-modified header. */
189 string
pkgAcqDiffIndex::Custom600Headers()
191 string Final
= _config
->FindDir("Dir::State::lists");
192 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
195 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
198 if (stat(Final
.c_str(),&Buf
) != 0)
199 return "\nIndex-File: true";
201 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
205 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
)
208 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
213 vector
<DiffInfo
> available_patches
;
215 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
217 if (_error
->PendingError() == true)
220 if(TF
.Step(Tags
) == true)
227 string tmp
= Tags
.FindS("SHA1-Current");
228 std::stringstream
ss(tmp
);
231 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
233 SHA1
.AddFD(fd
.Fd(), fd
.Size());
234 local_sha1
= string(SHA1
.Result());
236 if(local_sha1
== ServerSha1
) {
238 std::clog
<< "Package file is up-to-date" << std::endl
;
239 // set found to true, this will queue a pkgAcqIndexDiffs with
240 // a empty availabe_patches
244 std::clog
<< "SHA1-Current: " << ServerSha1
<< std::endl
;
246 // check the historie and see what patches we need
247 string history
= Tags
.FindS("SHA1-History");
248 std::stringstream
hist(history
);
249 while(hist
>> d
.sha1
>> size
>> d
.file
) {
250 d
.size
= atoi(size
.c_str());
251 // read until the first match is found
252 if(d
.sha1
== local_sha1
)
254 // from that point on, we probably need all diffs
257 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
258 available_patches
.push_back(d
);
263 // no information how to get the patches, bail out
266 std::clog
<< "Can't find a patch in the index file" << std::endl
;
267 // Failed will queue a big package file
271 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
272 ExpectedMD5
, available_patches
);
283 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
286 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
287 << "Falling back to normal index file aquire" << std::endl
;
289 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
297 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
,
298 pkgAcquire::MethodConfig
*Cnf
)
301 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
303 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
306 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
308 // sucess in downloading the index
310 FinalFile
+= string(".IndexDiff");
312 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
314 Rename(DestFile
,FinalFile
);
315 chmod(FinalFile
.c_str(),0644);
316 DestFile
= FinalFile
;
318 if(!ParseDiffIndex(DestFile
))
319 return Failed("", NULL
);
329 // AcqIndexDiffs::AcqIndexDiffs - Constructor
330 // ---------------------------------------------------------------------
331 /* The package diff is added to the queue. one object is constructed
332 * for each diff and the index
334 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
335 string URI
,string URIDesc
,string ShortDesc
,
336 string ExpectedMD5
, vector
<DiffInfo
> diffs
)
337 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
),
338 available_patches(diffs
)
341 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
342 DestFile
+= URItoFileName(URI
);
344 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
346 Desc
.Description
= URIDesc
;
348 Desc
.ShortDesc
= ShortDesc
;
350 if(available_patches
.size() == 0) {
351 // we are done (yeah!)
355 State
= StateFetchDiff
;
361 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
364 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
365 << "Falling back to normal index file aquire" << std::endl
;
366 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
372 // helper that cleans the item out of the fetcher queue
373 void pkgAcqIndexDiffs::Finish(bool allDone
)
375 // we restore the original name, this is required, otherwise
376 // the file will be cleaned
378 // this is for the "real" finish
379 DestFile
= _config
->FindDir("Dir::State::lists");
380 DestFile
+= URItoFileName(RealURI
);
385 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
390 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
399 bool pkgAcqIndexDiffs::QueueNextDiff()
402 // calc sha1 of the just patched file
403 string FinalFile
= _config
->FindDir("Dir::State::lists");
404 FinalFile
+= URItoFileName(RealURI
);
406 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
408 SHA1
.AddFD(fd
.Fd(), fd
.Size());
409 string local_sha1
= string(SHA1
.Result());
411 std::clog
<< "QueueNextDiff: "
412 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
414 // remove all patches until the next matching patch is found
415 // this requires the Index file to be ordered
416 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
417 available_patches
.size() > 0 && I
!= available_patches
.end()
418 && (*I
).sha1
!= local_sha1
;
420 available_patches
.erase(I
);
423 // error checking and falling back if no patch was found
424 if(available_patches
.size() == 0) {
429 // queue the right diff
430 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
431 Desc
.Description
= available_patches
[0].file
+ string(".pdiff");
433 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
434 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
437 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
446 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
,
447 pkgAcquire::MethodConfig
*Cnf
)
450 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
452 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
455 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
457 // sucess in downloading a diff, enter ApplyDiff state
458 if(State
== StateFetchDiff
)
462 std::clog
<< "Sending to gzip method: " << FinalFile
<< std::endl
;
464 string FileName
= LookupTag(Message
,"Filename");
465 State
= StateUnzipDiff
;
466 Desc
.URI
= "gzip:" + FileName
;
467 DestFile
+= ".decomp";
473 // sucess in downloading a diff, enter ApplyDiff state
474 if(State
== StateUnzipDiff
)
477 // rred excepts the patch as $FinalFile.ed
478 Rename(DestFile
,FinalFile
+".ed");
481 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
483 State
= StateApplyDiff
;
484 Desc
.URI
= "rred:" + FinalFile
;
491 // success in download/apply a diff, queue next (if needed)
492 if(State
== StateApplyDiff
)
494 // remove the just applied patch
495 available_patches
.erase(available_patches
.begin());
500 std::clog
<< "Moving patched file in place: " << std::endl
501 << DestFile
<< " -> " << FinalFile
<< std::endl
;
503 Rename(DestFile
,FinalFile
);
505 // see if there is more to download
506 if(available_patches
.size() > 0) {
507 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
508 ExpectedMD5
, available_patches
);
516 // AcqIndex::AcqIndex - Constructor /*{{{*/
517 // ---------------------------------------------------------------------
518 /* The package file is added to the queue and a second class is
519 instantiated to fetch the revision file */
520 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
521 string URI
,string URIDesc
,string ShortDesc
,
522 string ExpectedMD5
, string comprExt
)
523 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
)
525 Decompression
= false;
528 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
529 DestFile
+= URItoFileName(URI
);
533 // autoselect the compression method
534 if(FileExists("/usr/bin/bzip2"))
535 CompressionExtension
= ".bz2";
537 CompressionExtension
= ".gz";
539 CompressionExtension
= comprExt
;
541 Desc
.URI
= URI
+ CompressionExtension
;
543 Desc
.Description
= URIDesc
;
545 Desc
.ShortDesc
= ShortDesc
;
550 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
551 // ---------------------------------------------------------------------
552 /* The only header we use is the last-modified header. */
553 string
pkgAcqIndex::Custom600Headers()
555 string Final
= _config
->FindDir("Dir::State::lists");
556 Final
+= URItoFileName(RealURI
);
559 if (stat(Final
.c_str(),&Buf
) != 0)
560 return "\nIndex-File: true";
562 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
566 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
568 // no .bz2 found, retry with .gz
569 if(Desc
.URI
.substr(Desc
.URI
.size()-3,Desc
.URI
.size()-1) == "bz2") {
570 Desc
.URI
= Desc
.URI
.substr(0,Desc
.URI
.size()-3) + "gz";
572 // retry with a gzip one
573 new pkgAcqIndex(Owner
, RealURI
, Desc
.Description
,Desc
.ShortDesc
,
574 ExpectedMD5
, string(".gz"));
582 Item::Failed(Message
,Cnf
);
586 // AcqIndex::Done - Finished a fetch /*{{{*/
587 // ---------------------------------------------------------------------
588 /* This goes through a number of states.. On the initial fetch the
589 method could possibly return an alternate filename which points
590 to the uncompressed version of the file. If this is so the file
591 is copied into the partial directory. In all other cases the file
592 is decompressed with a gzip uri. */
593 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
,
594 pkgAcquire::MethodConfig
*Cfg
)
596 Item::Done(Message
,Size
,MD5
,Cfg
);
598 if (Decompression
== true)
600 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
602 std::cerr
<< std::endl
<< RealURI
<< ": Computed MD5: " << MD5
;
603 std::cerr
<< " Expected MD5: " << ExpectedMD5
<< std::endl
;
609 FileFd
Fd(DestFile
, FileFd::ReadOnly
);
610 sum
.AddFD(Fd
.Fd(), Fd
.Size());
612 MD5
= (string
)sum
.Result();
615 if (!ExpectedMD5
.empty() && MD5
!= ExpectedMD5
)
617 Status
= StatAuthError
;
618 ErrorText
= _("MD5Sum mismatch");
619 Rename(DestFile
,DestFile
+ ".FAILED");
622 // Done, move it into position
623 string FinalFile
= _config
->FindDir("Dir::State::lists");
624 FinalFile
+= URItoFileName(RealURI
);
625 Rename(DestFile
,FinalFile
);
626 chmod(FinalFile
.c_str(),0644);
628 /* We restore the original name to DestFile so that the clean operation
630 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
631 DestFile
+= URItoFileName(RealURI
);
633 // Remove the compressed version.
635 unlink(DestFile
.c_str());
642 // Handle the unzipd case
643 string FileName
= LookupTag(Message
,"Alt-Filename");
644 if (FileName
.empty() == false)
646 // The files timestamp matches
647 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
650 Decompression
= true;
652 DestFile
+= ".decomp";
653 Desc
.URI
= "copy:" + FileName
;
659 FileName
= LookupTag(Message
,"Filename");
660 if (FileName
.empty() == true)
663 ErrorText
= "Method gave a blank filename";
666 // The files timestamp matches
667 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
670 if (FileName
== DestFile
)
675 string compExt
= Desc
.URI
.substr(Desc
.URI
.size()-3,Desc
.URI
.size()-1);
678 decompProg
= "bzip2";
679 else if(compExt
== ".gz")
682 _error
->Error("Unsupported extension: %s", compExt
.c_str());
686 Decompression
= true;
687 DestFile
+= ".decomp";
688 Desc
.URI
= string(decompProg
) + ":" + FileName
;
693 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
694 string URI
,string URIDesc
,string ShortDesc
,
695 string MetaIndexURI
, string MetaIndexURIDesc
,
696 string MetaIndexShortDesc
,
697 const vector
<IndexTarget
*>* IndexTargets
,
698 indexRecords
* MetaIndexParser
) :
699 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
700 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
)
702 this->MetaIndexParser
= MetaIndexParser
;
703 this->IndexTargets
= IndexTargets
;
704 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
705 DestFile
+= URItoFileName(URI
);
707 // remove any partial downloaded sig-file. it may confuse proxies
708 // and is too small to warrant a partial download anyway
709 unlink(DestFile
.c_str());
712 Desc
.Description
= URIDesc
;
714 Desc
.ShortDesc
= ShortDesc
;
718 string Final
= _config
->FindDir("Dir::State::lists");
719 Final
+= URItoFileName(RealURI
);
721 if (stat(Final
.c_str(),&Buf
) == 0)
723 // File was already in place. It needs to be re-verified
724 // because Release might have changed, so Move it into partial
725 Rename(Final
,DestFile
);
726 // unlink the file and do not try to use I-M-S and Last-Modified
727 // if the users proxy is broken
728 if(_config
->FindB("Acquire::BrokenProxy", false) == true) {
729 std::cerr
<< "forcing re-get of the signature file as requested" << std::endl
;
730 unlink(DestFile
.c_str());
737 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
738 // ---------------------------------------------------------------------
739 /* The only header we use is the last-modified header. */
740 string
pkgAcqMetaSig::Custom600Headers()
743 if (stat(DestFile
.c_str(),&Buf
) != 0)
744 return "\nIndex-File: true";
746 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
749 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
750 pkgAcquire::MethodConfig
*Cfg
)
752 Item::Done(Message
,Size
,MD5
,Cfg
);
754 string FileName
= LookupTag(Message
,"Filename");
755 if (FileName
.empty() == true)
758 ErrorText
= "Method gave a blank filename";
762 if (FileName
!= DestFile
)
764 // We have to copy it into place
766 Desc
.URI
= "copy:" + FileName
;
773 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
774 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
775 DestFile
, IndexTargets
, MetaIndexParser
);
779 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
781 // Delete any existing sigfile, so that this source isn't
782 // mistakenly trusted
783 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
784 unlink(Final
.c_str());
786 // if we get a timeout if fail
787 if(LookupTag(Message
,"FailReason") == "Timeout" ||
788 LookupTag(Message
,"FailReason") == "TmpResolveFailure") {
789 Item::Failed(Message
,Cnf
);
793 // queue a pkgAcqMetaIndex with no sigfile
794 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
795 "", IndexTargets
, MetaIndexParser
);
797 if (Cnf
->LocalOnly
== true ||
798 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
807 Item::Failed(Message
,Cnf
);
810 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
,
811 string URI
,string URIDesc
,string ShortDesc
,
813 const vector
<struct IndexTarget
*>* IndexTargets
,
814 indexRecords
* MetaIndexParser
) :
815 Item(Owner
), RealURI(URI
), SigFile(SigFile
)
817 this->AuthPass
= false;
818 this->MetaIndexParser
= MetaIndexParser
;
819 this->IndexTargets
= IndexTargets
;
820 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
821 DestFile
+= URItoFileName(URI
);
824 Desc
.Description
= URIDesc
;
826 Desc
.ShortDesc
= ShortDesc
;
833 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
834 // ---------------------------------------------------------------------
835 /* The only header we use is the last-modified header. */
836 string
pkgAcqMetaIndex::Custom600Headers()
838 string Final
= _config
->FindDir("Dir::State::lists");
839 Final
+= URItoFileName(RealURI
);
842 if (stat(Final
.c_str(),&Buf
) != 0)
843 return "\nIndex-File: true";
845 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
848 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string MD5
,
849 pkgAcquire::MethodConfig
*Cfg
)
851 Item::Done(Message
,Size
,MD5
,Cfg
);
853 // MetaIndexes are done in two passes: one to download the
854 // metaindex with an appropriate method, and a second to verify it
855 // with the gpgv method
857 if (AuthPass
== true)
863 RetrievalDone(Message
);
865 // Still more retrieving to do
870 // There was no signature file, so we are finished. Download
871 // the indexes without verification.
876 // There was a signature file, so pass it to gpgv for
879 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
880 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
881 << SigFile
<< "," << DestFile
<< ")\n";
883 Desc
.URI
= "gpgv:" + SigFile
;
890 void pkgAcqMetaIndex::RetrievalDone(string Message
)
892 // We have just finished downloading a Release file (it is not
895 string FileName
= LookupTag(Message
,"Filename");
896 if (FileName
.empty() == true)
899 ErrorText
= "Method gave a blank filename";
903 if (FileName
!= DestFile
)
906 Desc
.URI
= "copy:" + FileName
;
913 string FinalFile
= _config
->FindDir("Dir::State::lists");
914 FinalFile
+= URItoFileName(RealURI
);
916 // The files timestamp matches
917 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == false)
919 // Move it into position
920 Rename(DestFile
,FinalFile
);
922 DestFile
= FinalFile
;
925 void pkgAcqMetaIndex::AuthDone(string Message
)
927 // At this point, the gpgv method has succeeded, so there is a
928 // valid signature from a key in the trusted keyring. We
929 // perform additional verification of its contents, and use them
930 // to verify the indexes we are about to download
932 if (!MetaIndexParser
->Load(DestFile
))
934 Status
= StatAuthError
;
935 ErrorText
= MetaIndexParser
->ErrorText
;
944 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
945 std::cerr
<< "Signature verification succeeded: "
946 << DestFile
<< std::endl
;
948 // Download further indexes with verification
951 // Done, move signature file into position
953 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
954 URItoFileName(RealURI
) + ".gpg";
955 Rename(SigFile
,VerifiedSigFile
);
956 chmod(VerifiedSigFile
.c_str(),0644);
959 void pkgAcqMetaIndex::QueueIndexes(bool verify
)
961 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
962 Target
!= IndexTargets
->end();
965 string ExpectedIndexMD5
;
968 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
971 Status
= StatAuthError
;
972 ErrorText
= "Unable to find expected entry "
973 + (*Target
)->MetaKey
+ " in Meta-index file (malformed Release file?)";
976 ExpectedIndexMD5
= Record
->MD5Hash
;
977 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
979 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
980 std::cerr
<< "Expected MD5: " << ExpectedIndexMD5
<< std::endl
;
982 if (ExpectedIndexMD5
.empty())
984 Status
= StatAuthError
;
985 ErrorText
= "Unable to find MD5 sum for "
986 + (*Target
)->MetaKey
+ " in Meta-index file";
991 // Queue Packages file
992 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
993 (*Target
)->ShortDesc
, ExpectedIndexMD5
);
997 bool pkgAcqMetaIndex::VerifyVendor()
999 // // Maybe this should be made available from above so we don't have
1000 // // to read and parse it every time?
1001 // pkgVendorList List;
1002 // List.ReadMainList();
1004 // const Vendor* Vndr = NULL;
1005 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1007 // string::size_type pos = (*I).find("VALIDSIG ");
1008 // if (_config->FindB("Debug::Vendor", false))
1009 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1011 // if (pos != std::string::npos)
1013 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1014 // if (_config->FindB("Debug::Vendor", false))
1015 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1017 // Vndr = List.FindVendor(Fingerprint) != "";
1018 // if (Vndr != NULL);
1023 string Transformed
= MetaIndexParser
->GetExpectedDist();
1025 if (Transformed
== "../project/experimental")
1027 Transformed
= "experimental";
1030 string::size_type pos
= Transformed
.rfind('/');
1031 if (pos
!= string::npos
)
1033 Transformed
= Transformed
.substr(0, pos
);
1036 if (Transformed
== ".")
1041 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1043 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1044 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1045 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1048 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1050 // This might become fatal one day
1051 // Status = StatAuthError;
1052 // ErrorText = "Conflicting distribution; expected "
1053 // + MetaIndexParser->GetExpectedDist() + " but got "
1054 // + MetaIndexParser->GetDist();
1056 if (!Transformed
.empty())
1058 _error
->Warning("Conflicting distribution: %s (expected %s but got %s)",
1059 Desc
.Description
.c_str(),
1060 Transformed
.c_str(),
1061 MetaIndexParser
->GetDist().c_str());
1068 // pkgAcqMetaIndex::Failed - no Release file present or no signature
1069 // file present /*{{{*/
1070 // ---------------------------------------------------------------------
1072 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1074 if (AuthPass
== true)
1076 // gpgv method failed
1077 _error
->Warning("GPG error: %s: %s",
1078 Desc
.Description
.c_str(),
1079 LookupTag(Message
,"Message").c_str());
1082 // No Release file was present, or verification failed, so fall
1083 // back to queueing Packages files without verification
1084 QueueIndexes(false);
1089 // AcqArchive::AcqArchive - Constructor /*{{{*/
1090 // ---------------------------------------------------------------------
1091 /* This just sets up the initial fetch environment and queues the first
1093 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1094 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1095 string
&StoreFilename
) :
1096 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1097 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1100 Retries
= _config
->FindI("Acquire::Retries",0);
1102 if (Version
.Arch() == 0)
1104 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1105 "This might mean you need to manually fix this package. "
1106 "(due to missing arch)"),
1107 Version
.ParentPkg().Name());
1111 /* We need to find a filename to determine the extension. We make the
1112 assumption here that all the available sources for this version share
1113 the same extension.. */
1114 // Skip not source sources, they do not have file fields.
1115 for (; Vf
.end() == false; Vf
++)
1117 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1122 // Does not really matter here.. we are going to fail out below
1123 if (Vf
.end() != true)
1125 // If this fails to get a file name we will bomb out below.
1126 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1127 if (_error
->PendingError() == true)
1130 // Generate the final file name as: package_version_arch.foo
1131 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1132 QuoteString(Version
.VerStr(),"_:") + '_' +
1133 QuoteString(Version
.Arch(),"_:.") +
1134 "." + flExtension(Parse
.FileName());
1137 // check if we have one trusted source for the package. if so, switch
1138 // to "TrustedOnly" mode
1139 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1141 pkgIndexFile
*Index
;
1142 if (Sources
->FindIndex(i
.File(),Index
) == false)
1144 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1146 std::cerr
<< "Checking index: " << Index
->Describe()
1147 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1149 if (Index
->IsTrusted()) {
1156 if (QueueNext() == false && _error
->PendingError() == false)
1157 _error
->Error(_("I wasn't able to locate file for the %s package. "
1158 "This might mean you need to manually fix this package."),
1159 Version
.ParentPkg().Name());
1162 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1163 // ---------------------------------------------------------------------
1164 /* This queues the next available file version for download. It checks if
1165 the archive is already available in the cache and stashs the MD5 for
1167 bool pkgAcqArchive::QueueNext()
1169 for (; Vf
.end() == false; Vf
++)
1171 // Ignore not source sources
1172 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1175 // Try to cross match against the source list
1176 pkgIndexFile
*Index
;
1177 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1180 // only try to get a trusted package from another source if that source
1182 if(Trusted
&& !Index
->IsTrusted())
1185 // Grab the text package record
1186 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1187 if (_error
->PendingError() == true)
1190 string PkgFile
= Parse
.FileName();
1191 MD5
= Parse
.MD5Hash();
1192 if (PkgFile
.empty() == true)
1193 return _error
->Error(_("The package index files are corrupted. No Filename: "
1194 "field for package %s."),
1195 Version
.ParentPkg().Name());
1197 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1198 Desc
.Description
= Index
->ArchiveInfo(Version
);
1200 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1202 // See if we already have the file. (Legacy filenames)
1203 FileSize
= Version
->Size
;
1204 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1206 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1208 // Make sure the size matches
1209 if ((unsigned)Buf
.st_size
== Version
->Size
)
1214 StoreFilename
= DestFile
= FinalFile
;
1218 /* Hmm, we have a file and its size does not match, this means it is
1219 an old style mismatched arch */
1220 unlink(FinalFile
.c_str());
1223 // Check it again using the new style output filenames
1224 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1225 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1227 // Make sure the size matches
1228 if ((unsigned)Buf
.st_size
== Version
->Size
)
1233 StoreFilename
= DestFile
= FinalFile
;
1237 /* Hmm, we have a file and its size does not match, this shouldnt
1239 unlink(FinalFile
.c_str());
1242 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1244 // Check the destination file
1245 if (stat(DestFile
.c_str(),&Buf
) == 0)
1247 // Hmm, the partial file is too big, erase it
1248 if ((unsigned)Buf
.st_size
> Version
->Size
)
1249 unlink(DestFile
.c_str());
1251 PartialSize
= Buf
.st_size
;
1256 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1257 Desc
.Description
= Index
->ArchiveInfo(Version
);
1259 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1268 // AcqArchive::Done - Finished fetching /*{{{*/
1269 // ---------------------------------------------------------------------
1271 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
,
1272 pkgAcquire::MethodConfig
*Cfg
)
1274 Item::Done(Message
,Size
,Md5Hash
,Cfg
);
1277 if (Size
!= Version
->Size
)
1280 ErrorText
= _("Size mismatch");
1285 if (Md5Hash
.empty() == false && MD5
.empty() == false)
1290 ErrorText
= _("MD5Sum mismatch");
1291 if(FileExists(DestFile
))
1292 Rename(DestFile
,DestFile
+ ".FAILED");
1297 // Grab the output filename
1298 string FileName
= LookupTag(Message
,"Filename");
1299 if (FileName
.empty() == true)
1302 ErrorText
= "Method gave a blank filename";
1308 // Reference filename
1309 if (FileName
!= DestFile
)
1311 StoreFilename
= DestFile
= FileName
;
1316 // Done, move it into position
1317 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1318 FinalFile
+= flNotDir(StoreFilename
);
1319 Rename(DestFile
,FinalFile
);
1321 StoreFilename
= DestFile
= FinalFile
;
1325 // AcqArchive::Failed - Failure handler /*{{{*/
1326 // ---------------------------------------------------------------------
1327 /* Here we try other sources */
1328 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1330 ErrorText
= LookupTag(Message
,"Message");
1332 /* We don't really want to retry on failed media swaps, this prevents
1333 that. An interesting observation is that permanent failures are not
1335 if (Cnf
->Removable
== true &&
1336 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1338 // Vf = Version.FileList();
1339 while (Vf
.end() == false) Vf
++;
1340 StoreFilename
= string();
1341 Item::Failed(Message
,Cnf
);
1345 if (QueueNext() == false)
1347 // This is the retry counter
1349 Cnf
->LocalOnly
== false &&
1350 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1353 Vf
= Version
.FileList();
1354 if (QueueNext() == true)
1358 StoreFilename
= string();
1359 Item::Failed(Message
,Cnf
);
1363 // AcqArchive::IsTrusted - Determine whether this archive comes from a
1364 // trusted source /*{{{*/
1365 // ---------------------------------------------------------------------
1366 bool pkgAcqArchive::IsTrusted()
1371 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1372 // ---------------------------------------------------------------------
1374 void pkgAcqArchive::Finished()
1376 if (Status
== pkgAcquire::Item::StatDone
&&
1379 StoreFilename
= string();
1383 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1384 // ---------------------------------------------------------------------
1385 /* The file is added to the queue */
1386 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string MD5
,
1387 unsigned long Size
,string Dsc
,string ShortDesc
) :
1388 Item(Owner
), Md5Hash(MD5
)
1390 Retries
= _config
->FindI("Acquire::Retries",0);
1392 DestFile
= flNotDir(URI
);
1396 Desc
.Description
= Dsc
;
1399 // Set the short description to the archive component
1400 Desc
.ShortDesc
= ShortDesc
;
1402 // Get the transfer sizes
1405 if (stat(DestFile
.c_str(),&Buf
) == 0)
1407 // Hmm, the partial file is too big, erase it
1408 if ((unsigned)Buf
.st_size
> Size
)
1409 unlink(DestFile
.c_str());
1411 PartialSize
= Buf
.st_size
;
1417 // AcqFile::Done - Item downloaded OK /*{{{*/
1418 // ---------------------------------------------------------------------
1420 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
,
1421 pkgAcquire::MethodConfig
*Cnf
)
1424 if (Md5Hash
.empty() == false && MD5
.empty() == false)
1429 ErrorText
= "MD5Sum mismatch";
1430 Rename(DestFile
,DestFile
+ ".FAILED");
1435 Item::Done(Message
,Size
,MD5
,Cnf
);
1437 string FileName
= LookupTag(Message
,"Filename");
1438 if (FileName
.empty() == true)
1441 ErrorText
= "Method gave a blank filename";
1447 // The files timestamp matches
1448 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1451 // We have to copy it into place
1452 if (FileName
!= DestFile
)
1455 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1456 Cnf
->Removable
== true)
1458 Desc
.URI
= "copy:" + FileName
;
1463 // Erase the file if it is a symlink so we can overwrite it
1465 if (lstat(DestFile
.c_str(),&St
) == 0)
1467 if (S_ISLNK(St
.st_mode
) != 0)
1468 unlink(DestFile
.c_str());
1472 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1474 ErrorText
= "Link to " + DestFile
+ " failure ";
1481 // AcqFile::Failed - Failure handler /*{{{*/
1482 // ---------------------------------------------------------------------
1483 /* Here we try other sources */
1484 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1486 ErrorText
= LookupTag(Message
,"Message");
1488 // This is the retry counter
1490 Cnf
->LocalOnly
== false &&
1491 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1498 Item::Failed(Message
,Cnf
);