1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
4 /* ######################################################################
6 Acquire Item - Item to acquire
8 Each item can download to exactly one file at a time. This means you
9 cannot create an item that fetches two uri's to two files at the same
10 time. The pkgAcqIndex class creates a second class upon instantiation
11 to fetch the other index files because of this.
13 ##################################################################### */
15 // Include Files /*{{{*/
16 #include <apt-pkg/acquire-item.h>
17 #include <apt-pkg/configuration.h>
18 #include <apt-pkg/aptconfiguration.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/vendorlist.h>
21 #include <apt-pkg/error.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/fileutl.h>
24 #include <apt-pkg/md5.h>
25 #include <apt-pkg/sha1.h>
26 #include <apt-pkg/tagfile.h>
41 // Acquire::Item::Item - Constructor /*{{{*/
42 // ---------------------------------------------------------------------
44 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
45 PartialSize(0), Mode(0), ID(0), Complete(false),
46 Local(false), QueueCounter(0)
52 // Acquire::Item::~Item - Destructor /*{{{*/
53 // ---------------------------------------------------------------------
55 pkgAcquire::Item::~Item()
60 // Acquire::Item::Failed - Item failed to download /*{{{*/
61 // ---------------------------------------------------------------------
62 /* We return to an idle state if there are still other queues that could
64 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
67 ErrorText
= LookupTag(Message
,"Message");
68 UsedMirror
= LookupTag(Message
,"UsedMirror");
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)
86 // report mirror failure back to LP if we actually use a mirror
87 string FailReason
= LookupTag(Message
, "FailReason");
88 if(FailReason
.size() != 0)
89 ReportMirrorFailure(FailReason
);
91 ReportMirrorFailure(ErrorText
);
94 // Acquire::Item::Start - Item has begun to download /*{{{*/
95 // ---------------------------------------------------------------------
96 /* Stash status and the file size. Note that setting Complete means
97 sub-phases of the acquire process such as decompresion are operating */
98 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long Size
)
100 Status
= StatFetching
;
101 if (FileSize
== 0 && Complete
== false)
105 // Acquire::Item::Done - Item downloaded OK /*{{{*/
106 // ---------------------------------------------------------------------
108 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string Hash
,
109 pkgAcquire::MethodConfig
*Cnf
)
111 // We just downloaded something..
112 string FileName
= LookupTag(Message
,"Filename");
113 UsedMirror
= LookupTag(Message
,"UsedMirror");
114 if (Complete
== false && !Local
&& FileName
== DestFile
)
117 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
123 ErrorText
= string();
124 Owner
->Dequeue(this);
127 // Acquire::Item::Rename - Rename a file /*{{{*/
128 // ---------------------------------------------------------------------
129 /* This helper function is used by alot of item methods as thier final
131 void pkgAcquire::Item::Rename(string From
,string To
)
133 if (rename(From
.c_str(),To
.c_str()) != 0)
136 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
137 From
.c_str(),To
.c_str());
143 // Acquire::Item::ReportMirrorFailure /*{{{*/
144 // ---------------------------------------------------------------------
145 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
147 // we only act if a mirror was used at all
148 if(UsedMirror
.empty())
151 std::cerr
<< "\nReportMirrorFailure: "
153 << " Uri: " << DescURI()
155 << FailCode
<< std::endl
;
157 const char *Args
[40];
159 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
160 "/usr/lib/apt/apt-report-mirror-failure");
161 if(!FileExists(report
))
163 Args
[i
++] = report
.c_str();
164 Args
[i
++] = UsedMirror
.c_str();
165 Args
[i
++] = DescURI().c_str();
166 Args
[i
++] = FailCode
.c_str();
168 pid_t pid
= ExecFork();
171 _error
->Error("ReportMirrorFailure Fork failed");
176 execvp(Args
[0], (char**)Args
);
177 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
180 if(!ExecWait(pid
, "report-mirror-failure"))
182 _error
->Warning("Couldn't report problem to '%s'",
183 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
187 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
188 // ---------------------------------------------------------------------
189 /* Get the Index file first and see if there are languages available
190 * If so, create a pkgAcqIndexTrans for the found language(s).
192 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
193 string
const &URIDesc
, string
const &ShortDesc
,
194 HashString
const &ExpectedHash
)
195 : Item(Owner
), ExpectedHash(ExpectedHash
)
197 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
199 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
200 DestFile
+= URItoFileName(URI
);
203 Desc
.Description
= URIDesc
;
205 Desc
.ShortDesc
= ShortDesc
;
210 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
213 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
214 // ---------------------------------------------------------------------
215 /* The only header we use is the last-modified header. */
216 string
pkgAcqSubIndex::Custom600Headers()
218 string Final
= _config
->FindDir("Dir::State::lists");
219 Final
+= URItoFileName(Desc
.URI
);
222 if (stat(Final
.c_str(),&Buf
) != 0)
223 return "\nIndex-File: true\nFail-Ignore: true\n";
224 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
227 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
230 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< std::endl
;
236 // No good Index is provided, so try guessing
237 std::vector
<std::string
> langs
= APT::Configuration::getLanguages(true);
238 for (std::vector
<std::string
>::const_iterator l
= langs
.begin();
239 l
!= langs
.end(); ++l
)
241 if (*l
== "none") continue;
242 string
const file
= "Translation-" + *l
;
243 new pkgAcqIndexTrans(Owner
, Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
),
244 Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
),
249 void pkgAcqSubIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
250 pkgAcquire::MethodConfig
*Cnf
)
253 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
255 string FileName
= LookupTag(Message
,"Filename");
256 if (FileName
.empty() == true)
259 ErrorText
= "Method gave a blank filename";
263 if (FileName
!= DestFile
)
266 Desc
.URI
= "copy:" + FileName
;
271 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
273 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
275 // sucess in downloading the index
278 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
279 Rename(DestFile
,FinalFile
);
280 chmod(FinalFile
.c_str(),0644);
281 DestFile
= FinalFile
;
283 if(ParseIndex(DestFile
) == false)
284 return Failed("", NULL
);
292 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
294 indexRecords SubIndexParser
;
295 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
298 std::vector
<std::string
> lang
= APT::Configuration::getLanguages(true);
299 for (std::vector
<std::string
>::const_iterator l
= lang
.begin();
300 l
!= lang
.end(); ++l
)
305 string file
= "Translation-" + *l
;
306 indexRecords::checkSum
const *Record
= SubIndexParser
.Lookup(file
);
310 // FIXME: the Index file provided by debian currently only includes bz2 records
311 Record
= SubIndexParser
.Lookup(file
+ ".bz2");
317 expected
= Record
->Hash
;
318 if (expected
.empty() == true)
323 target
.Description
= Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
);
324 target
.MetaKey
= file
;
325 target
.ShortDesc
= file
;
326 target
.URI
= Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
);
327 new pkgAcqIndexTrans(Owner
, &target
, expected
, &SubIndexParser
);
332 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
333 // ---------------------------------------------------------------------
334 /* Get the DiffIndex file first and see if there are patches availabe
335 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
336 * patches. If anything goes wrong in that process, it will fall back to
337 * the original packages file
339 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
340 string URI
,string URIDesc
,string ShortDesc
,
341 HashString ExpectedHash
)
342 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
346 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
348 Desc
.Description
= URIDesc
+ "/DiffIndex";
350 Desc
.ShortDesc
= ShortDesc
;
351 Desc
.URI
= URI
+ ".diff/Index";
353 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
354 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
357 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
359 // look for the current package file
360 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
361 CurrentPackagesFile
+= URItoFileName(RealURI
);
363 // FIXME: this file:/ check is a hack to prevent fetching
364 // from local sources. this is really silly, and
365 // should be fixed cleanly as soon as possible
366 if(!FileExists(CurrentPackagesFile
) ||
367 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
369 // we don't have a pkg file or we don't want to queue
371 std::clog
<< "No index file, local or canceld by user" << std::endl
;
377 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
378 << CurrentPackagesFile
<< std::endl
;
384 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
385 // ---------------------------------------------------------------------
386 /* The only header we use is the last-modified header. */
387 string
pkgAcqDiffIndex::Custom600Headers()
389 string Final
= _config
->FindDir("Dir::State::lists");
390 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
393 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
396 if (stat(Final
.c_str(),&Buf
) != 0)
397 return "\nIndex-File: true";
399 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
402 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
405 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
410 vector
<DiffInfo
> available_patches
;
412 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
414 if (_error
->PendingError() == true)
417 if(TF
.Step(Tags
) == true)
423 string
const tmp
= Tags
.FindS("SHA1-Current");
424 std::stringstream
ss(tmp
);
425 ss
>> ServerSha1
>> size
;
426 unsigned long const ServerSize
= atol(size
.c_str());
428 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
430 SHA1
.AddFD(fd
.Fd(), fd
.Size());
431 string
const local_sha1
= SHA1
.Result();
433 if(local_sha1
== ServerSha1
)
435 // we have the same sha1 as the server
437 std::clog
<< "Package file is up-to-date" << std::endl
;
438 // set found to true, this will queue a pkgAcqIndexDiffs with
439 // a empty availabe_patches
445 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
447 // check the historie and see what patches we need
448 string
const history
= Tags
.FindS("SHA1-History");
449 std::stringstream
hist(history
);
450 while(hist
>> d
.sha1
>> size
>> d
.file
)
452 // read until the first match is found
453 // from that point on, we probably need all diffs
454 if(d
.sha1
== local_sha1
)
456 else if (found
== false)
460 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
461 available_patches
.push_back(d
);
464 if (available_patches
.empty() == false)
466 // patching with too many files is rather slow compared to a fast download
467 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
468 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
471 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
472 << ") so fallback to complete download" << std::endl
;
476 // see if the patches are too big
477 found
= false; // it was true and it will be true again at the end
478 d
= *available_patches
.begin();
479 string
const firstPatch
= d
.file
;
480 unsigned long patchesSize
= 0;
481 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
482 while(patches
>> d
.sha1
>> size
>> d
.file
)
484 if (firstPatch
== d
.file
)
486 else if (found
== false)
489 patchesSize
+= atol(size
.c_str());
491 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
492 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
495 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
496 << ") so fallback to complete download" << std::endl
;
502 // we have something, queue the next diff
506 string::size_type
const last_space
= Description
.rfind(" ");
507 if(last_space
!= string::npos
)
508 Description
.erase(last_space
, Description
.size()-last_space
);
509 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
510 ExpectedHash
, ServerSha1
, available_patches
);
518 // Nothing found, report and return false
519 // Failing here is ok, if we return false later, the full
520 // IndexFile is queued
522 std::clog
<< "Can't find a patch in the index file" << std::endl
;
526 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
529 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
530 << "Falling back to normal index file aquire" << std::endl
;
532 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
540 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
541 pkgAcquire::MethodConfig
*Cnf
)
544 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
546 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
549 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
551 // sucess in downloading the index
553 FinalFile
+= string(".IndexDiff");
555 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
557 Rename(DestFile
,FinalFile
);
558 chmod(FinalFile
.c_str(),0644);
559 DestFile
= FinalFile
;
561 if(!ParseDiffIndex(DestFile
))
562 return Failed("", NULL
);
570 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
571 // ---------------------------------------------------------------------
572 /* The package diff is added to the queue. one object is constructed
573 * for each diff and the index
575 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
576 string URI
,string URIDesc
,string ShortDesc
,
577 HashString ExpectedHash
,
579 vector
<DiffInfo
> diffs
)
580 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
581 available_patches(diffs
), ServerSha1(ServerSha1
)
584 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
585 DestFile
+= URItoFileName(URI
);
587 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
589 Description
= URIDesc
;
591 Desc
.ShortDesc
= ShortDesc
;
593 if(available_patches
.size() == 0)
595 // we are done (yeah!)
601 State
= StateFetchDiff
;
606 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
609 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
610 << "Falling back to normal index file aquire" << std::endl
;
611 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
616 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
617 void pkgAcqIndexDiffs::Finish(bool allDone
)
619 // we restore the original name, this is required, otherwise
620 // the file will be cleaned
623 DestFile
= _config
->FindDir("Dir::State::lists");
624 DestFile
+= URItoFileName(RealURI
);
626 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
628 Status
= StatAuthError
;
629 ErrorText
= _("MD5Sum mismatch");
630 Rename(DestFile
,DestFile
+ ".FAILED");
635 // this is for the "real" finish
640 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
645 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
652 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
655 // calc sha1 of the just patched file
656 string FinalFile
= _config
->FindDir("Dir::State::lists");
657 FinalFile
+= URItoFileName(RealURI
);
659 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
661 SHA1
.AddFD(fd
.Fd(), fd
.Size());
662 string local_sha1
= string(SHA1
.Result());
664 std::clog
<< "QueueNextDiff: "
665 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
667 // final file reached before all patches are applied
668 if(local_sha1
== ServerSha1
)
674 // remove all patches until the next matching patch is found
675 // this requires the Index file to be ordered
676 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
677 available_patches
.size() > 0 &&
678 I
!= available_patches
.end() &&
679 (*I
).sha1
!= local_sha1
;
682 available_patches
.erase(I
);
685 // error checking and falling back if no patch was found
686 if(available_patches
.size() == 0)
692 // queue the right diff
693 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
694 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
695 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
696 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
699 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
706 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
707 pkgAcquire::MethodConfig
*Cnf
)
710 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
712 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
715 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
717 // sucess in downloading a diff, enter ApplyDiff state
718 if(State
== StateFetchDiff
)
721 // rred excepts the patch as $FinalFile.ed
722 Rename(DestFile
,FinalFile
+".ed");
725 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
727 State
= StateApplyDiff
;
729 Desc
.URI
= "rred:" + FinalFile
;
736 // success in download/apply a diff, queue next (if needed)
737 if(State
== StateApplyDiff
)
739 // remove the just applied patch
740 available_patches
.erase(available_patches
.begin());
745 std::clog
<< "Moving patched file in place: " << std::endl
746 << DestFile
<< " -> " << FinalFile
<< std::endl
;
748 Rename(DestFile
,FinalFile
);
749 chmod(FinalFile
.c_str(),0644);
751 // see if there is more to download
752 if(available_patches
.size() > 0) {
753 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
754 ExpectedHash
, ServerSha1
, available_patches
);
761 // AcqIndex::AcqIndex - Constructor /*{{{*/
762 // ---------------------------------------------------------------------
763 /* The package file is added to the queue and a second class is
764 instantiated to fetch the revision file */
765 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
766 string URI
,string URIDesc
,string ShortDesc
,
767 HashString ExpectedHash
, string comprExt
)
768 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
770 if(comprExt
.empty() == true)
772 // autoselect the compression method
773 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
774 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
775 comprExt
.append(*t
).append(" ");
776 if (comprExt
.empty() == false)
777 comprExt
.erase(comprExt
.end()-1);
779 CompressionExtension
= comprExt
;
781 Init(URI
, URIDesc
, ShortDesc
);
783 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
784 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
785 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
787 // autoselect the compression method
788 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
789 CompressionExtension
= "";
790 if (ExpectedHash
.empty() == false)
792 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
793 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
794 CompressionExtension
.append(*t
).append(" ");
798 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
799 CompressionExtension
.append(*t
).append(" ");
801 if (CompressionExtension
.empty() == false)
802 CompressionExtension
.erase(CompressionExtension
.end()-1);
804 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
807 // AcqIndex::Init - defered Constructor /*{{{*/
808 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
809 Decompression
= false;
812 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
813 DestFile
+= URItoFileName(URI
);
815 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
816 if (comprExt
== "uncompressed")
819 Desc
.URI
= URI
+ '.' + comprExt
;
821 Desc
.Description
= URIDesc
;
823 Desc
.ShortDesc
= ShortDesc
;
828 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
829 // ---------------------------------------------------------------------
830 /* The only header we use is the last-modified header. */
831 string
pkgAcqIndex::Custom600Headers()
833 string Final
= _config
->FindDir("Dir::State::lists");
834 Final
+= URItoFileName(RealURI
);
835 if (_config
->FindB("Acquire::GzipIndexes",false))
838 string msg
= "\nIndex-File: true";
839 // FIXME: this really should use "IndexTarget::IsOptional()" but that
840 // seems to be difficult without breaking ABI
841 if (ShortDesc().find("Translation") != 0)
842 msg
+= "\nFail-Ignore: true";
844 if (stat(Final
.c_str(),&Buf
) != 0)
845 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
850 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
852 size_t const nextExt
= CompressionExtension
.find(' ');
853 if (nextExt
!= std::string::npos
)
855 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
856 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
860 // on decompression failure, remove bad versions in partial/
861 if (Decompression
&& Erase
) {
862 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
863 s
.append(URItoFileName(RealURI
));
867 Item::Failed(Message
,Cnf
);
870 // AcqIndex::Done - Finished a fetch /*{{{*/
871 // ---------------------------------------------------------------------
872 /* This goes through a number of states.. On the initial fetch the
873 method could possibly return an alternate filename which points
874 to the uncompressed version of the file. If this is so the file
875 is copied into the partial directory. In all other cases the file
876 is decompressed with a gzip uri. */
877 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string Hash
,
878 pkgAcquire::MethodConfig
*Cfg
)
880 Item::Done(Message
,Size
,Hash
,Cfg
);
882 if (Decompression
== true)
884 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
886 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
887 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
890 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
892 Status
= StatAuthError
;
893 ErrorText
= _("Hash Sum mismatch");
894 Rename(DestFile
,DestFile
+ ".FAILED");
895 ReportMirrorFailure("HashChecksumFailure");
898 // Done, move it into position
899 string FinalFile
= _config
->FindDir("Dir::State::lists");
900 FinalFile
+= URItoFileName(RealURI
);
901 Rename(DestFile
,FinalFile
);
902 chmod(FinalFile
.c_str(),0644);
904 /* We restore the original name to DestFile so that the clean operation
906 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
907 DestFile
+= URItoFileName(RealURI
);
909 // Remove the compressed version.
911 unlink(DestFile
.c_str());
918 // Handle the unzipd case
919 string FileName
= LookupTag(Message
,"Alt-Filename");
920 if (FileName
.empty() == false)
922 // The files timestamp matches
923 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
925 Decompression
= true;
927 DestFile
+= ".decomp";
928 Desc
.URI
= "copy:" + FileName
;
934 FileName
= LookupTag(Message
,"Filename");
935 if (FileName
.empty() == true)
938 ErrorText
= "Method gave a blank filename";
941 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
943 // The files timestamp matches
944 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
945 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
946 // Update DestFile for .gz suffix so that the clean operation keeps it
951 if (FileName
== DestFile
)
958 // If we enable compressed indexes and already have gzip, keep it
959 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
960 string FinalFile
= _config
->FindDir("Dir::State::lists");
961 FinalFile
+= URItoFileName(RealURI
) + ".gz";
962 Rename(DestFile
,FinalFile
);
963 chmod(FinalFile
.c_str(),0644);
965 // Update DestFile for .gz suffix so that the clean operation keeps it
966 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
967 DestFile
+= URItoFileName(RealURI
) + ".gz";
971 // get the binary name for your used compression type
972 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
973 if(decompProg
.empty() == false);
974 else if(compExt
== "uncompressed")
977 _error
->Error("Unsupported extension: %s", compExt
.c_str());
981 Decompression
= true;
982 DestFile
+= ".decomp";
983 Desc
.URI
= decompProg
+ ":" + FileName
;
985 Mode
= decompProg
.c_str();
988 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
989 // ---------------------------------------------------------------------
990 /* The Translation file is added to the queue */
991 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
992 string URI
,string URIDesc
,string ShortDesc
)
993 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
996 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
997 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
998 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1002 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1003 // ---------------------------------------------------------------------
1004 string
pkgAcqIndexTrans::Custom600Headers()
1006 string Final
= _config
->FindDir("Dir::State::lists");
1007 Final
+= URItoFileName(RealURI
);
1010 if (stat(Final
.c_str(),&Buf
) != 0)
1011 return "\nFail-Ignore: true\nIndex-File: true";
1012 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1015 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1016 // ---------------------------------------------------------------------
1018 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1020 size_t const nextExt
= CompressionExtension
.find(' ');
1021 if (nextExt
!= std::string::npos
)
1023 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1024 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1029 if (Cnf
->LocalOnly
== true ||
1030 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1039 Item::Failed(Message
,Cnf
);
1042 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1043 string URI
,string URIDesc
,string ShortDesc
,
1044 string MetaIndexURI
, string MetaIndexURIDesc
,
1045 string MetaIndexShortDesc
,
1046 const vector
<IndexTarget
*>* IndexTargets
,
1047 indexRecords
* MetaIndexParser
) :
1048 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1049 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1050 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1052 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1053 DestFile
+= URItoFileName(URI
);
1055 // remove any partial downloaded sig-file in partial/.
1056 // it may confuse proxies and is too small to warrant a
1057 // partial download anyway
1058 unlink(DestFile
.c_str());
1061 Desc
.Description
= URIDesc
;
1063 Desc
.ShortDesc
= ShortDesc
;
1066 string Final
= _config
->FindDir("Dir::State::lists");
1067 Final
+= URItoFileName(RealURI
);
1069 if (stat(Final
.c_str(),&Buf
) == 0)
1071 // File was already in place. It needs to be re-downloaded/verified
1072 // because Release might have changed, we do give it a differnt
1073 // name than DestFile because otherwise the http method will
1074 // send If-Range requests and there are too many broken servers
1075 // out there that do not understand them
1076 LastGoodSig
= DestFile
+".reverify";
1077 Rename(Final
,LastGoodSig
);
1083 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1084 // ---------------------------------------------------------------------
1085 /* The only header we use is the last-modified header. */
1086 string
pkgAcqMetaSig::Custom600Headers()
1089 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1090 return "\nIndex-File: true";
1092 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1095 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
1096 pkgAcquire::MethodConfig
*Cfg
)
1098 Item::Done(Message
,Size
,MD5
,Cfg
);
1100 string FileName
= LookupTag(Message
,"Filename");
1101 if (FileName
.empty() == true)
1104 ErrorText
= "Method gave a blank filename";
1108 if (FileName
!= DestFile
)
1110 // We have to copy it into place
1112 Desc
.URI
= "copy:" + FileName
;
1119 // put the last known good file back on i-m-s hit (it will
1120 // be re-verified again)
1121 // Else do nothing, we have the new file in DestFile then
1122 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1123 Rename(LastGoodSig
, DestFile
);
1125 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1126 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1127 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1132 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1134 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1136 // if we get a network error we fail gracefully
1137 if(Status
== StatTransientNetworkError
)
1139 Item::Failed(Message
,Cnf
);
1140 // move the sigfile back on transient network failures
1141 if(FileExists(LastGoodSig
))
1142 Rename(LastGoodSig
,Final
);
1144 // set the status back to , Item::Failed likes to reset it
1145 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1149 // Delete any existing sigfile when the acquire failed
1150 unlink(Final
.c_str());
1152 // queue a pkgAcqMetaIndex with no sigfile
1153 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1154 "", IndexTargets
, MetaIndexParser
);
1156 if (Cnf
->LocalOnly
== true ||
1157 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1166 Item::Failed(Message
,Cnf
);
1169 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1170 string URI
,string URIDesc
,string ShortDesc
,
1172 const vector
<struct IndexTarget
*>* IndexTargets
,
1173 indexRecords
* MetaIndexParser
) :
1174 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1175 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1177 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1178 DestFile
+= URItoFileName(URI
);
1181 Desc
.Description
= URIDesc
;
1183 Desc
.ShortDesc
= ShortDesc
;
1189 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1190 // ---------------------------------------------------------------------
1191 /* The only header we use is the last-modified header. */
1192 string
pkgAcqMetaIndex::Custom600Headers()
1194 string Final
= _config
->FindDir("Dir::State::lists");
1195 Final
+= URItoFileName(RealURI
);
1198 if (stat(Final
.c_str(),&Buf
) != 0)
1199 return "\nIndex-File: true";
1201 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1204 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string Hash
, /*{{{*/
1205 pkgAcquire::MethodConfig
*Cfg
)
1207 Item::Done(Message
,Size
,Hash
,Cfg
);
1209 // MetaIndexes are done in two passes: one to download the
1210 // metaindex with an appropriate method, and a second to verify it
1211 // with the gpgv method
1213 if (AuthPass
== true)
1217 // all cool, move Release file into place
1222 RetrievalDone(Message
);
1224 // Still more retrieving to do
1229 // There was no signature file, so we are finished. Download
1230 // the indexes without verification.
1231 QueueIndexes(false);
1235 // There was a signature file, so pass it to gpgv for
1238 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1239 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1240 << SigFile
<< "," << DestFile
<< ")\n";
1242 Desc
.URI
= "gpgv:" + SigFile
;
1249 if (Complete
== true)
1251 string FinalFile
= _config
->FindDir("Dir::State::lists");
1252 FinalFile
+= URItoFileName(RealURI
);
1253 if (SigFile
== DestFile
)
1254 SigFile
= FinalFile
;
1255 Rename(DestFile
,FinalFile
);
1256 chmod(FinalFile
.c_str(),0644);
1257 DestFile
= FinalFile
;
1261 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1263 // We have just finished downloading a Release file (it is not
1266 string FileName
= LookupTag(Message
,"Filename");
1267 if (FileName
.empty() == true)
1270 ErrorText
= "Method gave a blank filename";
1274 if (FileName
!= DestFile
)
1277 Desc
.URI
= "copy:" + FileName
;
1282 // make sure to verify against the right file on I-M-S hit
1283 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1286 string FinalFile
= _config
->FindDir("Dir::State::lists");
1287 FinalFile
+= URItoFileName(RealURI
);
1288 if (SigFile
== DestFile
)
1289 SigFile
= FinalFile
;
1290 DestFile
= FinalFile
;
1295 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1297 // At this point, the gpgv method has succeeded, so there is a
1298 // valid signature from a key in the trusted keyring. We
1299 // perform additional verification of its contents, and use them
1300 // to verify the indexes we are about to download
1302 if (!MetaIndexParser
->Load(DestFile
))
1304 Status
= StatAuthError
;
1305 ErrorText
= MetaIndexParser
->ErrorText
;
1309 if (!VerifyVendor(Message
))
1314 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1315 std::cerr
<< "Signature verification succeeded: "
1316 << DestFile
<< std::endl
;
1318 // Download further indexes with verification
1321 // is it a clearsigned MetaIndex file?
1322 if (DestFile
== SigFile
)
1325 // Done, move signature file into position
1326 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1327 URItoFileName(RealURI
) + ".gpg";
1328 Rename(SigFile
,VerifiedSigFile
);
1329 chmod(VerifiedSigFile
.c_str(),0644);
1332 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1334 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1335 Target
!= IndexTargets
->end();
1338 HashString ExpectedIndexHash
;
1341 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1344 if ((*Target
)->IsOptional() == false)
1346 Status
= StatAuthError
;
1347 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1353 ExpectedIndexHash
= Record
->Hash
;
1354 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1356 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1357 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1359 if (ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1361 Status
= StatAuthError
;
1362 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1368 if ((*Target
)->IsOptional() == true)
1370 if ((*Target
)->IsSubIndex() == true)
1371 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1372 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1374 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1378 /* Queue Packages file (either diff or full packages files, depending
1379 on the users option) - we also check if the PDiff Index file is listed
1380 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1381 instead, but passing the required info to it is to much hassle */
1382 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1383 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1384 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1385 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1387 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1391 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1393 // // Maybe this should be made available from above so we don't have
1394 // // to read and parse it every time?
1395 // pkgVendorList List;
1396 // List.ReadMainList();
1398 // const Vendor* Vndr = NULL;
1399 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1401 // string::size_type pos = (*I).find("VALIDSIG ");
1402 // if (_config->FindB("Debug::Vendor", false))
1403 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1405 // if (pos != std::string::npos)
1407 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1408 // if (_config->FindB("Debug::Vendor", false))
1409 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1411 // Vndr = List.FindVendor(Fingerprint) != "";
1412 // if (Vndr != NULL);
1416 string::size_type pos
;
1418 // check for missing sigs (that where not fatal because otherwise we had
1421 string msg
= _("There is no public key available for the "
1422 "following key IDs:\n");
1423 pos
= Message
.find("NO_PUBKEY ");
1424 if (pos
!= std::string::npos
)
1426 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1427 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1428 missingkeys
+= (Fingerprint
);
1430 if(!missingkeys
.empty())
1431 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1433 string Transformed
= MetaIndexParser
->GetExpectedDist();
1435 if (Transformed
== "../project/experimental")
1437 Transformed
= "experimental";
1440 pos
= Transformed
.rfind('/');
1441 if (pos
!= string::npos
)
1443 Transformed
= Transformed
.substr(0, pos
);
1446 if (Transformed
== ".")
1451 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1452 MetaIndexParser
->GetValidUntil() > 0) {
1453 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1454 if (invalid_since
> 0)
1455 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1456 // the time since then the file is invalid - formated in the same way as in
1457 // the download progress display (e.g. 7d 3h 42min 1s)
1458 return _error
->Error(_("Release file expired, ignoring %s (invalid since %s)"),
1459 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1462 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1464 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1465 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1466 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1469 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1471 // This might become fatal one day
1472 // Status = StatAuthError;
1473 // ErrorText = "Conflicting distribution; expected "
1474 // + MetaIndexParser->GetExpectedDist() + " but got "
1475 // + MetaIndexParser->GetDist();
1477 if (!Transformed
.empty())
1479 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1480 Desc
.Description
.c_str(),
1481 Transformed
.c_str(),
1482 MetaIndexParser
->GetDist().c_str());
1489 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1490 // ---------------------------------------------------------------------
1492 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1494 if (AuthPass
== true)
1496 // gpgv method failed, if we have a good signature
1497 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists");
1498 if (DestFile
== SigFile
)
1499 LastGoodSigFile
.append(URItoFileName(RealURI
));
1501 LastGoodSigFile
.append("partial/").append(URItoFileName(RealURI
)).append(".gpg.reverify");
1503 if(FileExists(LastGoodSigFile
))
1505 if (DestFile
!= SigFile
)
1507 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1508 URItoFileName(RealURI
) + ".gpg";
1509 Rename(LastGoodSigFile
,VerifiedSigFile
);
1511 Status
= StatTransientNetworkError
;
1512 _error
->Warning(_("A error occurred during the signature "
1513 "verification. The repository is not updated "
1514 "and the previous index files will be used. "
1515 "GPG error: %s: %s\n"),
1516 Desc
.Description
.c_str(),
1517 LookupTag(Message
,"Message").c_str());
1518 RunScripts("APT::Update::Auth-Failure");
1521 _error
->Warning(_("GPG error: %s: %s"),
1522 Desc
.Description
.c_str(),
1523 LookupTag(Message
,"Message").c_str());
1525 // gpgv method failed
1526 ReportMirrorFailure("GPGFailure");
1529 // No Release file was present, or verification failed, so fall
1530 // back to queueing Packages files without verification
1531 QueueIndexes(false);
1534 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1535 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1536 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1537 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1538 const vector
<struct IndexTarget
*>* IndexTargets
,
1539 indexRecords
* MetaIndexParser
) :
1540 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1541 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1542 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1547 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1548 // ---------------------------------------------------------------------
1549 // FIXME: this can go away once the InRelease file is used widely
1550 string
pkgAcqMetaClearSig::Custom600Headers()
1552 string Final
= _config
->FindDir("Dir::State::lists");
1553 Final
+= URItoFileName(RealURI
);
1556 if (stat(Final
.c_str(),&Buf
) != 0)
1557 return "\nIndex-File: true\nFail-Ignore: true\n";
1559 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1562 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1564 if (AuthPass
== false)
1566 new pkgAcqMetaSig(Owner
,
1567 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1568 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1569 IndexTargets
, MetaIndexParser
);
1570 if (Cnf
->LocalOnly
== true ||
1571 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1575 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1578 // AcqArchive::AcqArchive - Constructor /*{{{*/
1579 // ---------------------------------------------------------------------
1580 /* This just sets up the initial fetch environment and queues the first
1582 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1583 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1584 string
&StoreFilename
) :
1585 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1586 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1589 Retries
= _config
->FindI("Acquire::Retries",0);
1591 if (Version
.Arch() == 0)
1593 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1594 "This might mean you need to manually fix this package. "
1595 "(due to missing arch)"),
1596 Version
.ParentPkg().Name());
1600 /* We need to find a filename to determine the extension. We make the
1601 assumption here that all the available sources for this version share
1602 the same extension.. */
1603 // Skip not source sources, they do not have file fields.
1604 for (; Vf
.end() == false; Vf
++)
1606 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1611 // Does not really matter here.. we are going to fail out below
1612 if (Vf
.end() != true)
1614 // If this fails to get a file name we will bomb out below.
1615 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1616 if (_error
->PendingError() == true)
1619 // Generate the final file name as: package_version_arch.foo
1620 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1621 QuoteString(Version
.VerStr(),"_:") + '_' +
1622 QuoteString(Version
.Arch(),"_:.") +
1623 "." + flExtension(Parse
.FileName());
1626 // check if we have one trusted source for the package. if so, switch
1627 // to "TrustedOnly" mode
1628 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1630 pkgIndexFile
*Index
;
1631 if (Sources
->FindIndex(i
.File(),Index
) == false)
1633 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1635 std::cerr
<< "Checking index: " << Index
->Describe()
1636 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1638 if (Index
->IsTrusted()) {
1644 // "allow-unauthenticated" restores apts old fetching behaviour
1645 // that means that e.g. unauthenticated file:// uris are higher
1646 // priority than authenticated http:// uris
1647 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1651 if (QueueNext() == false && _error
->PendingError() == false)
1652 _error
->Error(_("I wasn't able to locate file for the %s package. "
1653 "This might mean you need to manually fix this package."),
1654 Version
.ParentPkg().Name());
1657 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1658 // ---------------------------------------------------------------------
1659 /* This queues the next available file version for download. It checks if
1660 the archive is already available in the cache and stashs the MD5 for
1662 bool pkgAcqArchive::QueueNext()
1664 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1665 for (; Vf
.end() == false; Vf
++)
1667 // Ignore not source sources
1668 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1671 // Try to cross match against the source list
1672 pkgIndexFile
*Index
;
1673 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1676 // only try to get a trusted package from another source if that source
1678 if(Trusted
&& !Index
->IsTrusted())
1681 // Grab the text package record
1682 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1683 if (_error
->PendingError() == true)
1686 string PkgFile
= Parse
.FileName();
1687 if (ForceHash
.empty() == false)
1689 if(stringcasecmp(ForceHash
, "sha256") == 0)
1690 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1691 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1692 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1694 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1699 if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1700 ExpectedHash
= HashString("SHA256", Hash
);
1701 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1702 ExpectedHash
= HashString("SHA1", Hash
);
1704 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1706 if (PkgFile
.empty() == true)
1707 return _error
->Error(_("The package index files are corrupted. No Filename: "
1708 "field for package %s."),
1709 Version
.ParentPkg().Name());
1711 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1712 Desc
.Description
= Index
->ArchiveInfo(Version
);
1714 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1716 // See if we already have the file. (Legacy filenames)
1717 FileSize
= Version
->Size
;
1718 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1720 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1722 // Make sure the size matches
1723 if ((unsigned)Buf
.st_size
== Version
->Size
)
1728 StoreFilename
= DestFile
= FinalFile
;
1732 /* Hmm, we have a file and its size does not match, this means it is
1733 an old style mismatched arch */
1734 unlink(FinalFile
.c_str());
1737 // Check it again using the new style output filenames
1738 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1739 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1741 // Make sure the size matches
1742 if ((unsigned)Buf
.st_size
== Version
->Size
)
1747 StoreFilename
= DestFile
= FinalFile
;
1751 /* Hmm, we have a file and its size does not match, this shouldnt
1753 unlink(FinalFile
.c_str());
1756 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1758 // Check the destination file
1759 if (stat(DestFile
.c_str(),&Buf
) == 0)
1761 // Hmm, the partial file is too big, erase it
1762 if ((unsigned)Buf
.st_size
> Version
->Size
)
1763 unlink(DestFile
.c_str());
1765 PartialSize
= Buf
.st_size
;
1770 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1771 Desc
.Description
= Index
->ArchiveInfo(Version
);
1773 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1782 // AcqArchive::Done - Finished fetching /*{{{*/
1783 // ---------------------------------------------------------------------
1785 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string CalcHash
,
1786 pkgAcquire::MethodConfig
*Cfg
)
1788 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1791 if (Size
!= Version
->Size
)
1794 ErrorText
= _("Size mismatch");
1799 if(ExpectedHash
.toStr() != CalcHash
)
1802 ErrorText
= _("Hash Sum mismatch");
1803 if(FileExists(DestFile
))
1804 Rename(DestFile
,DestFile
+ ".FAILED");
1808 // Grab the output filename
1809 string FileName
= LookupTag(Message
,"Filename");
1810 if (FileName
.empty() == true)
1813 ErrorText
= "Method gave a blank filename";
1819 // Reference filename
1820 if (FileName
!= DestFile
)
1822 StoreFilename
= DestFile
= FileName
;
1827 // Done, move it into position
1828 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1829 FinalFile
+= flNotDir(StoreFilename
);
1830 Rename(DestFile
,FinalFile
);
1832 StoreFilename
= DestFile
= FinalFile
;
1836 // AcqArchive::Failed - Failure handler /*{{{*/
1837 // ---------------------------------------------------------------------
1838 /* Here we try other sources */
1839 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1841 ErrorText
= LookupTag(Message
,"Message");
1843 /* We don't really want to retry on failed media swaps, this prevents
1844 that. An interesting observation is that permanent failures are not
1846 if (Cnf
->Removable
== true &&
1847 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1849 // Vf = Version.FileList();
1850 while (Vf
.end() == false) Vf
++;
1851 StoreFilename
= string();
1852 Item::Failed(Message
,Cnf
);
1856 if (QueueNext() == false)
1858 // This is the retry counter
1860 Cnf
->LocalOnly
== false &&
1861 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1864 Vf
= Version
.FileList();
1865 if (QueueNext() == true)
1869 StoreFilename
= string();
1870 Item::Failed(Message
,Cnf
);
1874 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1875 // ---------------------------------------------------------------------
1876 bool pkgAcqArchive::IsTrusted()
1881 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1882 // ---------------------------------------------------------------------
1884 void pkgAcqArchive::Finished()
1886 if (Status
== pkgAcquire::Item::StatDone
&&
1889 StoreFilename
= string();
1892 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1893 // ---------------------------------------------------------------------
1894 /* The file is added to the queue */
1895 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1896 unsigned long Size
,string Dsc
,string ShortDesc
,
1897 const string
&DestDir
, const string
&DestFilename
,
1899 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
1901 Retries
= _config
->FindI("Acquire::Retries",0);
1903 if(!DestFilename
.empty())
1904 DestFile
= DestFilename
;
1905 else if(!DestDir
.empty())
1906 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1908 DestFile
= flNotDir(URI
);
1912 Desc
.Description
= Dsc
;
1915 // Set the short description to the archive component
1916 Desc
.ShortDesc
= ShortDesc
;
1918 // Get the transfer sizes
1921 if (stat(DestFile
.c_str(),&Buf
) == 0)
1923 // Hmm, the partial file is too big, erase it
1924 if ((unsigned)Buf
.st_size
> Size
)
1925 unlink(DestFile
.c_str());
1927 PartialSize
= Buf
.st_size
;
1933 // AcqFile::Done - Item downloaded OK /*{{{*/
1934 // ---------------------------------------------------------------------
1936 void pkgAcqFile::Done(string Message
,unsigned long Size
,string CalcHash
,
1937 pkgAcquire::MethodConfig
*Cnf
)
1939 Item::Done(Message
,Size
,CalcHash
,Cnf
);
1942 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
1945 ErrorText
= _("Hash Sum mismatch");
1946 Rename(DestFile
,DestFile
+ ".FAILED");
1950 string FileName
= LookupTag(Message
,"Filename");
1951 if (FileName
.empty() == true)
1954 ErrorText
= "Method gave a blank filename";
1960 // The files timestamp matches
1961 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1964 // We have to copy it into place
1965 if (FileName
!= DestFile
)
1968 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1969 Cnf
->Removable
== true)
1971 Desc
.URI
= "copy:" + FileName
;
1976 // Erase the file if it is a symlink so we can overwrite it
1978 if (lstat(DestFile
.c_str(),&St
) == 0)
1980 if (S_ISLNK(St
.st_mode
) != 0)
1981 unlink(DestFile
.c_str());
1985 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1987 ErrorText
= "Link to " + DestFile
+ " failure ";
1994 // AcqFile::Failed - Failure handler /*{{{*/
1995 // ---------------------------------------------------------------------
1996 /* Here we try other sources */
1997 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1999 ErrorText
= LookupTag(Message
,"Message");
2001 // This is the retry counter
2003 Cnf
->LocalOnly
== false &&
2004 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2011 Item::Failed(Message
,Cnf
);
2014 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2015 // ---------------------------------------------------------------------
2016 /* The only header we use is the last-modified header. */
2017 string
pkgAcqFile::Custom600Headers()
2020 return "\nIndex-File: true";
2024 bool IndexTarget::IsOptional() const {
2025 if (strncmp(ShortDesc
.c_str(), "Translation", 11) != 0)
2029 bool IndexTarget::IsSubIndex() const {
2030 if (ShortDesc
!= "TranslationIndex")