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 DiffIndex file first and see if there are patches availabe
190 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
191 * patches. If anything goes wrong in that process, it will fall back to
192 * the original packages file
194 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
195 string
const &URIDesc
, string
const &ShortDesc
,
196 HashString
const &ExpectedHash
)
197 : Item(Owner
), ExpectedHash(ExpectedHash
)
199 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
201 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
202 DestFile
+= URItoFileName(URI
);
205 Desc
.Description
= URIDesc
;
207 Desc
.ShortDesc
= ShortDesc
;
212 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
215 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
216 // ---------------------------------------------------------------------
217 /* The only header we use is the last-modified header. */
218 string
pkgAcqSubIndex::Custom600Headers()
220 string Final
= _config
->FindDir("Dir::State::lists");
221 Final
+= URItoFileName(Desc
.URI
);
224 if (stat(Final
.c_str(),&Buf
) != 0)
225 return "\nIndex-File: true";
226 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
229 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
232 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< std::endl
;
238 // No good Index is provided, so try guessing
239 std::vector
<std::string
> langs
= APT::Configuration::getLanguages(true);
240 for (std::vector
<std::string
>::const_iterator l
= langs
.begin();
241 l
!= langs
.end(); ++l
)
243 if (*l
== "none") continue;
244 string
const file
= "Translation-" + *l
;
245 new pkgAcqIndexTrans(Owner
, Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
),
246 Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
),
251 void pkgAcqSubIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
252 pkgAcquire::MethodConfig
*Cnf
)
255 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
257 string FileName
= LookupTag(Message
,"Filename");
258 if (FileName
.empty() == true)
261 ErrorText
= "Method gave a blank filename";
265 if (FileName
!= DestFile
)
268 Desc
.URI
= "copy:" + FileName
;
273 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
275 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
277 // sucess in downloading the index
280 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
281 Rename(DestFile
,FinalFile
);
282 chmod(FinalFile
.c_str(),0644);
283 DestFile
= FinalFile
;
285 if(ParseIndex(DestFile
) == false)
286 return Failed("", NULL
);
294 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
296 indexRecords SubIndexParser
;
297 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
300 std::vector
<std::string
> lang
= APT::Configuration::getLanguages(true);
301 for (std::vector
<std::string
>::const_iterator l
= lang
.begin();
302 l
!= lang
.end(); ++l
)
307 string file
= "Translation-" + *l
;
308 indexRecords::checkSum
const *Record
= SubIndexParser
.Lookup(file
);
312 // FIXME: the Index file provided by debian currently only includes bz2 records
313 Record
= SubIndexParser
.Lookup(file
+ ".bz2");
319 expected
= Record
->Hash
;
320 if (expected
.empty() == true)
325 target
.Description
= Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
);
326 target
.MetaKey
= file
;
327 target
.ShortDesc
= file
;
328 target
.URI
= Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
);
329 new pkgAcqIndexTrans(Owner
, &target
, expected
, &SubIndexParser
);
334 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
335 // ---------------------------------------------------------------------
336 /* Get the DiffIndex file first and see if there are patches availabe
337 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
338 * patches. If anything goes wrong in that process, it will fall back to
339 * the original packages file
341 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
342 string URI
,string URIDesc
,string ShortDesc
,
343 HashString ExpectedHash
)
344 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
348 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
350 Desc
.Description
= URIDesc
+ "/DiffIndex";
352 Desc
.ShortDesc
= ShortDesc
;
353 Desc
.URI
= URI
+ ".diff/Index";
355 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
356 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
359 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
361 // look for the current package file
362 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
363 CurrentPackagesFile
+= URItoFileName(RealURI
);
365 // FIXME: this file:/ check is a hack to prevent fetching
366 // from local sources. this is really silly, and
367 // should be fixed cleanly as soon as possible
368 if(!FileExists(CurrentPackagesFile
) ||
369 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
371 // we don't have a pkg file or we don't want to queue
373 std::clog
<< "No index file, local or canceld by user" << std::endl
;
379 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
380 << CurrentPackagesFile
<< std::endl
;
386 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
387 // ---------------------------------------------------------------------
388 /* The only header we use is the last-modified header. */
389 string
pkgAcqDiffIndex::Custom600Headers()
391 string Final
= _config
->FindDir("Dir::State::lists");
392 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
395 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
398 if (stat(Final
.c_str(),&Buf
) != 0)
399 return "\nIndex-File: true";
401 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
404 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
407 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
412 vector
<DiffInfo
> available_patches
;
414 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
416 if (_error
->PendingError() == true)
419 if(TF
.Step(Tags
) == true)
425 string
const tmp
= Tags
.FindS("SHA1-Current");
426 std::stringstream
ss(tmp
);
427 ss
>> ServerSha1
>> size
;
428 unsigned long const ServerSize
= atol(size
.c_str());
430 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
432 SHA1
.AddFD(fd
.Fd(), fd
.Size());
433 string
const local_sha1
= SHA1
.Result();
435 if(local_sha1
== ServerSha1
)
437 // we have the same sha1 as the server
439 std::clog
<< "Package file is up-to-date" << std::endl
;
440 // set found to true, this will queue a pkgAcqIndexDiffs with
441 // a empty availabe_patches
447 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
449 // check the historie and see what patches we need
450 string
const history
= Tags
.FindS("SHA1-History");
451 std::stringstream
hist(history
);
452 while(hist
>> d
.sha1
>> size
>> d
.file
)
454 // read until the first match is found
455 // from that point on, we probably need all diffs
456 if(d
.sha1
== local_sha1
)
458 else if (found
== false)
462 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
463 available_patches
.push_back(d
);
466 if (available_patches
.empty() == false)
468 // patching with too many files is rather slow compared to a fast download
469 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
470 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
473 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
474 << ") so fallback to complete download" << std::endl
;
478 // see if the patches are too big
479 found
= false; // it was true and it will be true again at the end
480 d
= *available_patches
.begin();
481 string
const firstPatch
= d
.file
;
482 unsigned long patchesSize
= 0;
483 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
484 while(patches
>> d
.sha1
>> size
>> d
.file
)
486 if (firstPatch
== d
.file
)
488 else if (found
== false)
491 patchesSize
+= atol(size
.c_str());
493 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
494 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
497 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
498 << ") so fallback to complete download" << std::endl
;
504 // we have something, queue the next diff
508 string::size_type
const last_space
= Description
.rfind(" ");
509 if(last_space
!= string::npos
)
510 Description
.erase(last_space
, Description
.size()-last_space
);
511 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
512 ExpectedHash
, ServerSha1
, available_patches
);
520 // Nothing found, report and return false
521 // Failing here is ok, if we return false later, the full
522 // IndexFile is queued
524 std::clog
<< "Can't find a patch in the index file" << std::endl
;
528 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
531 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
532 << "Falling back to normal index file aquire" << std::endl
;
534 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
542 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
543 pkgAcquire::MethodConfig
*Cnf
)
546 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
548 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
551 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
553 // sucess in downloading the index
555 FinalFile
+= string(".IndexDiff");
557 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
559 Rename(DestFile
,FinalFile
);
560 chmod(FinalFile
.c_str(),0644);
561 DestFile
= FinalFile
;
563 if(!ParseDiffIndex(DestFile
))
564 return Failed("", NULL
);
572 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
573 // ---------------------------------------------------------------------
574 /* The package diff is added to the queue. one object is constructed
575 * for each diff and the index
577 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
578 string URI
,string URIDesc
,string ShortDesc
,
579 HashString ExpectedHash
,
581 vector
<DiffInfo
> diffs
)
582 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
583 available_patches(diffs
), ServerSha1(ServerSha1
)
586 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
587 DestFile
+= URItoFileName(URI
);
589 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
591 Description
= URIDesc
;
593 Desc
.ShortDesc
= ShortDesc
;
595 if(available_patches
.size() == 0)
597 // we are done (yeah!)
603 State
= StateFetchDiff
;
608 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
611 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
612 << "Falling back to normal index file aquire" << std::endl
;
613 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
618 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
619 void pkgAcqIndexDiffs::Finish(bool allDone
)
621 // we restore the original name, this is required, otherwise
622 // the file will be cleaned
625 DestFile
= _config
->FindDir("Dir::State::lists");
626 DestFile
+= URItoFileName(RealURI
);
628 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
630 Status
= StatAuthError
;
631 ErrorText
= _("MD5Sum mismatch");
632 Rename(DestFile
,DestFile
+ ".FAILED");
637 // this is for the "real" finish
642 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
647 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
654 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
657 // calc sha1 of the just patched file
658 string FinalFile
= _config
->FindDir("Dir::State::lists");
659 FinalFile
+= URItoFileName(RealURI
);
661 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
663 SHA1
.AddFD(fd
.Fd(), fd
.Size());
664 string local_sha1
= string(SHA1
.Result());
666 std::clog
<< "QueueNextDiff: "
667 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
669 // final file reached before all patches are applied
670 if(local_sha1
== ServerSha1
)
676 // remove all patches until the next matching patch is found
677 // this requires the Index file to be ordered
678 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
679 available_patches
.size() > 0 &&
680 I
!= available_patches
.end() &&
681 (*I
).sha1
!= local_sha1
;
684 available_patches
.erase(I
);
687 // error checking and falling back if no patch was found
688 if(available_patches
.size() == 0)
694 // queue the right diff
695 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
696 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
697 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
698 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
701 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
708 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
709 pkgAcquire::MethodConfig
*Cnf
)
712 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
714 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
717 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
719 // sucess in downloading a diff, enter ApplyDiff state
720 if(State
== StateFetchDiff
)
723 // rred excepts the patch as $FinalFile.ed
724 Rename(DestFile
,FinalFile
+".ed");
727 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
729 State
= StateApplyDiff
;
731 Desc
.URI
= "rred:" + FinalFile
;
738 // success in download/apply a diff, queue next (if needed)
739 if(State
== StateApplyDiff
)
741 // remove the just applied patch
742 available_patches
.erase(available_patches
.begin());
747 std::clog
<< "Moving patched file in place: " << std::endl
748 << DestFile
<< " -> " << FinalFile
<< std::endl
;
750 Rename(DestFile
,FinalFile
);
751 chmod(FinalFile
.c_str(),0644);
753 // see if there is more to download
754 if(available_patches
.size() > 0) {
755 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
756 ExpectedHash
, ServerSha1
, available_patches
);
763 // AcqIndex::AcqIndex - Constructor /*{{{*/
764 // ---------------------------------------------------------------------
765 /* The package file is added to the queue and a second class is
766 instantiated to fetch the revision file */
767 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
768 string URI
,string URIDesc
,string ShortDesc
,
769 HashString ExpectedHash
, string comprExt
)
770 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
772 if(comprExt
.empty() == true)
774 // autoselect the compression method
775 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
776 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
777 comprExt
.append(*t
).append(" ");
778 if (comprExt
.empty() == false)
779 comprExt
.erase(comprExt
.end()-1);
781 CompressionExtension
= comprExt
;
783 Init(URI
, URIDesc
, ShortDesc
);
785 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
786 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
787 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
789 // autoselect the compression method
790 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
791 CompressionExtension
= "";
792 if (ExpectedHash
.empty() == false)
794 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
795 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
796 CompressionExtension
.append(*t
).append(" ");
800 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
801 CompressionExtension
.append(*t
).append(" ");
803 if (CompressionExtension
.empty() == false)
804 CompressionExtension
.erase(CompressionExtension
.end()-1);
806 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
809 // AcqIndex::Init - defered Constructor /*{{{*/
810 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
811 Decompression
= false;
814 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
815 DestFile
+= URItoFileName(URI
);
817 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
818 if (comprExt
== "uncompressed")
821 Desc
.URI
= URI
+ '.' + comprExt
;
823 Desc
.Description
= URIDesc
;
825 Desc
.ShortDesc
= ShortDesc
;
830 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
831 // ---------------------------------------------------------------------
832 /* The only header we use is the last-modified header. */
833 string
pkgAcqIndex::Custom600Headers()
835 string Final
= _config
->FindDir("Dir::State::lists");
836 Final
+= URItoFileName(RealURI
);
837 if (_config
->FindB("Acquire::GzipIndexes",false))
841 if (stat(Final
.c_str(),&Buf
) != 0)
842 return "\nIndex-File: true";
843 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
846 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
848 size_t const nextExt
= CompressionExtension
.find(' ');
849 if (nextExt
!= std::string::npos
)
851 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
852 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
856 // on decompression failure, remove bad versions in partial/
857 if (Decompression
&& Erase
) {
858 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
859 s
.append(URItoFileName(RealURI
));
863 Item::Failed(Message
,Cnf
);
866 // AcqIndex::Done - Finished a fetch /*{{{*/
867 // ---------------------------------------------------------------------
868 /* This goes through a number of states.. On the initial fetch the
869 method could possibly return an alternate filename which points
870 to the uncompressed version of the file. If this is so the file
871 is copied into the partial directory. In all other cases the file
872 is decompressed with a gzip uri. */
873 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string Hash
,
874 pkgAcquire::MethodConfig
*Cfg
)
876 Item::Done(Message
,Size
,Hash
,Cfg
);
878 if (Decompression
== true)
880 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
882 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
883 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
886 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
888 Status
= StatAuthError
;
889 ErrorText
= _("Hash Sum mismatch");
890 Rename(DestFile
,DestFile
+ ".FAILED");
891 ReportMirrorFailure("HashChecksumFailure");
894 // Done, move it into position
895 string FinalFile
= _config
->FindDir("Dir::State::lists");
896 FinalFile
+= URItoFileName(RealURI
);
897 Rename(DestFile
,FinalFile
);
898 chmod(FinalFile
.c_str(),0644);
900 /* We restore the original name to DestFile so that the clean operation
902 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
903 DestFile
+= URItoFileName(RealURI
);
905 // Remove the compressed version.
907 unlink(DestFile
.c_str());
914 // Handle the unzipd case
915 string FileName
= LookupTag(Message
,"Alt-Filename");
916 if (FileName
.empty() == false)
918 // The files timestamp matches
919 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
921 Decompression
= true;
923 DestFile
+= ".decomp";
924 Desc
.URI
= "copy:" + FileName
;
930 FileName
= LookupTag(Message
,"Filename");
931 if (FileName
.empty() == true)
934 ErrorText
= "Method gave a blank filename";
937 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
939 // The files timestamp matches
940 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
941 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
942 // Update DestFile for .gz suffix so that the clean operation keeps it
947 if (FileName
== DestFile
)
954 // If we enable compressed indexes and already have gzip, keep it
955 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
956 string FinalFile
= _config
->FindDir("Dir::State::lists");
957 FinalFile
+= URItoFileName(RealURI
) + ".gz";
958 Rename(DestFile
,FinalFile
);
959 chmod(FinalFile
.c_str(),0644);
961 // Update DestFile for .gz suffix so that the clean operation keeps it
962 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
963 DestFile
+= URItoFileName(RealURI
) + ".gz";
967 // get the binary name for your used compression type
968 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
969 if(decompProg
.empty() == false);
970 else if(compExt
== "uncompressed")
973 _error
->Error("Unsupported extension: %s", compExt
.c_str());
977 Decompression
= true;
978 DestFile
+= ".decomp";
979 Desc
.URI
= decompProg
+ ":" + FileName
;
981 Mode
= decompProg
.c_str();
984 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
985 // ---------------------------------------------------------------------
986 /* The Translation file is added to the queue */
987 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
988 string URI
,string URIDesc
,string ShortDesc
)
989 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
992 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
993 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
994 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
998 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
999 // ---------------------------------------------------------------------
1000 string
pkgAcqIndexTrans::Custom600Headers()
1002 string Final
= _config
->FindDir("Dir::State::lists");
1003 Final
+= URItoFileName(RealURI
);
1006 if (stat(Final
.c_str(),&Buf
) != 0)
1007 return "\nFail-Ignore: true";
1008 return "\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1011 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1012 // ---------------------------------------------------------------------
1014 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1016 size_t const nextExt
= CompressionExtension
.find(' ');
1017 if (nextExt
!= std::string::npos
)
1019 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1020 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1025 if (Cnf
->LocalOnly
== true ||
1026 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1035 Item::Failed(Message
,Cnf
);
1038 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1039 string URI
,string URIDesc
,string ShortDesc
,
1040 string MetaIndexURI
, string MetaIndexURIDesc
,
1041 string MetaIndexShortDesc
,
1042 const vector
<IndexTarget
*>* IndexTargets
,
1043 indexRecords
* MetaIndexParser
) :
1044 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1045 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1046 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1048 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1049 DestFile
+= URItoFileName(URI
);
1051 // remove any partial downloaded sig-file in partial/.
1052 // it may confuse proxies and is too small to warrant a
1053 // partial download anyway
1054 unlink(DestFile
.c_str());
1057 Desc
.Description
= URIDesc
;
1059 Desc
.ShortDesc
= ShortDesc
;
1062 string Final
= _config
->FindDir("Dir::State::lists");
1063 Final
+= URItoFileName(RealURI
);
1065 if (stat(Final
.c_str(),&Buf
) == 0)
1067 // File was already in place. It needs to be re-downloaded/verified
1068 // because Release might have changed, we do give it a differnt
1069 // name than DestFile because otherwise the http method will
1070 // send If-Range requests and there are too many broken servers
1071 // out there that do not understand them
1072 LastGoodSig
= DestFile
+".reverify";
1073 Rename(Final
,LastGoodSig
);
1079 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1080 // ---------------------------------------------------------------------
1081 /* The only header we use is the last-modified header. */
1082 string
pkgAcqMetaSig::Custom600Headers()
1085 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1086 return "\nIndex-File: true";
1088 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1091 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
1092 pkgAcquire::MethodConfig
*Cfg
)
1094 Item::Done(Message
,Size
,MD5
,Cfg
);
1096 string FileName
= LookupTag(Message
,"Filename");
1097 if (FileName
.empty() == true)
1100 ErrorText
= "Method gave a blank filename";
1104 if (FileName
!= DestFile
)
1106 // We have to copy it into place
1108 Desc
.URI
= "copy:" + FileName
;
1115 // put the last known good file back on i-m-s hit (it will
1116 // be re-verified again)
1117 // Else do nothing, we have the new file in DestFile then
1118 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1119 Rename(LastGoodSig
, DestFile
);
1121 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1122 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1123 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1128 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1130 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1132 // if we get a network error we fail gracefully
1133 if(Status
== StatTransientNetworkError
)
1135 Item::Failed(Message
,Cnf
);
1136 // move the sigfile back on transient network failures
1137 if(FileExists(LastGoodSig
))
1138 Rename(LastGoodSig
,Final
);
1140 // set the status back to , Item::Failed likes to reset it
1141 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1145 // Delete any existing sigfile when the acquire failed
1146 unlink(Final
.c_str());
1148 // queue a pkgAcqMetaIndex with no sigfile
1149 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1150 "", IndexTargets
, MetaIndexParser
);
1152 if (Cnf
->LocalOnly
== true ||
1153 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1162 Item::Failed(Message
,Cnf
);
1165 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1166 string URI
,string URIDesc
,string ShortDesc
,
1168 const vector
<struct IndexTarget
*>* IndexTargets
,
1169 indexRecords
* MetaIndexParser
) :
1170 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1171 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1173 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1174 DestFile
+= URItoFileName(URI
);
1177 Desc
.Description
= URIDesc
;
1179 Desc
.ShortDesc
= ShortDesc
;
1185 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1186 // ---------------------------------------------------------------------
1187 /* The only header we use is the last-modified header. */
1188 string
pkgAcqMetaIndex::Custom600Headers()
1190 string Final
= _config
->FindDir("Dir::State::lists");
1191 Final
+= URItoFileName(RealURI
);
1194 if (stat(Final
.c_str(),&Buf
) != 0)
1195 return "\nIndex-File: true";
1197 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1200 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string Hash
, /*{{{*/
1201 pkgAcquire::MethodConfig
*Cfg
)
1203 Item::Done(Message
,Size
,Hash
,Cfg
);
1205 // MetaIndexes are done in two passes: one to download the
1206 // metaindex with an appropriate method, and a second to verify it
1207 // with the gpgv method
1209 if (AuthPass
== true)
1213 // all cool, move Release file into place
1218 RetrievalDone(Message
);
1220 // Still more retrieving to do
1225 // There was no signature file, so we are finished. Download
1226 // the indexes without verification.
1227 QueueIndexes(false);
1231 // There was a signature file, so pass it to gpgv for
1234 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1235 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1236 << SigFile
<< "," << DestFile
<< ")\n";
1238 Desc
.URI
= "gpgv:" + SigFile
;
1245 if (Complete
== true)
1247 string FinalFile
= _config
->FindDir("Dir::State::lists");
1248 FinalFile
+= URItoFileName(RealURI
);
1249 if (SigFile
== DestFile
)
1250 SigFile
= FinalFile
;
1251 Rename(DestFile
,FinalFile
);
1252 chmod(FinalFile
.c_str(),0644);
1253 DestFile
= FinalFile
;
1257 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1259 // We have just finished downloading a Release file (it is not
1262 string FileName
= LookupTag(Message
,"Filename");
1263 if (FileName
.empty() == true)
1266 ErrorText
= "Method gave a blank filename";
1270 if (FileName
!= DestFile
)
1273 Desc
.URI
= "copy:" + FileName
;
1278 // make sure to verify against the right file on I-M-S hit
1279 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1282 string FinalFile
= _config
->FindDir("Dir::State::lists");
1283 FinalFile
+= URItoFileName(RealURI
);
1284 if (SigFile
== DestFile
)
1285 SigFile
= FinalFile
;
1286 DestFile
= FinalFile
;
1291 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1293 // At this point, the gpgv method has succeeded, so there is a
1294 // valid signature from a key in the trusted keyring. We
1295 // perform additional verification of its contents, and use them
1296 // to verify the indexes we are about to download
1298 if (!MetaIndexParser
->Load(DestFile
))
1300 Status
= StatAuthError
;
1301 ErrorText
= MetaIndexParser
->ErrorText
;
1305 if (!VerifyVendor(Message
))
1310 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1311 std::cerr
<< "Signature verification succeeded: "
1312 << DestFile
<< std::endl
;
1314 // Download further indexes with verification
1317 // is it a clearsigned MetaIndex file?
1318 if (DestFile
== SigFile
)
1321 // Done, move signature file into position
1322 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1323 URItoFileName(RealURI
) + ".gpg";
1324 Rename(SigFile
,VerifiedSigFile
);
1325 chmod(VerifiedSigFile
.c_str(),0644);
1328 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1330 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1331 Target
!= IndexTargets
->end();
1334 HashString ExpectedIndexHash
;
1337 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1340 if ((*Target
)->IsOptional() == false)
1342 Status
= StatAuthError
;
1343 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1349 ExpectedIndexHash
= Record
->Hash
;
1350 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1352 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1353 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1355 if (ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1357 Status
= StatAuthError
;
1358 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1364 if ((*Target
)->IsOptional() == true)
1366 if ((*Target
)->IsSubIndex() == true)
1367 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1368 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1370 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1374 /* Queue Packages file (either diff or full packages files, depending
1375 on the users option) - we also check if the PDiff Index file is listed
1376 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1377 instead, but passing the required info to it is to much hassle */
1378 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1379 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1380 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1381 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1383 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1387 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1389 // // Maybe this should be made available from above so we don't have
1390 // // to read and parse it every time?
1391 // pkgVendorList List;
1392 // List.ReadMainList();
1394 // const Vendor* Vndr = NULL;
1395 // for (std::vector<string>::const_iterator I = GPGVOutput.begin(); I != GPGVOutput.end(); I++)
1397 // string::size_type pos = (*I).find("VALIDSIG ");
1398 // if (_config->FindB("Debug::Vendor", false))
1399 // std::cerr << "Looking for VALIDSIG in \"" << (*I) << "\": pos " << pos
1401 // if (pos != std::string::npos)
1403 // string Fingerprint = (*I).substr(pos+sizeof("VALIDSIG"));
1404 // if (_config->FindB("Debug::Vendor", false))
1405 // std::cerr << "Looking for \"" << Fingerprint << "\" in vendor..." <<
1407 // Vndr = List.FindVendor(Fingerprint) != "";
1408 // if (Vndr != NULL);
1412 string::size_type pos
;
1414 // check for missing sigs (that where not fatal because otherwise we had
1417 string msg
= _("There is no public key available for the "
1418 "following key IDs:\n");
1419 pos
= Message
.find("NO_PUBKEY ");
1420 if (pos
!= std::string::npos
)
1422 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1423 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1424 missingkeys
+= (Fingerprint
);
1426 if(!missingkeys
.empty())
1427 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1429 string Transformed
= MetaIndexParser
->GetExpectedDist();
1431 if (Transformed
== "../project/experimental")
1433 Transformed
= "experimental";
1436 pos
= Transformed
.rfind('/');
1437 if (pos
!= string::npos
)
1439 Transformed
= Transformed
.substr(0, pos
);
1442 if (Transformed
== ".")
1447 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1448 MetaIndexParser
->GetValidUntil() > 0) {
1449 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1450 if (invalid_since
> 0)
1451 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1452 // the time since then the file is invalid - formated in the same way as in
1453 // the download progress display (e.g. 7d 3h 42min 1s)
1454 return _error
->Error(_("Release file expired, ignoring %s (invalid since %s)"),
1455 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1458 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1460 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1461 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1462 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1465 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1467 // This might become fatal one day
1468 // Status = StatAuthError;
1469 // ErrorText = "Conflicting distribution; expected "
1470 // + MetaIndexParser->GetExpectedDist() + " but got "
1471 // + MetaIndexParser->GetDist();
1473 if (!Transformed
.empty())
1475 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1476 Desc
.Description
.c_str(),
1477 Transformed
.c_str(),
1478 MetaIndexParser
->GetDist().c_str());
1485 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1486 // ---------------------------------------------------------------------
1488 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1490 if (AuthPass
== true)
1492 // gpgv method failed, if we have a good signature
1493 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists");
1494 if (DestFile
== SigFile
)
1495 LastGoodSigFile
.append(URItoFileName(RealURI
));
1497 LastGoodSigFile
.append("partial/").append(URItoFileName(RealURI
)).append(".gpg.reverify");
1499 if(FileExists(LastGoodSigFile
))
1501 if (DestFile
!= SigFile
)
1503 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1504 URItoFileName(RealURI
) + ".gpg";
1505 Rename(LastGoodSigFile
,VerifiedSigFile
);
1507 Status
= StatTransientNetworkError
;
1508 _error
->Warning(_("A error occurred during the signature "
1509 "verification. The repository is not updated "
1510 "and the previous index files will be used. "
1511 "GPG error: %s: %s\n"),
1512 Desc
.Description
.c_str(),
1513 LookupTag(Message
,"Message").c_str());
1514 RunScripts("APT::Update::Auth-Failure");
1517 _error
->Warning(_("GPG error: %s: %s"),
1518 Desc
.Description
.c_str(),
1519 LookupTag(Message
,"Message").c_str());
1521 // gpgv method failed
1522 ReportMirrorFailure("GPGFailure");
1525 // No Release file was present, or verification failed, so fall
1526 // back to queueing Packages files without verification
1527 QueueIndexes(false);
1530 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1531 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1532 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1533 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1534 const vector
<struct IndexTarget
*>* IndexTargets
,
1535 indexRecords
* MetaIndexParser
) :
1536 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1537 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1538 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1543 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1545 if (AuthPass
== false)
1547 new pkgAcqMetaSig(Owner
,
1548 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1549 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1550 IndexTargets
, MetaIndexParser
);
1551 if (Cnf
->LocalOnly
== true ||
1552 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1556 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1559 // AcqArchive::AcqArchive - Constructor /*{{{*/
1560 // ---------------------------------------------------------------------
1561 /* This just sets up the initial fetch environment and queues the first
1563 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1564 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1565 string
&StoreFilename
) :
1566 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1567 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1570 Retries
= _config
->FindI("Acquire::Retries",0);
1572 if (Version
.Arch() == 0)
1574 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1575 "This might mean you need to manually fix this package. "
1576 "(due to missing arch)"),
1577 Version
.ParentPkg().Name());
1581 /* We need to find a filename to determine the extension. We make the
1582 assumption here that all the available sources for this version share
1583 the same extension.. */
1584 // Skip not source sources, they do not have file fields.
1585 for (; Vf
.end() == false; Vf
++)
1587 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1592 // Does not really matter here.. we are going to fail out below
1593 if (Vf
.end() != true)
1595 // If this fails to get a file name we will bomb out below.
1596 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1597 if (_error
->PendingError() == true)
1600 // Generate the final file name as: package_version_arch.foo
1601 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1602 QuoteString(Version
.VerStr(),"_:") + '_' +
1603 QuoteString(Version
.Arch(),"_:.") +
1604 "." + flExtension(Parse
.FileName());
1607 // check if we have one trusted source for the package. if so, switch
1608 // to "TrustedOnly" mode
1609 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1611 pkgIndexFile
*Index
;
1612 if (Sources
->FindIndex(i
.File(),Index
) == false)
1614 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1616 std::cerr
<< "Checking index: " << Index
->Describe()
1617 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1619 if (Index
->IsTrusted()) {
1625 // "allow-unauthenticated" restores apts old fetching behaviour
1626 // that means that e.g. unauthenticated file:// uris are higher
1627 // priority than authenticated http:// uris
1628 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1632 if (QueueNext() == false && _error
->PendingError() == false)
1633 _error
->Error(_("I wasn't able to locate file for the %s package. "
1634 "This might mean you need to manually fix this package."),
1635 Version
.ParentPkg().Name());
1638 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1639 // ---------------------------------------------------------------------
1640 /* This queues the next available file version for download. It checks if
1641 the archive is already available in the cache and stashs the MD5 for
1643 bool pkgAcqArchive::QueueNext()
1645 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1646 for (; Vf
.end() == false; Vf
++)
1648 // Ignore not source sources
1649 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1652 // Try to cross match against the source list
1653 pkgIndexFile
*Index
;
1654 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1657 // only try to get a trusted package from another source if that source
1659 if(Trusted
&& !Index
->IsTrusted())
1662 // Grab the text package record
1663 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1664 if (_error
->PendingError() == true)
1667 string PkgFile
= Parse
.FileName();
1668 if (ForceHash
.empty() == false)
1670 if(stringcasecmp(ForceHash
, "sha256") == 0)
1671 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1672 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1673 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1675 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1680 if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1681 ExpectedHash
= HashString("SHA256", Hash
);
1682 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1683 ExpectedHash
= HashString("SHA1", Hash
);
1685 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1687 if (PkgFile
.empty() == true)
1688 return _error
->Error(_("The package index files are corrupted. No Filename: "
1689 "field for package %s."),
1690 Version
.ParentPkg().Name());
1692 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1693 Desc
.Description
= Index
->ArchiveInfo(Version
);
1695 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1697 // See if we already have the file. (Legacy filenames)
1698 FileSize
= Version
->Size
;
1699 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1701 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1703 // Make sure the size matches
1704 if ((unsigned)Buf
.st_size
== Version
->Size
)
1709 StoreFilename
= DestFile
= FinalFile
;
1713 /* Hmm, we have a file and its size does not match, this means it is
1714 an old style mismatched arch */
1715 unlink(FinalFile
.c_str());
1718 // Check it again using the new style output filenames
1719 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
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 shouldnt
1734 unlink(FinalFile
.c_str());
1737 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1739 // Check the destination file
1740 if (stat(DestFile
.c_str(),&Buf
) == 0)
1742 // Hmm, the partial file is too big, erase it
1743 if ((unsigned)Buf
.st_size
> Version
->Size
)
1744 unlink(DestFile
.c_str());
1746 PartialSize
= Buf
.st_size
;
1751 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1752 Desc
.Description
= Index
->ArchiveInfo(Version
);
1754 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1763 // AcqArchive::Done - Finished fetching /*{{{*/
1764 // ---------------------------------------------------------------------
1766 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string CalcHash
,
1767 pkgAcquire::MethodConfig
*Cfg
)
1769 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1772 if (Size
!= Version
->Size
)
1775 ErrorText
= _("Size mismatch");
1780 if(ExpectedHash
.toStr() != CalcHash
)
1783 ErrorText
= _("Hash Sum mismatch");
1784 if(FileExists(DestFile
))
1785 Rename(DestFile
,DestFile
+ ".FAILED");
1789 // Grab the output filename
1790 string FileName
= LookupTag(Message
,"Filename");
1791 if (FileName
.empty() == true)
1794 ErrorText
= "Method gave a blank filename";
1800 // Reference filename
1801 if (FileName
!= DestFile
)
1803 StoreFilename
= DestFile
= FileName
;
1808 // Done, move it into position
1809 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1810 FinalFile
+= flNotDir(StoreFilename
);
1811 Rename(DestFile
,FinalFile
);
1813 StoreFilename
= DestFile
= FinalFile
;
1817 // AcqArchive::Failed - Failure handler /*{{{*/
1818 // ---------------------------------------------------------------------
1819 /* Here we try other sources */
1820 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1822 ErrorText
= LookupTag(Message
,"Message");
1824 /* We don't really want to retry on failed media swaps, this prevents
1825 that. An interesting observation is that permanent failures are not
1827 if (Cnf
->Removable
== true &&
1828 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1830 // Vf = Version.FileList();
1831 while (Vf
.end() == false) Vf
++;
1832 StoreFilename
= string();
1833 Item::Failed(Message
,Cnf
);
1837 if (QueueNext() == false)
1839 // This is the retry counter
1841 Cnf
->LocalOnly
== false &&
1842 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1845 Vf
= Version
.FileList();
1846 if (QueueNext() == true)
1850 StoreFilename
= string();
1851 Item::Failed(Message
,Cnf
);
1855 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1856 // ---------------------------------------------------------------------
1857 bool pkgAcqArchive::IsTrusted()
1862 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1863 // ---------------------------------------------------------------------
1865 void pkgAcqArchive::Finished()
1867 if (Status
== pkgAcquire::Item::StatDone
&&
1870 StoreFilename
= string();
1873 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1874 // ---------------------------------------------------------------------
1875 /* The file is added to the queue */
1876 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1877 unsigned long Size
,string Dsc
,string ShortDesc
,
1878 const string
&DestDir
, const string
&DestFilename
,
1880 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
1882 Retries
= _config
->FindI("Acquire::Retries",0);
1884 if(!DestFilename
.empty())
1885 DestFile
= DestFilename
;
1886 else if(!DestDir
.empty())
1887 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1889 DestFile
= flNotDir(URI
);
1893 Desc
.Description
= Dsc
;
1896 // Set the short description to the archive component
1897 Desc
.ShortDesc
= ShortDesc
;
1899 // Get the transfer sizes
1902 if (stat(DestFile
.c_str(),&Buf
) == 0)
1904 // Hmm, the partial file is too big, erase it
1905 if ((unsigned)Buf
.st_size
> Size
)
1906 unlink(DestFile
.c_str());
1908 PartialSize
= Buf
.st_size
;
1914 // AcqFile::Done - Item downloaded OK /*{{{*/
1915 // ---------------------------------------------------------------------
1917 void pkgAcqFile::Done(string Message
,unsigned long Size
,string CalcHash
,
1918 pkgAcquire::MethodConfig
*Cnf
)
1920 Item::Done(Message
,Size
,CalcHash
,Cnf
);
1923 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
1926 ErrorText
= _("Hash Sum mismatch");
1927 Rename(DestFile
,DestFile
+ ".FAILED");
1931 string FileName
= LookupTag(Message
,"Filename");
1932 if (FileName
.empty() == true)
1935 ErrorText
= "Method gave a blank filename";
1941 // The files timestamp matches
1942 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1945 // We have to copy it into place
1946 if (FileName
!= DestFile
)
1949 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1950 Cnf
->Removable
== true)
1952 Desc
.URI
= "copy:" + FileName
;
1957 // Erase the file if it is a symlink so we can overwrite it
1959 if (lstat(DestFile
.c_str(),&St
) == 0)
1961 if (S_ISLNK(St
.st_mode
) != 0)
1962 unlink(DestFile
.c_str());
1966 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1968 ErrorText
= "Link to " + DestFile
+ " failure ";
1975 // AcqFile::Failed - Failure handler /*{{{*/
1976 // ---------------------------------------------------------------------
1977 /* Here we try other sources */
1978 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1980 ErrorText
= LookupTag(Message
,"Message");
1982 // This is the retry counter
1984 Cnf
->LocalOnly
== false &&
1985 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1992 Item::Failed(Message
,Cnf
);
1995 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1996 // ---------------------------------------------------------------------
1997 /* The only header we use is the last-modified header. */
1998 string
pkgAcqFile::Custom600Headers()
2001 return "\nIndex-File: true";
2005 bool IndexTarget::IsOptional() const {
2006 if (strncmp(ShortDesc
.c_str(), "Translation", 11) != 0)
2010 bool IndexTarget::IsSubIndex() const {
2011 if (ShortDesc
!= "TranslationIndex")