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 /*{{{*/
18 #include <apt-pkg/acquire-item.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/aptconfiguration.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/md5.h>
26 #include <apt-pkg/sha1.h>
27 #include <apt-pkg/tagfile.h>
28 #include <apt-pkg/indexrecords.h>
29 #include <apt-pkg/metaindex.h>
44 // Acquire::Item::Item - Constructor /*{{{*/
45 // ---------------------------------------------------------------------
47 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
48 PartialSize(0), Mode(0), ID(0), Complete(false),
49 Local(false), QueueCounter(0)
55 // Acquire::Item::~Item - Destructor /*{{{*/
56 // ---------------------------------------------------------------------
58 pkgAcquire::Item::~Item()
63 // Acquire::Item::Failed - Item failed to download /*{{{*/
64 // ---------------------------------------------------------------------
65 /* We return to an idle state if there are still other queues that could
67 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
70 ErrorText
= LookupTag(Message
,"Message");
71 UsedMirror
= LookupTag(Message
,"UsedMirror");
72 if (QueueCounter
<= 1)
74 /* This indicates that the file is not available right now but might
75 be sometime later. If we do a retry cycle then this should be
77 if (Cnf
->LocalOnly
== true &&
78 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
89 // report mirror failure back to LP if we actually use a mirror
90 string FailReason
= LookupTag(Message
, "FailReason");
91 if(FailReason
.size() != 0)
92 ReportMirrorFailure(FailReason
);
94 ReportMirrorFailure(ErrorText
);
97 // Acquire::Item::Start - Item has begun to download /*{{{*/
98 // ---------------------------------------------------------------------
99 /* Stash status and the file size. Note that setting Complete means
100 sub-phases of the acquire process such as decompresion are operating */
101 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
103 Status
= StatFetching
;
104 if (FileSize
== 0 && Complete
== false)
108 // Acquire::Item::Done - Item downloaded OK /*{{{*/
109 // ---------------------------------------------------------------------
111 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,string Hash
,
112 pkgAcquire::MethodConfig
*Cnf
)
114 // We just downloaded something..
115 string FileName
= LookupTag(Message
,"Filename");
116 UsedMirror
= LookupTag(Message
,"UsedMirror");
117 if (Complete
== false && !Local
&& FileName
== DestFile
)
120 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
126 ErrorText
= string();
127 Owner
->Dequeue(this);
130 // Acquire::Item::Rename - Rename a file /*{{{*/
131 // ---------------------------------------------------------------------
132 /* This helper function is used by alot of item methods as thier final
134 void pkgAcquire::Item::Rename(string From
,string To
)
136 if (rename(From
.c_str(),To
.c_str()) != 0)
139 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
140 From
.c_str(),To
.c_str());
146 // Acquire::Item::ReportMirrorFailure /*{{{*/
147 // ---------------------------------------------------------------------
148 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
150 // we only act if a mirror was used at all
151 if(UsedMirror
.empty())
154 std::cerr
<< "\nReportMirrorFailure: "
156 << " Uri: " << DescURI()
158 << FailCode
<< std::endl
;
160 const char *Args
[40];
162 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
163 "/usr/lib/apt/apt-report-mirror-failure");
164 if(!FileExists(report
))
166 Args
[i
++] = report
.c_str();
167 Args
[i
++] = UsedMirror
.c_str();
168 Args
[i
++] = DescURI().c_str();
169 Args
[i
++] = FailCode
.c_str();
171 pid_t pid
= ExecFork();
174 _error
->Error("ReportMirrorFailure Fork failed");
179 execvp(Args
[0], (char**)Args
);
180 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
183 if(!ExecWait(pid
, "report-mirror-failure"))
185 _error
->Warning("Couldn't report problem to '%s'",
186 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
190 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
191 // ---------------------------------------------------------------------
192 /* Get the Index file first and see if there are languages available
193 * If so, create a pkgAcqIndexTrans for the found language(s).
195 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
196 string
const &URIDesc
, string
const &ShortDesc
,
197 HashString
const &ExpectedHash
)
198 : Item(Owner
), ExpectedHash(ExpectedHash
)
200 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
202 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
203 DestFile
+= URItoFileName(URI
);
206 Desc
.Description
= URIDesc
;
208 Desc
.ShortDesc
= ShortDesc
;
213 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
216 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
217 // ---------------------------------------------------------------------
218 /* The only header we use is the last-modified header. */
219 string
pkgAcqSubIndex::Custom600Headers()
221 string Final
= _config
->FindDir("Dir::State::lists");
222 Final
+= URItoFileName(Desc
.URI
);
225 if (stat(Final
.c_str(),&Buf
) != 0)
226 return "\nIndex-File: true\nFail-Ignore: true\n";
227 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
230 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
233 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< std::endl
;
239 // No good Index is provided, so try guessing
240 std::vector
<std::string
> langs
= APT::Configuration::getLanguages(true);
241 for (std::vector
<std::string
>::const_iterator l
= langs
.begin();
242 l
!= langs
.end(); ++l
)
244 if (*l
== "none") continue;
245 string
const file
= "Translation-" + *l
;
246 new pkgAcqIndexTrans(Owner
, Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
),
247 Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
),
252 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
253 pkgAcquire::MethodConfig
*Cnf
)
256 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
258 string FileName
= LookupTag(Message
,"Filename");
259 if (FileName
.empty() == true)
262 ErrorText
= "Method gave a blank filename";
266 if (FileName
!= DestFile
)
269 Desc
.URI
= "copy:" + FileName
;
274 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
276 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
278 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
279 indexRecords SubIndexParser
;
280 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
282 ErrorText
= SubIndexParser
.ErrorText
;
286 // sucess in downloading the index
289 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
290 Rename(DestFile
,FinalFile
);
291 chmod(FinalFile
.c_str(),0644);
292 DestFile
= FinalFile
;
294 if(ParseIndex(DestFile
) == false)
295 return Failed("", NULL
);
303 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
305 indexRecords SubIndexParser
;
306 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
309 std::vector
<std::string
> lang
= APT::Configuration::getLanguages(true);
310 for (std::vector
<std::string
>::const_iterator l
= lang
.begin();
311 l
!= lang
.end(); ++l
)
316 string file
= "Translation-" + *l
;
317 indexRecords::checkSum
const *Record
= SubIndexParser
.Lookup(file
);
321 // FIXME: the Index file provided by debian currently only includes bz2 records
322 Record
= SubIndexParser
.Lookup(file
+ ".bz2");
328 expected
= Record
->Hash
;
329 if (expected
.empty() == true)
334 target
.Description
= Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
);
335 target
.MetaKey
= file
;
336 target
.ShortDesc
= file
;
337 target
.URI
= Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
);
338 new pkgAcqIndexTrans(Owner
, &target
, expected
, &SubIndexParser
);
343 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
344 // ---------------------------------------------------------------------
345 /* Get the DiffIndex file first and see if there are patches availabe
346 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
347 * patches. If anything goes wrong in that process, it will fall back to
348 * the original packages file
350 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
351 string URI
,string URIDesc
,string ShortDesc
,
352 HashString ExpectedHash
)
353 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
357 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
359 Desc
.Description
= URIDesc
+ "/DiffIndex";
361 Desc
.ShortDesc
= ShortDesc
;
362 Desc
.URI
= URI
+ ".diff/Index";
364 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
365 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
368 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
370 // look for the current package file
371 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
372 CurrentPackagesFile
+= URItoFileName(RealURI
);
374 // FIXME: this file:/ check is a hack to prevent fetching
375 // from local sources. this is really silly, and
376 // should be fixed cleanly as soon as possible
377 if(!FileExists(CurrentPackagesFile
) ||
378 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
380 // we don't have a pkg file or we don't want to queue
382 std::clog
<< "No index file, local or canceld by user" << std::endl
;
388 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
389 << CurrentPackagesFile
<< std::endl
;
395 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
396 // ---------------------------------------------------------------------
397 /* The only header we use is the last-modified header. */
398 string
pkgAcqDiffIndex::Custom600Headers()
400 string Final
= _config
->FindDir("Dir::State::lists");
401 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
404 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
407 if (stat(Final
.c_str(),&Buf
) != 0)
408 return "\nIndex-File: true";
410 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
413 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
416 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
421 vector
<DiffInfo
> available_patches
;
423 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
425 if (_error
->PendingError() == true)
428 if(TF
.Step(Tags
) == true)
434 string
const tmp
= Tags
.FindS("SHA1-Current");
435 std::stringstream
ss(tmp
);
436 ss
>> ServerSha1
>> size
;
437 unsigned long const ServerSize
= atol(size
.c_str());
439 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
441 SHA1
.AddFD(fd
.Fd(), fd
.Size());
442 string
const local_sha1
= SHA1
.Result();
444 if(local_sha1
== ServerSha1
)
446 // we have the same sha1 as the server
448 std::clog
<< "Package file is up-to-date" << std::endl
;
449 // set found to true, this will queue a pkgAcqIndexDiffs with
450 // a empty availabe_patches
456 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
458 // check the historie and see what patches we need
459 string
const history
= Tags
.FindS("SHA1-History");
460 std::stringstream
hist(history
);
461 while(hist
>> d
.sha1
>> size
>> d
.file
)
463 // read until the first match is found
464 // from that point on, we probably need all diffs
465 if(d
.sha1
== local_sha1
)
467 else if (found
== false)
471 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
472 available_patches
.push_back(d
);
475 if (available_patches
.empty() == false)
477 // patching with too many files is rather slow compared to a fast download
478 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
479 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
482 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
483 << ") so fallback to complete download" << std::endl
;
487 // see if the patches are too big
488 found
= false; // it was true and it will be true again at the end
489 d
= *available_patches
.begin();
490 string
const firstPatch
= d
.file
;
491 unsigned long patchesSize
= 0;
492 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
493 while(patches
>> d
.sha1
>> size
>> d
.file
)
495 if (firstPatch
== d
.file
)
497 else if (found
== false)
500 patchesSize
+= atol(size
.c_str());
502 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
503 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
506 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
507 << ") so fallback to complete download" << std::endl
;
513 // we have something, queue the next diff
517 string::size_type
const last_space
= Description
.rfind(" ");
518 if(last_space
!= string::npos
)
519 Description
.erase(last_space
, Description
.size()-last_space
);
520 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
521 ExpectedHash
, ServerSha1
, available_patches
);
529 // Nothing found, report and return false
530 // Failing here is ok, if we return false later, the full
531 // IndexFile is queued
533 std::clog
<< "Can't find a patch in the index file" << std::endl
;
537 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
540 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
541 << "Falling back to normal index file aquire" << std::endl
;
543 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
551 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
552 pkgAcquire::MethodConfig
*Cnf
)
555 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
557 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
560 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
562 // sucess in downloading the index
564 FinalFile
+= string(".IndexDiff");
566 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
568 Rename(DestFile
,FinalFile
);
569 chmod(FinalFile
.c_str(),0644);
570 DestFile
= FinalFile
;
572 if(!ParseDiffIndex(DestFile
))
573 return Failed("", NULL
);
581 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
582 // ---------------------------------------------------------------------
583 /* The package diff is added to the queue. one object is constructed
584 * for each diff and the index
586 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
587 string URI
,string URIDesc
,string ShortDesc
,
588 HashString ExpectedHash
,
590 vector
<DiffInfo
> diffs
)
591 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
592 available_patches(diffs
), ServerSha1(ServerSha1
)
595 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
596 DestFile
+= URItoFileName(URI
);
598 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
600 Description
= URIDesc
;
602 Desc
.ShortDesc
= ShortDesc
;
604 if(available_patches
.size() == 0)
606 // we are done (yeah!)
612 State
= StateFetchDiff
;
617 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
620 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
621 << "Falling back to normal index file aquire" << std::endl
;
622 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
627 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
628 void pkgAcqIndexDiffs::Finish(bool allDone
)
630 // we restore the original name, this is required, otherwise
631 // the file will be cleaned
634 DestFile
= _config
->FindDir("Dir::State::lists");
635 DestFile
+= URItoFileName(RealURI
);
637 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
639 Status
= StatAuthError
;
640 ErrorText
= _("MD5Sum mismatch");
641 Rename(DestFile
,DestFile
+ ".FAILED");
646 // this is for the "real" finish
651 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
656 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
663 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
666 // calc sha1 of the just patched file
667 string FinalFile
= _config
->FindDir("Dir::State::lists");
668 FinalFile
+= URItoFileName(RealURI
);
670 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
672 SHA1
.AddFD(fd
.Fd(), fd
.Size());
673 string local_sha1
= string(SHA1
.Result());
675 std::clog
<< "QueueNextDiff: "
676 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
678 // final file reached before all patches are applied
679 if(local_sha1
== ServerSha1
)
685 // remove all patches until the next matching patch is found
686 // this requires the Index file to be ordered
687 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
688 available_patches
.empty() == false &&
689 I
!= available_patches
.end() &&
690 I
->sha1
!= local_sha1
;
693 available_patches
.erase(I
);
696 // error checking and falling back if no patch was found
697 if(available_patches
.empty() == true)
703 // queue the right diff
704 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
705 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
706 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
707 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
710 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
717 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
718 pkgAcquire::MethodConfig
*Cnf
)
721 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
723 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
726 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
728 // sucess in downloading a diff, enter ApplyDiff state
729 if(State
== StateFetchDiff
)
732 // rred excepts the patch as $FinalFile.ed
733 Rename(DestFile
,FinalFile
+".ed");
736 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
738 State
= StateApplyDiff
;
740 Desc
.URI
= "rred:" + FinalFile
;
747 // success in download/apply a diff, queue next (if needed)
748 if(State
== StateApplyDiff
)
750 // remove the just applied patch
751 available_patches
.erase(available_patches
.begin());
756 std::clog
<< "Moving patched file in place: " << std::endl
757 << DestFile
<< " -> " << FinalFile
<< std::endl
;
759 Rename(DestFile
,FinalFile
);
760 chmod(FinalFile
.c_str(),0644);
762 // see if there is more to download
763 if(available_patches
.empty() == false) {
764 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
765 ExpectedHash
, ServerSha1
, available_patches
);
772 // AcqIndex::AcqIndex - Constructor /*{{{*/
773 // ---------------------------------------------------------------------
774 /* The package file is added to the queue and a second class is
775 instantiated to fetch the revision file */
776 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
777 string URI
,string URIDesc
,string ShortDesc
,
778 HashString ExpectedHash
, string comprExt
)
779 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
781 if(comprExt
.empty() == true)
783 // autoselect the compression method
784 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
785 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
786 comprExt
.append(*t
).append(" ");
787 if (comprExt
.empty() == false)
788 comprExt
.erase(comprExt
.end()-1);
790 CompressionExtension
= comprExt
;
792 Init(URI
, URIDesc
, ShortDesc
);
794 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
795 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
796 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
798 // autoselect the compression method
799 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
800 CompressionExtension
= "";
801 if (ExpectedHash
.empty() == false)
803 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
804 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
805 CompressionExtension
.append(*t
).append(" ");
809 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
810 CompressionExtension
.append(*t
).append(" ");
812 if (CompressionExtension
.empty() == false)
813 CompressionExtension
.erase(CompressionExtension
.end()-1);
815 // only verify non-optional targets, see acquire-item.h for a FIXME
816 // to make this more flexible
817 if (Target
->IsOptional())
822 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
825 // AcqIndex::Init - defered Constructor /*{{{*/
826 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
827 Decompression
= false;
830 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
831 DestFile
+= URItoFileName(URI
);
833 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
834 if (comprExt
== "uncompressed")
837 Desc
.URI
= URI
+ '.' + comprExt
;
839 Desc
.Description
= URIDesc
;
841 Desc
.ShortDesc
= ShortDesc
;
846 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
847 // ---------------------------------------------------------------------
848 /* The only header we use is the last-modified header. */
849 string
pkgAcqIndex::Custom600Headers()
851 string Final
= _config
->FindDir("Dir::State::lists");
852 Final
+= URItoFileName(RealURI
);
853 if (_config
->FindB("Acquire::GzipIndexes",false))
856 string msg
= "\nIndex-File: true";
857 // FIXME: this really should use "IndexTarget::IsOptional()" but that
858 // seems to be difficult without breaking ABI
859 if (ShortDesc().find("Translation") != 0)
860 msg
+= "\nFail-Ignore: true";
862 if (stat(Final
.c_str(),&Buf
) == 0)
863 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
868 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
870 size_t const nextExt
= CompressionExtension
.find(' ');
871 if (nextExt
!= std::string::npos
)
873 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
874 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
878 // on decompression failure, remove bad versions in partial/
879 if (Decompression
&& Erase
) {
880 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
881 s
.append(URItoFileName(RealURI
));
885 Item::Failed(Message
,Cnf
);
888 // AcqIndex::Done - Finished a fetch /*{{{*/
889 // ---------------------------------------------------------------------
890 /* This goes through a number of states.. On the initial fetch the
891 method could possibly return an alternate filename which points
892 to the uncompressed version of the file. If this is so the file
893 is copied into the partial directory. In all other cases the file
894 is decompressed with a gzip uri. */
895 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
896 pkgAcquire::MethodConfig
*Cfg
)
898 Item::Done(Message
,Size
,Hash
,Cfg
);
900 if (Decompression
== true)
902 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
904 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
905 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
908 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
910 Status
= StatAuthError
;
911 ErrorText
= _("Hash Sum mismatch");
912 Rename(DestFile
,DestFile
+ ".FAILED");
913 ReportMirrorFailure("HashChecksumFailure");
917 /* Verify the index file for correctness (all indexes must
918 * have a Package field) (LP: #346386) (Closes: #627642) */
921 FileFd
fd(DestFile
, FileFd::ReadOnly
);
925 // Only test for correctness if the file is not empty (empty is ok)
927 if (_error
->PendingError() || !tag
.Step(sec
)) {
929 _error
->DumpErrors();
930 Rename(DestFile
,DestFile
+ ".FAILED");
932 } else if (!sec
.Exists("Package")) {
934 ErrorText
= ("Encountered a section with no Package: header");
935 Rename(DestFile
,DestFile
+ ".FAILED");
941 // Done, move it into position
942 string FinalFile
= _config
->FindDir("Dir::State::lists");
943 FinalFile
+= URItoFileName(RealURI
);
944 Rename(DestFile
,FinalFile
);
945 chmod(FinalFile
.c_str(),0644);
947 /* We restore the original name to DestFile so that the clean operation
949 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
950 DestFile
+= URItoFileName(RealURI
);
952 // Remove the compressed version.
954 unlink(DestFile
.c_str());
961 // Handle the unzipd case
962 string FileName
= LookupTag(Message
,"Alt-Filename");
963 if (FileName
.empty() == false)
965 // The files timestamp matches
966 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
968 Decompression
= true;
970 DestFile
+= ".decomp";
971 Desc
.URI
= "copy:" + FileName
;
977 FileName
= LookupTag(Message
,"Filename");
978 if (FileName
.empty() == true)
981 ErrorText
= "Method gave a blank filename";
984 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
986 // The files timestamp matches
987 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
988 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
989 // Update DestFile for .gz suffix so that the clean operation keeps it
994 if (FileName
== DestFile
)
1001 // If we enable compressed indexes and already have gzip, keep it
1002 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
1003 string FinalFile
= _config
->FindDir("Dir::State::lists");
1004 FinalFile
+= URItoFileName(RealURI
) + ".gz";
1005 Rename(DestFile
,FinalFile
);
1006 chmod(FinalFile
.c_str(),0644);
1008 // Update DestFile for .gz suffix so that the clean operation keeps it
1009 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1010 DestFile
+= URItoFileName(RealURI
) + ".gz";
1014 // get the binary name for your used compression type
1015 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1016 if(decompProg
.empty() == false);
1017 else if(compExt
== "uncompressed")
1018 decompProg
= "copy";
1020 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1024 Decompression
= true;
1025 DestFile
+= ".decomp";
1026 Desc
.URI
= decompProg
+ ":" + FileName
;
1028 Mode
= decompProg
.c_str();
1031 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1032 // ---------------------------------------------------------------------
1033 /* The Translation file is added to the queue */
1034 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1035 string URI
,string URIDesc
,string ShortDesc
)
1036 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1039 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1040 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1041 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1045 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1046 // ---------------------------------------------------------------------
1047 string
pkgAcqIndexTrans::Custom600Headers()
1049 string Final
= _config
->FindDir("Dir::State::lists");
1050 Final
+= URItoFileName(RealURI
);
1053 if (stat(Final
.c_str(),&Buf
) != 0)
1054 return "\nFail-Ignore: true\nIndex-File: true";
1055 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1058 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1059 // ---------------------------------------------------------------------
1061 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1063 size_t const nextExt
= CompressionExtension
.find(' ');
1064 if (nextExt
!= std::string::npos
)
1066 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1067 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1072 if (Cnf
->LocalOnly
== true ||
1073 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1082 Item::Failed(Message
,Cnf
);
1085 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1086 string URI
,string URIDesc
,string ShortDesc
,
1087 string MetaIndexURI
, string MetaIndexURIDesc
,
1088 string MetaIndexShortDesc
,
1089 const vector
<IndexTarget
*>* IndexTargets
,
1090 indexRecords
* MetaIndexParser
) :
1091 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1092 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1093 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1095 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1096 DestFile
+= URItoFileName(URI
);
1098 // remove any partial downloaded sig-file in partial/.
1099 // it may confuse proxies and is too small to warrant a
1100 // partial download anyway
1101 unlink(DestFile
.c_str());
1104 Desc
.Description
= URIDesc
;
1106 Desc
.ShortDesc
= ShortDesc
;
1109 string Final
= _config
->FindDir("Dir::State::lists");
1110 Final
+= URItoFileName(RealURI
);
1112 if (stat(Final
.c_str(),&Buf
) == 0)
1114 // File was already in place. It needs to be re-downloaded/verified
1115 // because Release might have changed, we do give it a differnt
1116 // name than DestFile because otherwise the http method will
1117 // send If-Range requests and there are too many broken servers
1118 // out there that do not understand them
1119 LastGoodSig
= DestFile
+".reverify";
1120 Rename(Final
,LastGoodSig
);
1126 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1127 // ---------------------------------------------------------------------
1128 /* The only header we use is the last-modified header. */
1129 string
pkgAcqMetaSig::Custom600Headers()
1132 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1133 return "\nIndex-File: true";
1135 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1138 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1139 pkgAcquire::MethodConfig
*Cfg
)
1141 Item::Done(Message
,Size
,MD5
,Cfg
);
1143 string FileName
= LookupTag(Message
,"Filename");
1144 if (FileName
.empty() == true)
1147 ErrorText
= "Method gave a blank filename";
1151 if (FileName
!= DestFile
)
1153 // We have to copy it into place
1155 Desc
.URI
= "copy:" + FileName
;
1162 // put the last known good file back on i-m-s hit (it will
1163 // be re-verified again)
1164 // Else do nothing, we have the new file in DestFile then
1165 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1166 Rename(LastGoodSig
, DestFile
);
1168 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1169 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1170 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1175 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1177 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1179 // if we get a network error we fail gracefully
1180 if(Status
== StatTransientNetworkError
)
1182 Item::Failed(Message
,Cnf
);
1183 // move the sigfile back on transient network failures
1184 if(FileExists(LastGoodSig
))
1185 Rename(LastGoodSig
,Final
);
1187 // set the status back to , Item::Failed likes to reset it
1188 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1192 // Delete any existing sigfile when the acquire failed
1193 unlink(Final
.c_str());
1195 // queue a pkgAcqMetaIndex with no sigfile
1196 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1197 "", IndexTargets
, MetaIndexParser
);
1199 if (Cnf
->LocalOnly
== true ||
1200 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1209 Item::Failed(Message
,Cnf
);
1212 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1213 string URI
,string URIDesc
,string ShortDesc
,
1215 const vector
<struct IndexTarget
*>* IndexTargets
,
1216 indexRecords
* MetaIndexParser
) :
1217 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1218 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1220 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1221 DestFile
+= URItoFileName(URI
);
1224 Desc
.Description
= URIDesc
;
1226 Desc
.ShortDesc
= ShortDesc
;
1232 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1233 // ---------------------------------------------------------------------
1234 /* The only header we use is the last-modified header. */
1235 string
pkgAcqMetaIndex::Custom600Headers()
1237 string Final
= _config
->FindDir("Dir::State::lists");
1238 Final
+= URItoFileName(RealURI
);
1241 if (stat(Final
.c_str(),&Buf
) != 0)
1242 return "\nIndex-File: true";
1244 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1247 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1248 pkgAcquire::MethodConfig
*Cfg
)
1250 Item::Done(Message
,Size
,Hash
,Cfg
);
1252 // MetaIndexes are done in two passes: one to download the
1253 // metaindex with an appropriate method, and a second to verify it
1254 // with the gpgv method
1256 if (AuthPass
== true)
1260 // all cool, move Release file into place
1265 RetrievalDone(Message
);
1267 // Still more retrieving to do
1272 // There was no signature file, so we are finished. Download
1273 // the indexes and do only hashsum verification if possible
1274 MetaIndexParser
->Load(DestFile
);
1275 QueueIndexes(false);
1279 // There was a signature file, so pass it to gpgv for
1282 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1283 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1284 << SigFile
<< "," << DestFile
<< ")\n";
1286 Desc
.URI
= "gpgv:" + SigFile
;
1293 if (Complete
== true)
1295 string FinalFile
= _config
->FindDir("Dir::State::lists");
1296 FinalFile
+= URItoFileName(RealURI
);
1297 if (SigFile
== DestFile
)
1298 SigFile
= FinalFile
;
1299 Rename(DestFile
,FinalFile
);
1300 chmod(FinalFile
.c_str(),0644);
1301 DestFile
= FinalFile
;
1305 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1307 // We have just finished downloading a Release file (it is not
1310 string FileName
= LookupTag(Message
,"Filename");
1311 if (FileName
.empty() == true)
1314 ErrorText
= "Method gave a blank filename";
1318 if (FileName
!= DestFile
)
1321 Desc
.URI
= "copy:" + FileName
;
1326 // make sure to verify against the right file on I-M-S hit
1327 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1330 string FinalFile
= _config
->FindDir("Dir::State::lists");
1331 FinalFile
+= URItoFileName(RealURI
);
1332 if (SigFile
== DestFile
)
1333 SigFile
= FinalFile
;
1334 DestFile
= FinalFile
;
1339 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1341 // At this point, the gpgv method has succeeded, so there is a
1342 // valid signature from a key in the trusted keyring. We
1343 // perform additional verification of its contents, and use them
1344 // to verify the indexes we are about to download
1346 if (!MetaIndexParser
->Load(DestFile
))
1348 Status
= StatAuthError
;
1349 ErrorText
= MetaIndexParser
->ErrorText
;
1353 if (!VerifyVendor(Message
))
1358 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1359 std::cerr
<< "Signature verification succeeded: "
1360 << DestFile
<< std::endl
;
1362 // Download further indexes with verification
1365 // is it a clearsigned MetaIndex file?
1366 if (DestFile
== SigFile
)
1369 // Done, move signature file into position
1370 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1371 URItoFileName(RealURI
) + ".gpg";
1372 Rename(SigFile
,VerifiedSigFile
);
1373 chmod(VerifiedSigFile
.c_str(),0644);
1376 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1379 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1380 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1381 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1384 ErrorText
= MetaIndexParser
->ErrorText
;
1388 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1389 Target
!= IndexTargets
->end();
1392 HashString ExpectedIndexHash
;
1393 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1396 if (verify
== true && (*Target
)->IsOptional() == false)
1398 Status
= StatAuthError
;
1399 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1405 ExpectedIndexHash
= Record
->Hash
;
1406 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1408 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1409 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1410 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1412 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1414 Status
= StatAuthError
;
1415 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1420 if ((*Target
)->IsOptional() == true)
1422 if ((*Target
)->IsSubIndex() == true)
1423 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1424 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1426 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1430 /* Queue Packages file (either diff or full packages files, depending
1431 on the users option) - we also check if the PDiff Index file is listed
1432 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1433 instead, but passing the required info to it is to much hassle */
1434 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1435 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1436 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1437 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1439 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1443 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1445 string::size_type pos
;
1447 // check for missing sigs (that where not fatal because otherwise we had
1450 string msg
= _("There is no public key available for the "
1451 "following key IDs:\n");
1452 pos
= Message
.find("NO_PUBKEY ");
1453 if (pos
!= std::string::npos
)
1455 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1456 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1457 missingkeys
+= (Fingerprint
);
1459 if(!missingkeys
.empty())
1460 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1462 string Transformed
= MetaIndexParser
->GetExpectedDist();
1464 if (Transformed
== "../project/experimental")
1466 Transformed
= "experimental";
1469 pos
= Transformed
.rfind('/');
1470 if (pos
!= string::npos
)
1472 Transformed
= Transformed
.substr(0, pos
);
1475 if (Transformed
== ".")
1480 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1481 MetaIndexParser
->GetValidUntil() > 0) {
1482 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1483 if (invalid_since
> 0)
1484 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1485 // the time since then the file is invalid - formated in the same way as in
1486 // the download progress display (e.g. 7d 3h 42min 1s)
1487 return _error
->Error(
1488 _("Release file for %s is expired (invalid since %s). "
1489 "Updates for this repository will not be applied."),
1490 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1493 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1495 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1496 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1497 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1500 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1502 // This might become fatal one day
1503 // Status = StatAuthError;
1504 // ErrorText = "Conflicting distribution; expected "
1505 // + MetaIndexParser->GetExpectedDist() + " but got "
1506 // + MetaIndexParser->GetDist();
1508 if (!Transformed
.empty())
1510 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1511 Desc
.Description
.c_str(),
1512 Transformed
.c_str(),
1513 MetaIndexParser
->GetDist().c_str());
1520 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1521 // ---------------------------------------------------------------------
1523 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1525 if (AuthPass
== true)
1527 // gpgv method failed, if we have a good signature
1528 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists");
1529 if (DestFile
== SigFile
)
1530 LastGoodSigFile
.append(URItoFileName(RealURI
));
1532 LastGoodSigFile
.append("partial/").append(URItoFileName(RealURI
)).append(".gpg.reverify");
1534 if(FileExists(LastGoodSigFile
))
1536 if (DestFile
!= SigFile
)
1538 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1539 URItoFileName(RealURI
) + ".gpg";
1540 Rename(LastGoodSigFile
,VerifiedSigFile
);
1542 Status
= StatTransientNetworkError
;
1543 _error
->Warning(_("A error occurred during the signature "
1544 "verification. The repository is not updated "
1545 "and the previous index files will be used. "
1546 "GPG error: %s: %s\n"),
1547 Desc
.Description
.c_str(),
1548 LookupTag(Message
,"Message").c_str());
1549 RunScripts("APT::Update::Auth-Failure");
1551 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1552 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1553 _error
->Error(_("GPG error: %s: %s"),
1554 Desc
.Description
.c_str(),
1555 LookupTag(Message
,"Message").c_str());
1558 _error
->Warning(_("GPG error: %s: %s"),
1559 Desc
.Description
.c_str(),
1560 LookupTag(Message
,"Message").c_str());
1562 // gpgv method failed
1563 ReportMirrorFailure("GPGFailure");
1566 /* Always move the meta index, even if gpgv failed. This ensures
1567 * that PackageFile objects are correctly filled in */
1568 if (FileExists(DestFile
)) {
1569 string FinalFile
= _config
->FindDir("Dir::State::lists");
1570 FinalFile
+= URItoFileName(RealURI
);
1571 /* InRelease files become Release files, otherwise
1572 * they would be considered as trusted later on */
1573 if (SigFile
== DestFile
) {
1574 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1576 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1578 SigFile
= FinalFile
;
1580 Rename(DestFile
,FinalFile
);
1581 chmod(FinalFile
.c_str(),0644);
1583 DestFile
= FinalFile
;
1586 // No Release file was present, or verification failed, so fall
1587 // back to queueing Packages files without verification
1588 QueueIndexes(false);
1591 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1592 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1593 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1594 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1595 const vector
<struct IndexTarget
*>* IndexTargets
,
1596 indexRecords
* MetaIndexParser
) :
1597 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1598 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1599 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1604 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1605 // ---------------------------------------------------------------------
1606 // FIXME: this can go away once the InRelease file is used widely
1607 string
pkgAcqMetaClearSig::Custom600Headers()
1609 string Final
= _config
->FindDir("Dir::State::lists");
1610 Final
+= URItoFileName(RealURI
);
1613 if (stat(Final
.c_str(),&Buf
) != 0)
1614 return "\nIndex-File: true\nFail-Ignore: true\n";
1616 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1619 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1621 if (AuthPass
== false)
1623 new pkgAcqMetaSig(Owner
,
1624 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1625 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1626 IndexTargets
, MetaIndexParser
);
1627 if (Cnf
->LocalOnly
== true ||
1628 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1632 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1635 // AcqArchive::AcqArchive - Constructor /*{{{*/
1636 // ---------------------------------------------------------------------
1637 /* This just sets up the initial fetch environment and queues the first
1639 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1640 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1641 string
&StoreFilename
) :
1642 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1643 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1646 Retries
= _config
->FindI("Acquire::Retries",0);
1648 if (Version
.Arch() == 0)
1650 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1651 "This might mean you need to manually fix this package. "
1652 "(due to missing arch)"),
1653 Version
.ParentPkg().Name());
1657 /* We need to find a filename to determine the extension. We make the
1658 assumption here that all the available sources for this version share
1659 the same extension.. */
1660 // Skip not source sources, they do not have file fields.
1661 for (; Vf
.end() == false; Vf
++)
1663 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1668 // Does not really matter here.. we are going to fail out below
1669 if (Vf
.end() != true)
1671 // If this fails to get a file name we will bomb out below.
1672 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1673 if (_error
->PendingError() == true)
1676 // Generate the final file name as: package_version_arch.foo
1677 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1678 QuoteString(Version
.VerStr(),"_:") + '_' +
1679 QuoteString(Version
.Arch(),"_:.") +
1680 "." + flExtension(Parse
.FileName());
1683 // check if we have one trusted source for the package. if so, switch
1684 // to "TrustedOnly" mode
1685 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1687 pkgIndexFile
*Index
;
1688 if (Sources
->FindIndex(i
.File(),Index
) == false)
1690 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1692 std::cerr
<< "Checking index: " << Index
->Describe()
1693 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1695 if (Index
->IsTrusted()) {
1701 // "allow-unauthenticated" restores apts old fetching behaviour
1702 // that means that e.g. unauthenticated file:// uris are higher
1703 // priority than authenticated http:// uris
1704 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1708 if (QueueNext() == false && _error
->PendingError() == false)
1709 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1710 "This might mean you need to manually fix this package."),
1711 Version
.ParentPkg().Name());
1714 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1715 // ---------------------------------------------------------------------
1716 /* This queues the next available file version for download. It checks if
1717 the archive is already available in the cache and stashs the MD5 for
1719 bool pkgAcqArchive::QueueNext()
1721 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1722 for (; Vf
.end() == false; ++Vf
)
1724 // Ignore not source sources
1725 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1728 // Try to cross match against the source list
1729 pkgIndexFile
*Index
;
1730 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1733 // only try to get a trusted package from another source if that source
1735 if(Trusted
&& !Index
->IsTrusted())
1738 // Grab the text package record
1739 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1740 if (_error
->PendingError() == true)
1743 string PkgFile
= Parse
.FileName();
1744 if (ForceHash
.empty() == false)
1746 if(stringcasecmp(ForceHash
, "sha512") == 0)
1747 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
1748 if(stringcasecmp(ForceHash
, "sha256") == 0)
1749 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1750 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1751 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1753 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1758 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
1759 ExpectedHash
= HashString("SHA512", Hash
);
1760 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1761 ExpectedHash
= HashString("SHA256", Hash
);
1762 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1763 ExpectedHash
= HashString("SHA1", Hash
);
1765 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1767 if (PkgFile
.empty() == true)
1768 return _error
->Error(_("The package index files are corrupted. No Filename: "
1769 "field for package %s."),
1770 Version
.ParentPkg().Name());
1772 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1773 Desc
.Description
= Index
->ArchiveInfo(Version
);
1775 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1777 // See if we already have the file. (Legacy filenames)
1778 FileSize
= Version
->Size
;
1779 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1781 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1783 // Make sure the size matches
1784 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1789 StoreFilename
= DestFile
= FinalFile
;
1793 /* Hmm, we have a file and its size does not match, this means it is
1794 an old style mismatched arch */
1795 unlink(FinalFile
.c_str());
1798 // Check it again using the new style output filenames
1799 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1800 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1802 // Make sure the size matches
1803 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1808 StoreFilename
= DestFile
= FinalFile
;
1812 /* Hmm, we have a file and its size does not match, this shouldnt
1814 unlink(FinalFile
.c_str());
1817 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1819 // Check the destination file
1820 if (stat(DestFile
.c_str(),&Buf
) == 0)
1822 // Hmm, the partial file is too big, erase it
1823 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
1824 unlink(DestFile
.c_str());
1826 PartialSize
= Buf
.st_size
;
1831 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1832 Desc
.Description
= Index
->ArchiveInfo(Version
);
1834 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1843 // AcqArchive::Done - Finished fetching /*{{{*/
1844 // ---------------------------------------------------------------------
1846 void pkgAcqArchive::Done(string Message
,unsigned long long Size
,string CalcHash
,
1847 pkgAcquire::MethodConfig
*Cfg
)
1849 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1852 if (Size
!= Version
->Size
)
1855 ErrorText
= _("Size mismatch");
1860 if(ExpectedHash
.toStr() != CalcHash
)
1863 ErrorText
= _("Hash Sum mismatch");
1864 if(FileExists(DestFile
))
1865 Rename(DestFile
,DestFile
+ ".FAILED");
1869 // Grab the output filename
1870 string FileName
= LookupTag(Message
,"Filename");
1871 if (FileName
.empty() == true)
1874 ErrorText
= "Method gave a blank filename";
1880 // Reference filename
1881 if (FileName
!= DestFile
)
1883 StoreFilename
= DestFile
= FileName
;
1888 // Done, move it into position
1889 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1890 FinalFile
+= flNotDir(StoreFilename
);
1891 Rename(DestFile
,FinalFile
);
1893 StoreFilename
= DestFile
= FinalFile
;
1897 // AcqArchive::Failed - Failure handler /*{{{*/
1898 // ---------------------------------------------------------------------
1899 /* Here we try other sources */
1900 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1902 ErrorText
= LookupTag(Message
,"Message");
1904 /* We don't really want to retry on failed media swaps, this prevents
1905 that. An interesting observation is that permanent failures are not
1907 if (Cnf
->Removable
== true &&
1908 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1910 // Vf = Version.FileList();
1911 while (Vf
.end() == false) ++Vf
;
1912 StoreFilename
= string();
1913 Item::Failed(Message
,Cnf
);
1917 if (QueueNext() == false)
1919 // This is the retry counter
1921 Cnf
->LocalOnly
== false &&
1922 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1925 Vf
= Version
.FileList();
1926 if (QueueNext() == true)
1930 StoreFilename
= string();
1931 Item::Failed(Message
,Cnf
);
1935 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1936 // ---------------------------------------------------------------------
1937 bool pkgAcqArchive::IsTrusted()
1942 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1943 // ---------------------------------------------------------------------
1945 void pkgAcqArchive::Finished()
1947 if (Status
== pkgAcquire::Item::StatDone
&&
1950 StoreFilename
= string();
1953 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1954 // ---------------------------------------------------------------------
1955 /* The file is added to the queue */
1956 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1957 unsigned long long Size
,string Dsc
,string ShortDesc
,
1958 const string
&DestDir
, const string
&DestFilename
,
1960 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
1962 Retries
= _config
->FindI("Acquire::Retries",0);
1964 if(!DestFilename
.empty())
1965 DestFile
= DestFilename
;
1966 else if(!DestDir
.empty())
1967 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1969 DestFile
= flNotDir(URI
);
1973 Desc
.Description
= Dsc
;
1976 // Set the short description to the archive component
1977 Desc
.ShortDesc
= ShortDesc
;
1979 // Get the transfer sizes
1982 if (stat(DestFile
.c_str(),&Buf
) == 0)
1984 // Hmm, the partial file is too big, erase it
1985 if ((unsigned long long)Buf
.st_size
> Size
)
1986 unlink(DestFile
.c_str());
1988 PartialSize
= Buf
.st_size
;
1994 // AcqFile::Done - Item downloaded OK /*{{{*/
1995 // ---------------------------------------------------------------------
1997 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
1998 pkgAcquire::MethodConfig
*Cnf
)
2000 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2003 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2006 ErrorText
= _("Hash Sum mismatch");
2007 Rename(DestFile
,DestFile
+ ".FAILED");
2011 string FileName
= LookupTag(Message
,"Filename");
2012 if (FileName
.empty() == true)
2015 ErrorText
= "Method gave a blank filename";
2021 // The files timestamp matches
2022 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2025 // We have to copy it into place
2026 if (FileName
!= DestFile
)
2029 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2030 Cnf
->Removable
== true)
2032 Desc
.URI
= "copy:" + FileName
;
2037 // Erase the file if it is a symlink so we can overwrite it
2039 if (lstat(DestFile
.c_str(),&St
) == 0)
2041 if (S_ISLNK(St
.st_mode
) != 0)
2042 unlink(DestFile
.c_str());
2046 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2048 ErrorText
= "Link to " + DestFile
+ " failure ";
2055 // AcqFile::Failed - Failure handler /*{{{*/
2056 // ---------------------------------------------------------------------
2057 /* Here we try other sources */
2058 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2060 ErrorText
= LookupTag(Message
,"Message");
2062 // This is the retry counter
2064 Cnf
->LocalOnly
== false &&
2065 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2072 Item::Failed(Message
,Cnf
);
2075 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2076 // ---------------------------------------------------------------------
2077 /* The only header we use is the last-modified header. */
2078 string
pkgAcqFile::Custom600Headers()
2081 return "\nIndex-File: true";