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 // we only inform the Log class if it was actually not a local thing
107 if (Complete
== false && !Local
&& FileName
== DestFile
)
110 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
117 ErrorText
= string();
118 Owner
->Dequeue(this);
121 // Acquire::Item::Rename - Rename a file /*{{{*/
122 // ---------------------------------------------------------------------
123 /* This helper function is used by alot of item methods as thier final
125 void pkgAcquire::Item::Rename(string From
,string To
)
127 if (rename(From
.c_str(),To
.c_str()) != 0)
130 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
131 From
.c_str(),To
.c_str());
140 // AcqDiffIndex::AcqDiffIndex - Constructor
141 // ---------------------------------------------------------------------
142 /* Get the DiffIndex file first and see if there are patches availabe
143 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
144 * patches. If anything goes wrong in that process, it will fall back to
145 * the original packages file
147 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
148 string URI
,string URIDesc
,string ShortDesc
,
150 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
), Description(URIDesc
)
153 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
155 Desc
.Description
= URIDesc
+ "/DiffIndex";
157 Desc
.ShortDesc
= ShortDesc
;
158 Desc
.URI
= URI
+ ".diff/Index";
160 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
161 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
164 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
166 // look for the current package file
167 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
168 CurrentPackagesFile
+= URItoFileName(RealURI
);
170 // FIXME: this file:/ check is a hack to prevent fetching
171 // from local sources. this is really silly, and
172 // should be fixed cleanly as soon as possible
173 if(!FileExists(CurrentPackagesFile
) ||
174 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
176 // we don't have a pkg file or we don't want to queue
178 std::clog
<< "No index file, local or canceld by user" << std::endl
;
184 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
185 << CurrentPackagesFile
<< std::endl
;
191 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
192 // ---------------------------------------------------------------------
193 /* The only header we use is the last-modified header. */
194 string
pkgAcqDiffIndex::Custom600Headers()
196 string Final
= _config
->FindDir("Dir::State::lists");
197 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
200 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
203 if (stat(Final
.c_str(),&Buf
) != 0)
204 return "\nIndex-File: true";
206 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
210 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
)
213 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
218 vector
<DiffInfo
> available_patches
;
220 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
222 if (_error
->PendingError() == true)
225 if(TF
.Step(Tags
) == true)
232 string tmp
= Tags
.FindS("SHA1-Current");
233 std::stringstream
ss(tmp
);
236 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
238 SHA1
.AddFD(fd
.Fd(), fd
.Size());
239 local_sha1
= string(SHA1
.Result());
241 if(local_sha1
== ServerSha1
)
243 // we have the same sha1 as the server
245 std::clog
<< "Package file is up-to-date" << std::endl
;
246 // set found to true, this will queue a pkgAcqIndexDiffs with
247 // a empty availabe_patches
253 std::clog
<< "SHA1-Current: " << ServerSha1
<< std::endl
;
255 // check the historie and see what patches we need
256 string history
= Tags
.FindS("SHA1-History");
257 std::stringstream
hist(history
);
258 while(hist
>> d
.sha1
>> size
>> d
.file
)
260 d
.size
= atoi(size
.c_str());
261 // read until the first match is found
262 if(d
.sha1
== local_sha1
)
264 // from that point on, we probably need all diffs
268 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
269 available_patches
.push_back(d
);
274 // we have something, queue the next diff
278 int last_space
= Description
.rfind(" ");
279 if(last_space
!= string::npos
)
280 Description
.erase(last_space
, Description
.size()-last_space
);
281 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
282 ExpectedMD5
, available_patches
);
290 // Nothing found, report and return false
291 // Failing here is ok, if we return false later, the full
292 // IndexFile is queued
294 std::clog
<< "Can't find a patch in the index file" << std::endl
;
298 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
301 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
302 << "Falling back to normal index file aquire" << std::endl
;
304 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
312 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
,
313 pkgAcquire::MethodConfig
*Cnf
)
316 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
318 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
321 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
323 // sucess in downloading the index
325 FinalFile
+= string(".IndexDiff");
327 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
329 Rename(DestFile
,FinalFile
);
330 chmod(FinalFile
.c_str(),0644);
331 DestFile
= FinalFile
;
333 if(!ParseDiffIndex(DestFile
))
334 return Failed("", NULL
);
344 // AcqIndexDiffs::AcqIndexDiffs - Constructor
345 // ---------------------------------------------------------------------
346 /* The package diff is added to the queue. one object is constructed
347 * for each diff and the index
349 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
350 string URI
,string URIDesc
,string ShortDesc
,
351 string ExpectedMD5
, vector
<DiffInfo
> diffs
)
352 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
),
353 available_patches(diffs
)
356 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
357 DestFile
+= URItoFileName(URI
);
359 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
361 Description
= URIDesc
;
363 Desc
.ShortDesc
= ShortDesc
;
365 if(available_patches
.size() == 0)
367 // we are done (yeah!)
373 State
= StateFetchDiff
;
379 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
382 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
383 << "Falling back to normal index file aquire" << std::endl
;
384 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
390 // helper that cleans the item out of the fetcher queue
391 void pkgAcqIndexDiffs::Finish(bool allDone
)
393 // we restore the original name, this is required, otherwise
394 // the file will be cleaned
397 DestFile
= _config
->FindDir("Dir::State::lists");
398 DestFile
+= URItoFileName(RealURI
);
400 // do the final md5sum checking
402 FileFd
Fd(DestFile
, FileFd::ReadOnly
);
403 sum
.AddFD(Fd
.Fd(), Fd
.Size());
405 string MD5
= (string
)sum
.Result();
407 if (!ExpectedMD5
.empty() && MD5
!= ExpectedMD5
)
409 Status
= StatAuthError
;
410 ErrorText
= _("MD5Sum mismatch");
411 Rename(DestFile
,DestFile
+ ".FAILED");
416 // this is for the "real" finish
421 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
426 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
435 bool pkgAcqIndexDiffs::QueueNextDiff()
438 // calc sha1 of the just patched file
439 string FinalFile
= _config
->FindDir("Dir::State::lists");
440 FinalFile
+= URItoFileName(RealURI
);
442 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
444 SHA1
.AddFD(fd
.Fd(), fd
.Size());
445 string local_sha1
= string(SHA1
.Result());
447 std::clog
<< "QueueNextDiff: "
448 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
450 // remove all patches until the next matching patch is found
451 // this requires the Index file to be ordered
452 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
453 available_patches
.size() > 0 &&
454 I
!= available_patches
.end() &&
455 (*I
).sha1
!= local_sha1
;
458 available_patches
.erase(I
);
461 // error checking and falling back if no patch was found
462 if(available_patches
.size() == 0)
468 // queue the right diff
469 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
470 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
472 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
473 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
476 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
485 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
,
486 pkgAcquire::MethodConfig
*Cnf
)
489 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
491 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
494 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
496 // sucess in downloading a diff, enter ApplyDiff state
497 if(State
== StateFetchDiff
)
501 std::clog
<< "Sending to gzip method: " << FinalFile
<< std::endl
;
503 string FileName
= LookupTag(Message
,"Filename");
504 State
= StateUnzipDiff
;
506 Desc
.URI
= "gzip:" + FileName
;
507 DestFile
+= ".decomp";
513 // sucess in downloading a diff, enter ApplyDiff state
514 if(State
== StateUnzipDiff
)
517 // rred excepts the patch as $FinalFile.ed
518 Rename(DestFile
,FinalFile
+".ed");
521 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
523 State
= StateApplyDiff
;
525 Desc
.URI
= "rred:" + FinalFile
;
532 // success in download/apply a diff, queue next (if needed)
533 if(State
== StateApplyDiff
)
535 // remove the just applied patch
536 available_patches
.erase(available_patches
.begin());
541 std::clog
<< "Moving patched file in place: " << std::endl
542 << DestFile
<< " -> " << FinalFile
<< std::endl
;
544 Rename(DestFile
,FinalFile
);
545 chmod(FinalFile
.c_str(),0644);
547 // see if there is more to download
548 if(available_patches
.size() > 0) {
549 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
550 ExpectedMD5
, available_patches
);
558 // AcqIndex::AcqIndex - Constructor /*{{{*/
559 // ---------------------------------------------------------------------
560 /* The package file is added to the queue and a second class is
561 instantiated to fetch the revision file */
562 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
563 string URI
,string URIDesc
,string ShortDesc
,
564 string ExpectedMD5
, string comprExt
)
565 : Item(Owner
), RealURI(URI
), ExpectedMD5(ExpectedMD5
)
567 Decompression
= false;
570 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
571 DestFile
+= URItoFileName(URI
);
575 // autoselect the compression method
576 if(FileExists("/bin/bzip2"))
577 CompressionExtension
= ".bz2";
579 CompressionExtension
= ".gz";
581 CompressionExtension
= comprExt
;
583 Desc
.URI
= URI
+ CompressionExtension
;
585 Desc
.Description
= URIDesc
;
587 Desc
.ShortDesc
= ShortDesc
;
592 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
593 // ---------------------------------------------------------------------
594 /* The only header we use is the last-modified header. */
595 string
pkgAcqIndex::Custom600Headers()
597 string Final
= _config
->FindDir("Dir::State::lists");
598 Final
+= URItoFileName(RealURI
);
601 if (stat(Final
.c_str(),&Buf
) != 0)
602 return "\nIndex-File: true";
604 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
608 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
610 // no .bz2 found, retry with .gz
611 if(Desc
.URI
.substr(Desc
.URI
.size()-3) == "bz2") {
612 Desc
.URI
= Desc
.URI
.substr(0,Desc
.URI
.size()-3) + "gz";
614 // retry with a gzip one
615 new pkgAcqIndex(Owner
, RealURI
, Desc
.Description
,Desc
.ShortDesc
,
616 ExpectedMD5
, string(".gz"));
624 Item::Failed(Message
,Cnf
);
628 // AcqIndex::Done - Finished a fetch /*{{{*/
629 // ---------------------------------------------------------------------
630 /* This goes through a number of states.. On the initial fetch the
631 method could possibly return an alternate filename which points
632 to the uncompressed version of the file. If this is so the file
633 is copied into the partial directory. In all other cases the file
634 is decompressed with a gzip uri. */
635 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string MD5
,
636 pkgAcquire::MethodConfig
*Cfg
)
638 Item::Done(Message
,Size
,MD5
,Cfg
);
640 if (Decompression
== true)
642 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
644 std::cerr
<< std::endl
<< RealURI
<< ": Computed MD5: " << MD5
;
645 std::cerr
<< " Expected MD5: " << ExpectedMD5
<< std::endl
;
651 FileFd
Fd(DestFile
, FileFd::ReadOnly
);
652 sum
.AddFD(Fd
.Fd(), Fd
.Size());
654 MD5
= (string
)sum
.Result();
657 if (!ExpectedMD5
.empty() && MD5
!= ExpectedMD5
)
659 Status
= StatAuthError
;
660 ErrorText
= _("MD5Sum mismatch");
661 Rename(DestFile
,DestFile
+ ".FAILED");
664 // Done, move it into position
665 string FinalFile
= _config
->FindDir("Dir::State::lists");
666 FinalFile
+= URItoFileName(RealURI
);
667 Rename(DestFile
,FinalFile
);
668 chmod(FinalFile
.c_str(),0644);
670 /* We restore the original name to DestFile so that the clean operation
672 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
673 DestFile
+= URItoFileName(RealURI
);
675 // Remove the compressed version.
677 unlink(DestFile
.c_str());
684 // Handle the unzipd case
685 string FileName
= LookupTag(Message
,"Alt-Filename");
686 if (FileName
.empty() == false)
688 // The files timestamp matches
689 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
692 Decompression
= true;
694 DestFile
+= ".decomp";
695 Desc
.URI
= "copy:" + FileName
;
701 FileName
= LookupTag(Message
,"Filename");
702 if (FileName
.empty() == true)
705 ErrorText
= "Method gave a blank filename";
708 // The files timestamp matches
709 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
712 if (FileName
== DestFile
)
717 string compExt
= Desc
.URI
.substr(Desc
.URI
.size()-3);
720 decompProg
= "bzip2";
721 else if(compExt
== ".gz")
724 _error
->Error("Unsupported extension: %s", compExt
.c_str());
728 Decompression
= true;
729 DestFile
+= ".decomp";
730 Desc
.URI
= string(decompProg
) + ":" + FileName
;
735 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
736 string URI
,string URIDesc
,string ShortDesc
,
737 string MetaIndexURI
, string MetaIndexURIDesc
,
738 string MetaIndexShortDesc
,
739 const vector
<IndexTarget
*>* IndexTargets
,
740 indexRecords
* MetaIndexParser
) :
741 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
742 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
743 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
745 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
746 DestFile
+= URItoFileName(URI
);
748 // remove any partial downloaded sig-file. it may confuse proxies
749 // and is too small to warrant a partial download anyway
750 unlink(DestFile
.c_str());
753 Desc
.Description
= URIDesc
;
755 Desc
.ShortDesc
= ShortDesc
;
759 string Final
= _config
->FindDir("Dir::State::lists");
760 Final
+= URItoFileName(RealURI
);
762 if (stat(Final
.c_str(),&Buf
) == 0)
764 // File was already in place. It needs to be re-verified
765 // because Release might have changed, so Move it into partial
766 Rename(Final
,DestFile
);
772 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
773 // ---------------------------------------------------------------------
774 /* The only header we use is the last-modified header. */
775 string
pkgAcqMetaSig::Custom600Headers()
778 if (stat(DestFile
.c_str(),&Buf
) != 0)
779 return "\nIndex-File: true";
781 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
784 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
785 pkgAcquire::MethodConfig
*Cfg
)
787 Item::Done(Message
,Size
,MD5
,Cfg
);
789 string FileName
= LookupTag(Message
,"Filename");
790 if (FileName
.empty() == true)
793 ErrorText
= "Method gave a blank filename";
797 if (FileName
!= DestFile
)
799 // We have to copy it into place
801 Desc
.URI
= "copy:" + FileName
;
808 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
809 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
810 DestFile
, IndexTargets
, MetaIndexParser
);
814 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
817 // if we get a network error we fail gracefully
818 if(LookupTag(Message
,"FailReason") == "Timeout" ||
819 LookupTag(Message
,"FailReason") == "TmpResolveFailure" ||
820 LookupTag(Message
,"FailReason") == "ConnectionRefused") {
821 Item::Failed(Message
,Cnf
);
825 // Delete any existing sigfile when the acquire failed
826 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
827 unlink(Final
.c_str());
829 // queue a pkgAcqMetaIndex with no sigfile
830 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
831 "", IndexTargets
, MetaIndexParser
);
833 if (Cnf
->LocalOnly
== true ||
834 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
843 Item::Failed(Message
,Cnf
);
846 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
,
847 string URI
,string URIDesc
,string ShortDesc
,
849 const vector
<struct IndexTarget
*>* IndexTargets
,
850 indexRecords
* MetaIndexParser
) :
851 Item(Owner
), RealURI(URI
), SigFile(SigFile
), AuthPass(false),
852 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
), IMSHit(false)
854 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
855 DestFile
+= URItoFileName(URI
);
858 Desc
.Description
= URIDesc
;
860 Desc
.ShortDesc
= ShortDesc
;
867 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
868 // ---------------------------------------------------------------------
869 /* The only header we use is the last-modified header. */
870 string
pkgAcqMetaIndex::Custom600Headers()
872 string Final
= _config
->FindDir("Dir::State::lists");
873 Final
+= URItoFileName(RealURI
);
876 if (stat(Final
.c_str(),&Buf
) != 0)
877 return "\nIndex-File: true";
879 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
882 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string MD5
,
883 pkgAcquire::MethodConfig
*Cfg
)
885 Item::Done(Message
,Size
,MD5
,Cfg
);
887 // MetaIndexes are done in two passes: one to download the
888 // metaindex with an appropriate method, and a second to verify it
889 // with the gpgv method
891 if (AuthPass
== true)
897 RetrievalDone(Message
);
899 // Still more retrieving to do
904 // There was no signature file, so we are finished. Download
905 // the indexes without verification.
910 // There was a signature file, so pass it to gpgv for
913 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
914 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
915 << SigFile
<< "," << DestFile
<< ")\n";
917 Desc
.URI
= "gpgv:" + SigFile
;
924 void pkgAcqMetaIndex::RetrievalDone(string Message
)
926 // We have just finished downloading a Release file (it is not
929 string FileName
= LookupTag(Message
,"Filename");
930 if (FileName
.empty() == true)
933 ErrorText
= "Method gave a blank filename";
937 if (FileName
!= DestFile
)
940 Desc
.URI
= "copy:" + FileName
;
945 // see if the download was a IMSHit
946 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
950 string FinalFile
= _config
->FindDir("Dir::State::lists");
951 FinalFile
+= URItoFileName(RealURI
);
953 // The files timestamp matches
954 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == false)
956 // Move it into position
957 Rename(DestFile
,FinalFile
);
959 chmod(FinalFile
.c_str(),0644);
960 DestFile
= FinalFile
;
963 void pkgAcqMetaIndex::AuthDone(string Message
)
965 // At this point, the gpgv method has succeeded, so there is a
966 // valid signature from a key in the trusted keyring. We
967 // perform additional verification of its contents, and use them
968 // to verify the indexes we are about to download
970 if (!MetaIndexParser
->Load(DestFile
))
972 Status
= StatAuthError
;
973 ErrorText
= MetaIndexParser
->ErrorText
;
977 if (!VerifyVendor(Message
))
982 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
983 std::cerr
<< "Signature verification succeeded: "
984 << DestFile
<< std::endl
;
986 // Download further indexes with verification
989 // Done, move signature file into position
991 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
992 URItoFileName(RealURI
) + ".gpg";
993 Rename(SigFile
,VerifiedSigFile
);
994 chmod(VerifiedSigFile
.c_str(),0644);
997 void pkgAcqMetaIndex::QueueIndexes(bool verify
)
999 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1000 Target
!= IndexTargets
->end();
1003 string ExpectedIndexMD5
;
1006 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1009 Status
= StatAuthError
;
1010 ErrorText
= "Unable to find expected entry "
1011 + (*Target
)->MetaKey
+ " in Meta-index file (malformed Release file?)";
1014 ExpectedIndexMD5
= Record
->MD5Hash
;
1015 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1017 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1018 std::cerr
<< "Expected MD5: " << ExpectedIndexMD5
<< std::endl
;
1020 if (ExpectedIndexMD5
.empty())
1022 Status
= StatAuthError
;
1023 ErrorText
= "Unable to find MD5 sum for "
1024 + (*Target
)->MetaKey
+ " in Meta-index file";
1029 // Queue Packages file (either diff or full packages files, depending
1030 // on the users option)
1031 if(_config
->FindB("Acquire::PDiffs",true) == true)
1032 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1033 (*Target
)->ShortDesc
, ExpectedIndexMD5
);
1035 new pkgAcqIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1036 (*Target
)->ShortDesc
, ExpectedIndexMD5
);
1040 bool pkgAcqMetaIndex::VerifyVendor(string Message
)
1042 // // Maybe this should be made available from above so we don't have
1043 // // to read and parse it every time?
1044 // pkgVendorList List;
1045 // List.ReadMainList();
1047 // const Vendor* Vndr = NULL;
1048 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1050 // string::size_type pos = (*I).find("VALIDSIG ");
1051 // if (_config->FindB("Debug::Vendor", false))
1052 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1054 // if (pos != std::string::npos)
1056 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1057 // if (_config->FindB("Debug::Vendor", false))
1058 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1060 // Vndr = List.FindVendor(Fingerprint) != "";
1061 // if (Vndr != NULL);
1065 string::size_type pos
;
1067 // check for missing sigs (that where not fatal because otherwise we had
1070 string msg
= _("There is no public key available for the "
1071 "following key IDs:\n");
1072 pos
= Message
.find("NO_PUBKEY ");
1073 if (pos
!= std::string::npos
)
1075 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1076 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1077 missingkeys
+= (Fingerprint
);
1079 if(!missingkeys
.empty())
1080 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1082 string Transformed
= MetaIndexParser
->GetExpectedDist();
1084 if (Transformed
== "../project/experimental")
1086 Transformed
= "experimental";
1089 pos
= Transformed
.rfind('/');
1090 if (pos
!= string::npos
)
1092 Transformed
= Transformed
.substr(0, pos
);
1095 if (Transformed
== ".")
1100 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1102 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1103 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1104 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1107 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1109 // This might become fatal one day
1110 // Status = StatAuthError;
1111 // ErrorText = "Conflicting distribution; expected "
1112 // + MetaIndexParser->GetExpectedDist() + " but got "
1113 // + MetaIndexParser->GetDist();
1115 if (!Transformed
.empty())
1117 _error
->Warning("Conflicting distribution: %s (expected %s but got %s)",
1118 Desc
.Description
.c_str(),
1119 Transformed
.c_str(),
1120 MetaIndexParser
->GetDist().c_str());
1127 // pkgAcqMetaIndex::Failed - no Release file present or no signature
1128 // file present /*{{{*/
1129 // ---------------------------------------------------------------------
1131 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1133 if (AuthPass
== true)
1135 // if we fail the authentication but got the file via a IMS-Hit
1136 // this means that the file wasn't downloaded and that it might be
1137 // just stale (server problem, proxy etc). we delete what we have
1138 // queue it again without i-m-s
1139 // alternatively we could just unlink the file and let the user try again
1145 unlink(DestFile
.c_str());
1147 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1148 DestFile
+= URItoFileName(RealURI
);
1154 // gpgv method failed
1155 _error
->Warning("GPG error: %s: %s",
1156 Desc
.Description
.c_str(),
1157 LookupTag(Message
,"Message").c_str());
1161 // No Release file was present, or verification failed, so fall
1162 // back to queueing Packages files without verification
1163 QueueIndexes(false);
1168 // AcqArchive::AcqArchive - Constructor /*{{{*/
1169 // ---------------------------------------------------------------------
1170 /* This just sets up the initial fetch environment and queues the first
1172 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1173 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1174 string
&StoreFilename
) :
1175 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1176 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1179 Retries
= _config
->FindI("Acquire::Retries",0);
1181 if (Version
.Arch() == 0)
1183 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1184 "This might mean you need to manually fix this package. "
1185 "(due to missing arch)"),
1186 Version
.ParentPkg().Name());
1190 /* We need to find a filename to determine the extension. We make the
1191 assumption here that all the available sources for this version share
1192 the same extension.. */
1193 // Skip not source sources, they do not have file fields.
1194 for (; Vf
.end() == false; Vf
++)
1196 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1201 // Does not really matter here.. we are going to fail out below
1202 if (Vf
.end() != true)
1204 // If this fails to get a file name we will bomb out below.
1205 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1206 if (_error
->PendingError() == true)
1209 // Generate the final file name as: package_version_arch.foo
1210 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1211 QuoteString(Version
.VerStr(),"_:") + '_' +
1212 QuoteString(Version
.Arch(),"_:.") +
1213 "." + flExtension(Parse
.FileName());
1216 // check if we have one trusted source for the package. if so, switch
1217 // to "TrustedOnly" mode
1218 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1220 pkgIndexFile
*Index
;
1221 if (Sources
->FindIndex(i
.File(),Index
) == false)
1223 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1225 std::cerr
<< "Checking index: " << Index
->Describe()
1226 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1228 if (Index
->IsTrusted()) {
1234 // "allow-unauthenticated" restores apts old fetching behaviour
1235 // that means that e.g. unauthenticated file:// uris are higher
1236 // priority than authenticated http:// uris
1237 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1241 if (QueueNext() == false && _error
->PendingError() == false)
1242 _error
->Error(_("I wasn't able to locate file for the %s package. "
1243 "This might mean you need to manually fix this package."),
1244 Version
.ParentPkg().Name());
1247 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1248 // ---------------------------------------------------------------------
1249 /* This queues the next available file version for download. It checks if
1250 the archive is already available in the cache and stashs the MD5 for
1252 bool pkgAcqArchive::QueueNext()
1254 for (; Vf
.end() == false; Vf
++)
1256 // Ignore not source sources
1257 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1260 // Try to cross match against the source list
1261 pkgIndexFile
*Index
;
1262 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1265 // only try to get a trusted package from another source if that source
1267 if(Trusted
&& !Index
->IsTrusted())
1270 // Grab the text package record
1271 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1272 if (_error
->PendingError() == true)
1275 string PkgFile
= Parse
.FileName();
1276 MD5
= Parse
.MD5Hash();
1277 if (PkgFile
.empty() == true)
1278 return _error
->Error(_("The package index files are corrupted. No Filename: "
1279 "field for package %s."),
1280 Version
.ParentPkg().Name());
1282 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1283 Desc
.Description
= Index
->ArchiveInfo(Version
);
1285 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1287 // See if we already have the file. (Legacy filenames)
1288 FileSize
= Version
->Size
;
1289 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1291 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1293 // Make sure the size matches
1294 if ((unsigned)Buf
.st_size
== Version
->Size
)
1299 StoreFilename
= DestFile
= FinalFile
;
1303 /* Hmm, we have a file and its size does not match, this means it is
1304 an old style mismatched arch */
1305 unlink(FinalFile
.c_str());
1308 // Check it again using the new style output filenames
1309 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1310 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1312 // Make sure the size matches
1313 if ((unsigned)Buf
.st_size
== Version
->Size
)
1318 StoreFilename
= DestFile
= FinalFile
;
1322 /* Hmm, we have a file and its size does not match, this shouldnt
1324 unlink(FinalFile
.c_str());
1327 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1329 // Check the destination file
1330 if (stat(DestFile
.c_str(),&Buf
) == 0)
1332 // Hmm, the partial file is too big, erase it
1333 if ((unsigned)Buf
.st_size
> Version
->Size
)
1334 unlink(DestFile
.c_str());
1336 PartialSize
= Buf
.st_size
;
1341 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1342 Desc
.Description
= Index
->ArchiveInfo(Version
);
1344 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1353 // AcqArchive::Done - Finished fetching /*{{{*/
1354 // ---------------------------------------------------------------------
1356 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string Md5Hash
,
1357 pkgAcquire::MethodConfig
*Cfg
)
1359 Item::Done(Message
,Size
,Md5Hash
,Cfg
);
1362 if (Size
!= Version
->Size
)
1365 ErrorText
= _("Size mismatch");
1370 if (Md5Hash
.empty() == false && MD5
.empty() == false)
1375 ErrorText
= _("MD5Sum mismatch");
1376 if(FileExists(DestFile
))
1377 Rename(DestFile
,DestFile
+ ".FAILED");
1382 // Grab the output filename
1383 string FileName
= LookupTag(Message
,"Filename");
1384 if (FileName
.empty() == true)
1387 ErrorText
= "Method gave a blank filename";
1393 // Reference filename
1394 if (FileName
!= DestFile
)
1396 StoreFilename
= DestFile
= FileName
;
1401 // Done, move it into position
1402 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1403 FinalFile
+= flNotDir(StoreFilename
);
1404 Rename(DestFile
,FinalFile
);
1406 StoreFilename
= DestFile
= FinalFile
;
1410 // AcqArchive::Failed - Failure handler /*{{{*/
1411 // ---------------------------------------------------------------------
1412 /* Here we try other sources */
1413 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1415 ErrorText
= LookupTag(Message
,"Message");
1417 /* We don't really want to retry on failed media swaps, this prevents
1418 that. An interesting observation is that permanent failures are not
1420 if (Cnf
->Removable
== true &&
1421 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1423 // Vf = Version.FileList();
1424 while (Vf
.end() == false) Vf
++;
1425 StoreFilename
= string();
1426 Item::Failed(Message
,Cnf
);
1430 if (QueueNext() == false)
1432 // This is the retry counter
1434 Cnf
->LocalOnly
== false &&
1435 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1438 Vf
= Version
.FileList();
1439 if (QueueNext() == true)
1443 StoreFilename
= string();
1444 Item::Failed(Message
,Cnf
);
1448 // AcqArchive::IsTrusted - Determine whether this archive comes from a
1449 // trusted source /*{{{*/
1450 // ---------------------------------------------------------------------
1451 bool pkgAcqArchive::IsTrusted()
1456 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1457 // ---------------------------------------------------------------------
1459 void pkgAcqArchive::Finished()
1461 if (Status
== pkgAcquire::Item::StatDone
&&
1464 StoreFilename
= string();
1468 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1469 // ---------------------------------------------------------------------
1470 /* The file is added to the queue */
1471 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string MD5
,
1472 unsigned long Size
,string Dsc
,string ShortDesc
,
1473 const string
&DestDir
, const string
&DestFilename
) :
1474 Item(Owner
), Md5Hash(MD5
)
1476 Retries
= _config
->FindI("Acquire::Retries",0);
1478 if(!DestFilename
.empty())
1479 DestFile
= DestFilename
;
1480 else if(!DestDir
.empty())
1481 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1483 DestFile
= flNotDir(URI
);
1487 Desc
.Description
= Dsc
;
1490 // Set the short description to the archive component
1491 Desc
.ShortDesc
= ShortDesc
;
1493 // Get the transfer sizes
1496 if (stat(DestFile
.c_str(),&Buf
) == 0)
1498 // Hmm, the partial file is too big, erase it
1499 if ((unsigned)Buf
.st_size
> Size
)
1500 unlink(DestFile
.c_str());
1502 PartialSize
= Buf
.st_size
;
1508 // AcqFile::Done - Item downloaded OK /*{{{*/
1509 // ---------------------------------------------------------------------
1511 void pkgAcqFile::Done(string Message
,unsigned long Size
,string MD5
,
1512 pkgAcquire::MethodConfig
*Cnf
)
1515 if (Md5Hash
.empty() == false && MD5
.empty() == false)
1520 ErrorText
= "MD5Sum mismatch";
1521 Rename(DestFile
,DestFile
+ ".FAILED");
1526 Item::Done(Message
,Size
,MD5
,Cnf
);
1528 string FileName
= LookupTag(Message
,"Filename");
1529 if (FileName
.empty() == true)
1532 ErrorText
= "Method gave a blank filename";
1538 // The files timestamp matches
1539 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1542 // We have to copy it into place
1543 if (FileName
!= DestFile
)
1546 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1547 Cnf
->Removable
== true)
1549 Desc
.URI
= "copy:" + FileName
;
1554 // Erase the file if it is a symlink so we can overwrite it
1556 if (lstat(DestFile
.c_str(),&St
) == 0)
1558 if (S_ISLNK(St
.st_mode
) != 0)
1559 unlink(DestFile
.c_str());
1563 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1565 ErrorText
= "Link to " + DestFile
+ " failure ";
1572 // AcqFile::Failed - Failure handler /*{{{*/
1573 // ---------------------------------------------------------------------
1574 /* Here we try other sources */
1575 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1577 ErrorText
= LookupTag(Message
,"Message");
1579 // This is the retry counter
1581 Cnf
->LocalOnly
== false &&
1582 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1589 Item::Failed(Message
,Cnf
);