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 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
148 if(FileExists(DestFile
))
149 Rename(DestFile
, DestFile
+ ".FAILED");
153 case HashSumMismatch
:
154 ErrorText
= _("Hash Sum mismatch");
155 Status
= StatAuthError
;
156 ReportMirrorFailure("HashChecksumFailure");
159 ErrorText
= _("Size mismatch");
160 Status
= StatAuthError
;
161 ReportMirrorFailure("SizeFailure");
164 ErrorText
= _("Invalid file format");
166 // do not report as usually its not the mirrors fault, but Portal/Proxy
172 // Acquire::Item::ReportMirrorFailure /*{{{*/
173 // ---------------------------------------------------------------------
174 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
176 // we only act if a mirror was used at all
177 if(UsedMirror
.empty())
180 std::cerr
<< "\nReportMirrorFailure: "
182 << " Uri: " << DescURI()
184 << FailCode
<< std::endl
;
186 const char *Args
[40];
188 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
189 "/usr/lib/apt/apt-report-mirror-failure");
190 if(!FileExists(report
))
192 Args
[i
++] = report
.c_str();
193 Args
[i
++] = UsedMirror
.c_str();
194 Args
[i
++] = DescURI().c_str();
195 Args
[i
++] = FailCode
.c_str();
197 pid_t pid
= ExecFork();
200 _error
->Error("ReportMirrorFailure Fork failed");
205 execvp(Args
[0], (char**)Args
);
206 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
209 if(!ExecWait(pid
, "report-mirror-failure"))
211 _error
->Warning("Couldn't report problem to '%s'",
212 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
216 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
217 // ---------------------------------------------------------------------
218 /* Get a sub-index file based on checksums from a 'master' file and
219 possibly query additional files */
220 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
221 string
const &URIDesc
, string
const &ShortDesc
,
222 HashString
const &ExpectedHash
)
223 : Item(Owner
), ExpectedHash(ExpectedHash
)
225 /* XXX: Beware: Currently this class does nothing (of value) anymore ! */
226 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
228 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
229 DestFile
+= URItoFileName(URI
);
232 Desc
.Description
= URIDesc
;
234 Desc
.ShortDesc
= ShortDesc
;
239 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
242 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
243 // ---------------------------------------------------------------------
244 /* The only header we use is the last-modified header. */
245 string
pkgAcqSubIndex::Custom600Headers()
247 string Final
= _config
->FindDir("Dir::State::lists");
248 Final
+= URItoFileName(Desc
.URI
);
251 if (stat(Final
.c_str(),&Buf
) != 0)
252 return "\nIndex-File: true\nFail-Ignore: true\n";
253 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
256 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
259 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< std::endl
;
265 // No good Index is provided
268 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
269 pkgAcquire::MethodConfig
*Cnf
)
272 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
274 string FileName
= LookupTag(Message
,"Filename");
275 if (FileName
.empty() == true)
278 ErrorText
= "Method gave a blank filename";
282 if (FileName
!= DestFile
)
285 Desc
.URI
= "copy:" + FileName
;
290 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
292 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
294 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
295 indexRecords SubIndexParser
;
296 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
298 ErrorText
= SubIndexParser
.ErrorText
;
302 // sucess in downloading the index
305 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
306 Rename(DestFile
,FinalFile
);
307 chmod(FinalFile
.c_str(),0644);
308 DestFile
= FinalFile
;
310 if(ParseIndex(DestFile
) == false)
311 return Failed("", NULL
);
319 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
321 indexRecords SubIndexParser
;
322 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
324 // so something with the downloaded index
328 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
329 // ---------------------------------------------------------------------
330 /* Get the DiffIndex file first and see if there are patches availabe
331 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
332 * patches. If anything goes wrong in that process, it will fall back to
333 * the original packages file
335 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
336 string URI
,string URIDesc
,string ShortDesc
,
337 HashString ExpectedHash
)
338 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
342 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
344 Desc
.Description
= URIDesc
+ "/DiffIndex";
346 Desc
.ShortDesc
= ShortDesc
;
347 Desc
.URI
= URI
+ ".diff/Index";
349 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
350 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
353 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
355 // look for the current package file
356 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
357 CurrentPackagesFile
+= URItoFileName(RealURI
);
359 // FIXME: this file:/ check is a hack to prevent fetching
360 // from local sources. this is really silly, and
361 // should be fixed cleanly as soon as possible
362 if(!FileExists(CurrentPackagesFile
) ||
363 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
365 // we don't have a pkg file or we don't want to queue
367 std::clog
<< "No index file, local or canceld by user" << std::endl
;
373 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
374 << CurrentPackagesFile
<< std::endl
;
380 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
381 // ---------------------------------------------------------------------
382 /* The only header we use is the last-modified header. */
383 string
pkgAcqDiffIndex::Custom600Headers()
385 string Final
= _config
->FindDir("Dir::State::lists");
386 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
389 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
392 if (stat(Final
.c_str(),&Buf
) != 0)
393 return "\nIndex-File: true";
395 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
398 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
401 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
406 vector
<DiffInfo
> available_patches
;
408 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
410 if (_error
->PendingError() == true)
413 if(TF
.Step(Tags
) == true)
419 string
const tmp
= Tags
.FindS("SHA1-Current");
420 std::stringstream
ss(tmp
);
421 ss
>> ServerSha1
>> size
;
422 unsigned long const ServerSize
= atol(size
.c_str());
424 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
427 string
const local_sha1
= SHA1
.Result();
429 if(local_sha1
== ServerSha1
)
431 // we have the same sha1 as the server
433 std::clog
<< "Package file is up-to-date" << std::endl
;
434 // set found to true, this will queue a pkgAcqIndexDiffs with
435 // a empty availabe_patches
441 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
443 // check the historie and see what patches we need
444 string
const history
= Tags
.FindS("SHA1-History");
445 std::stringstream
hist(history
);
446 while(hist
>> d
.sha1
>> size
>> d
.file
)
448 // read until the first match is found
449 // from that point on, we probably need all diffs
450 if(d
.sha1
== local_sha1
)
452 else if (found
== false)
456 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
457 available_patches
.push_back(d
);
460 if (available_patches
.empty() == false)
462 // patching with too many files is rather slow compared to a fast download
463 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 20);
464 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
467 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
468 << ") so fallback to complete download" << std::endl
;
472 // see if the patches are too big
473 found
= false; // it was true and it will be true again at the end
474 d
= *available_patches
.begin();
475 string
const firstPatch
= d
.file
;
476 unsigned long patchesSize
= 0;
477 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
478 while(patches
>> d
.sha1
>> size
>> d
.file
)
480 if (firstPatch
== d
.file
)
482 else if (found
== false)
485 patchesSize
+= atol(size
.c_str());
487 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
488 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
491 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
492 << ") so fallback to complete download" << std::endl
;
498 // we have something, queue the next diff
502 string::size_type
const last_space
= Description
.rfind(" ");
503 if(last_space
!= string::npos
)
504 Description
.erase(last_space
, Description
.size()-last_space
);
505 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
506 ExpectedHash
, ServerSha1
, available_patches
);
514 // Nothing found, report and return false
515 // Failing here is ok, if we return false later, the full
516 // IndexFile is queued
518 std::clog
<< "Can't find a patch in the index file" << std::endl
;
522 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
525 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
526 << "Falling back to normal index file aquire" << std::endl
;
528 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
536 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
537 pkgAcquire::MethodConfig
*Cnf
)
540 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
542 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
545 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
547 // sucess in downloading the index
549 FinalFile
+= string(".IndexDiff");
551 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
553 Rename(DestFile
,FinalFile
);
554 chmod(FinalFile
.c_str(),0644);
555 DestFile
= FinalFile
;
557 if(!ParseDiffIndex(DestFile
))
558 return Failed("", NULL
);
566 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
567 // ---------------------------------------------------------------------
568 /* The package diff is added to the queue. one object is constructed
569 * for each diff and the index
571 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
572 string URI
,string URIDesc
,string ShortDesc
,
573 HashString ExpectedHash
,
575 vector
<DiffInfo
> diffs
)
576 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
577 available_patches(diffs
), ServerSha1(ServerSha1
)
580 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
581 DestFile
+= URItoFileName(URI
);
583 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
585 Description
= URIDesc
;
587 Desc
.ShortDesc
= ShortDesc
;
589 if(available_patches
.empty() == true)
591 // we are done (yeah!)
597 State
= StateFetchDiff
;
602 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
605 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
606 << "Falling back to normal index file aquire" << std::endl
;
607 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
612 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
613 void pkgAcqIndexDiffs::Finish(bool allDone
)
615 // we restore the original name, this is required, otherwise
616 // the file will be cleaned
619 DestFile
= _config
->FindDir("Dir::State::lists");
620 DestFile
+= URItoFileName(RealURI
);
622 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
624 RenameOnError(HashSumMismatch
);
629 // this is for the "real" finish
634 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
639 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
646 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
649 // calc sha1 of the just patched file
650 string FinalFile
= _config
->FindDir("Dir::State::lists");
651 FinalFile
+= URItoFileName(RealURI
);
653 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
656 string local_sha1
= string(SHA1
.Result());
658 std::clog
<< "QueueNextDiff: "
659 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
661 // final file reached before all patches are applied
662 if(local_sha1
== ServerSha1
)
668 // remove all patches until the next matching patch is found
669 // this requires the Index file to be ordered
670 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
671 available_patches
.empty() == false &&
672 I
!= available_patches
.end() &&
673 I
->sha1
!= local_sha1
;
676 available_patches
.erase(I
);
679 // error checking and falling back if no patch was found
680 if(available_patches
.empty() == true)
686 // queue the right diff
687 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
688 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
689 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
690 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
693 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
700 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
701 pkgAcquire::MethodConfig
*Cnf
)
704 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
706 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
709 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
711 // sucess in downloading a diff, enter ApplyDiff state
712 if(State
== StateFetchDiff
)
715 // rred excepts the patch as $FinalFile.ed
716 Rename(DestFile
,FinalFile
+".ed");
719 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
721 State
= StateApplyDiff
;
723 Desc
.URI
= "rred:" + FinalFile
;
730 // success in download/apply a diff, queue next (if needed)
731 if(State
== StateApplyDiff
)
733 // remove the just applied patch
734 available_patches
.erase(available_patches
.begin());
739 std::clog
<< "Moving patched file in place: " << std::endl
740 << DestFile
<< " -> " << FinalFile
<< std::endl
;
742 Rename(DestFile
,FinalFile
);
743 chmod(FinalFile
.c_str(),0644);
745 // see if there is more to download
746 if(available_patches
.empty() == false) {
747 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
748 ExpectedHash
, ServerSha1
, available_patches
);
755 // AcqIndex::AcqIndex - Constructor /*{{{*/
756 // ---------------------------------------------------------------------
757 /* The package file is added to the queue and a second class is
758 instantiated to fetch the revision file */
759 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
760 string URI
,string URIDesc
,string ShortDesc
,
761 HashString ExpectedHash
, string comprExt
)
762 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
764 if(comprExt
.empty() == true)
766 // autoselect the compression method
767 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
768 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
769 comprExt
.append(*t
).append(" ");
770 if (comprExt
.empty() == false)
771 comprExt
.erase(comprExt
.end()-1);
773 CompressionExtension
= comprExt
;
775 Init(URI
, URIDesc
, ShortDesc
);
777 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
778 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
779 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
781 // autoselect the compression method
782 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
783 CompressionExtension
= "";
784 if (ExpectedHash
.empty() == false)
786 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
787 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
788 CompressionExtension
.append(*t
).append(" ");
792 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
793 CompressionExtension
.append(*t
).append(" ");
795 if (CompressionExtension
.empty() == false)
796 CompressionExtension
.erase(CompressionExtension
.end()-1);
798 // only verify non-optional targets, see acquire-item.h for a FIXME
799 // to make this more flexible
800 if (Target
->IsOptional())
805 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
808 // AcqIndex::Init - defered Constructor /*{{{*/
809 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
810 Decompression
= false;
813 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
814 DestFile
+= URItoFileName(URI
);
816 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
817 if (comprExt
== "uncompressed")
820 Desc
.URI
= URI
+ '.' + comprExt
;
822 Desc
.Description
= URIDesc
;
824 Desc
.ShortDesc
= ShortDesc
;
829 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
830 // ---------------------------------------------------------------------
831 /* The only header we use is the last-modified header. */
832 string
pkgAcqIndex::Custom600Headers()
834 string Final
= _config
->FindDir("Dir::State::lists");
835 Final
+= URItoFileName(RealURI
);
836 if (_config
->FindB("Acquire::GzipIndexes",false))
839 string msg
= "\nIndex-File: true";
840 // FIXME: this really should use "IndexTarget::IsOptional()" but that
841 // seems to be difficult without breaking ABI
842 if (ShortDesc().find("Translation") != 0)
843 msg
+= "\nFail-Ignore: true";
845 if (stat(Final
.c_str(),&Buf
) == 0)
846 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
851 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
853 size_t const nextExt
= CompressionExtension
.find(' ');
854 if (nextExt
!= std::string::npos
)
856 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
857 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
861 // on decompression failure, remove bad versions in partial/
862 if (Decompression
&& Erase
) {
863 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
864 s
.append(URItoFileName(RealURI
));
868 Item::Failed(Message
,Cnf
);
871 // AcqIndex::Done - Finished a fetch /*{{{*/
872 // ---------------------------------------------------------------------
873 /* This goes through a number of states.. On the initial fetch the
874 method could possibly return an alternate filename which points
875 to the uncompressed version of the file. If this is so the file
876 is copied into the partial directory. In all other cases the file
877 is decompressed with a gzip uri. */
878 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
879 pkgAcquire::MethodConfig
*Cfg
)
881 Item::Done(Message
,Size
,Hash
,Cfg
);
883 if (Decompression
== true)
885 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
887 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
888 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
891 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
893 RenameOnError(HashSumMismatch
);
897 /* Verify the index file for correctness (all indexes must
898 * have a Package field) (LP: #346386) (Closes: #627642) */
901 FileFd
fd(DestFile
, FileFd::ReadOnly
);
902 // Only test for correctness if the file is not empty (empty is ok)
903 if (fd
.FileSize() > 0)
908 // all our current indexes have a field 'Package' in each section
909 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
911 RenameOnError(InvalidFormat
);
917 // Done, move it into position
918 string FinalFile
= _config
->FindDir("Dir::State::lists");
919 FinalFile
+= URItoFileName(RealURI
);
920 Rename(DestFile
,FinalFile
);
921 chmod(FinalFile
.c_str(),0644);
923 /* We restore the original name to DestFile so that the clean operation
925 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
926 DestFile
+= URItoFileName(RealURI
);
928 // Remove the compressed version.
930 unlink(DestFile
.c_str());
937 // Handle the unzipd case
938 string FileName
= LookupTag(Message
,"Alt-Filename");
939 if (FileName
.empty() == false)
941 // The files timestamp matches
942 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
944 Decompression
= true;
946 DestFile
+= ".decomp";
947 Desc
.URI
= "copy:" + FileName
;
953 FileName
= LookupTag(Message
,"Filename");
954 if (FileName
.empty() == true)
957 ErrorText
= "Method gave a blank filename";
960 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
962 // The files timestamp matches
963 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
964 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
965 // Update DestFile for .gz suffix so that the clean operation keeps it
970 if (FileName
== DestFile
)
977 // If we enable compressed indexes and already have gzip, keep it
978 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
979 string FinalFile
= _config
->FindDir("Dir::State::lists");
980 FinalFile
+= URItoFileName(RealURI
) + ".gz";
981 Rename(DestFile
,FinalFile
);
982 chmod(FinalFile
.c_str(),0644);
984 // Update DestFile for .gz suffix so that the clean operation keeps it
985 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
986 DestFile
+= URItoFileName(RealURI
) + ".gz";
990 // get the binary name for your used compression type
991 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
992 if(decompProg
.empty() == false);
993 else if(compExt
== "uncompressed")
996 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1000 Decompression
= true;
1001 DestFile
+= ".decomp";
1002 Desc
.URI
= decompProg
+ ":" + FileName
;
1005 // FIXME: this points to a c++ string that goes out of scope
1006 Mode
= decompProg
.c_str();
1009 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1010 // ---------------------------------------------------------------------
1011 /* The Translation file is added to the queue */
1012 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1013 string URI
,string URIDesc
,string ShortDesc
)
1014 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1017 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1018 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1019 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1023 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1024 // ---------------------------------------------------------------------
1025 string
pkgAcqIndexTrans::Custom600Headers()
1027 string Final
= _config
->FindDir("Dir::State::lists");
1028 Final
+= URItoFileName(RealURI
);
1031 if (stat(Final
.c_str(),&Buf
) != 0)
1032 return "\nFail-Ignore: true\nIndex-File: true";
1033 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1036 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1037 // ---------------------------------------------------------------------
1039 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1041 size_t const nextExt
= CompressionExtension
.find(' ');
1042 if (nextExt
!= std::string::npos
)
1044 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1045 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1050 if (Cnf
->LocalOnly
== true ||
1051 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1060 Item::Failed(Message
,Cnf
);
1063 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1064 string URI
,string URIDesc
,string ShortDesc
,
1065 string MetaIndexURI
, string MetaIndexURIDesc
,
1066 string MetaIndexShortDesc
,
1067 const vector
<IndexTarget
*>* IndexTargets
,
1068 indexRecords
* MetaIndexParser
) :
1069 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1070 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1071 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1073 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1074 DestFile
+= URItoFileName(URI
);
1076 // remove any partial downloaded sig-file in partial/.
1077 // it may confuse proxies and is too small to warrant a
1078 // partial download anyway
1079 unlink(DestFile
.c_str());
1082 Desc
.Description
= URIDesc
;
1084 Desc
.ShortDesc
= ShortDesc
;
1087 string Final
= _config
->FindDir("Dir::State::lists");
1088 Final
+= URItoFileName(RealURI
);
1089 if (RealFileExists(Final
) == true)
1091 // File was already in place. It needs to be re-downloaded/verified
1092 // because Release might have changed, we do give it a differnt
1093 // name than DestFile because otherwise the http method will
1094 // send If-Range requests and there are too many broken servers
1095 // out there that do not understand them
1096 LastGoodSig
= DestFile
+".reverify";
1097 Rename(Final
,LastGoodSig
);
1103 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1105 // if the file was never queued undo file-changes done in the constructor
1106 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1107 LastGoodSig
.empty() == false)
1109 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1110 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1111 Rename(LastGoodSig
, Final
);
1116 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1117 // ---------------------------------------------------------------------
1118 /* The only header we use is the last-modified header. */
1119 string
pkgAcqMetaSig::Custom600Headers()
1122 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1123 return "\nIndex-File: true";
1125 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1128 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1129 pkgAcquire::MethodConfig
*Cfg
)
1131 Item::Done(Message
,Size
,MD5
,Cfg
);
1133 string FileName
= LookupTag(Message
,"Filename");
1134 if (FileName
.empty() == true)
1137 ErrorText
= "Method gave a blank filename";
1141 if (FileName
!= DestFile
)
1143 // We have to copy it into place
1145 Desc
.URI
= "copy:" + FileName
;
1152 // put the last known good file back on i-m-s hit (it will
1153 // be re-verified again)
1154 // Else do nothing, we have the new file in DestFile then
1155 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1156 Rename(LastGoodSig
, DestFile
);
1158 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1159 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1160 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1165 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1167 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1169 // if we get a network error we fail gracefully
1170 if(Status
== StatTransientNetworkError
)
1172 Item::Failed(Message
,Cnf
);
1173 // move the sigfile back on transient network failures
1174 if(FileExists(LastGoodSig
))
1175 Rename(LastGoodSig
,Final
);
1177 // set the status back to , Item::Failed likes to reset it
1178 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1182 // Delete any existing sigfile when the acquire failed
1183 unlink(Final
.c_str());
1185 // queue a pkgAcqMetaIndex with no sigfile
1186 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1187 "", IndexTargets
, MetaIndexParser
);
1189 if (Cnf
->LocalOnly
== true ||
1190 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1199 Item::Failed(Message
,Cnf
);
1202 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1203 string URI
,string URIDesc
,string ShortDesc
,
1205 const vector
<struct IndexTarget
*>* IndexTargets
,
1206 indexRecords
* MetaIndexParser
) :
1207 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1208 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1210 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1211 DestFile
+= URItoFileName(URI
);
1214 Desc
.Description
= URIDesc
;
1216 Desc
.ShortDesc
= ShortDesc
;
1222 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1223 // ---------------------------------------------------------------------
1224 /* The only header we use is the last-modified header. */
1225 string
pkgAcqMetaIndex::Custom600Headers()
1227 string Final
= _config
->FindDir("Dir::State::lists");
1228 Final
+= URItoFileName(RealURI
);
1231 if (stat(Final
.c_str(),&Buf
) != 0)
1232 return "\nIndex-File: true";
1234 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1237 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1238 pkgAcquire::MethodConfig
*Cfg
)
1240 Item::Done(Message
,Size
,Hash
,Cfg
);
1242 // MetaIndexes are done in two passes: one to download the
1243 // metaindex with an appropriate method, and a second to verify it
1244 // with the gpgv method
1246 if (AuthPass
== true)
1250 // all cool, move Release file into place
1255 RetrievalDone(Message
);
1257 // Still more retrieving to do
1262 // There was no signature file, so we are finished. Download
1263 // the indexes and do only hashsum verification if possible
1264 MetaIndexParser
->Load(DestFile
);
1265 QueueIndexes(false);
1269 // There was a signature file, so pass it to gpgv for
1272 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1273 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1274 << SigFile
<< "," << DestFile
<< ")\n";
1276 Desc
.URI
= "gpgv:" + SigFile
;
1283 if (Complete
== true)
1285 string FinalFile
= _config
->FindDir("Dir::State::lists");
1286 FinalFile
+= URItoFileName(RealURI
);
1287 if (SigFile
== DestFile
)
1288 SigFile
= FinalFile
;
1289 Rename(DestFile
,FinalFile
);
1290 chmod(FinalFile
.c_str(),0644);
1291 DestFile
= FinalFile
;
1295 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1297 // We have just finished downloading a Release file (it is not
1300 string FileName
= LookupTag(Message
,"Filename");
1301 if (FileName
.empty() == true)
1304 ErrorText
= "Method gave a blank filename";
1308 if (FileName
!= DestFile
)
1311 Desc
.URI
= "copy:" + FileName
;
1316 // make sure to verify against the right file on I-M-S hit
1317 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1320 string FinalFile
= _config
->FindDir("Dir::State::lists");
1321 FinalFile
+= URItoFileName(RealURI
);
1322 if (SigFile
== DestFile
)
1324 SigFile
= FinalFile
;
1325 // constructor of pkgAcqMetaClearSig moved it out of the way,
1326 // now move it back in on IMS hit for the 'old' file
1327 string
const OldClearSig
= DestFile
+ ".reverify";
1328 if (RealFileExists(OldClearSig
) == true)
1329 Rename(OldClearSig
, FinalFile
);
1331 DestFile
= FinalFile
;
1336 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1338 // At this point, the gpgv method has succeeded, so there is a
1339 // valid signature from a key in the trusted keyring. We
1340 // perform additional verification of its contents, and use them
1341 // to verify the indexes we are about to download
1343 if (!MetaIndexParser
->Load(DestFile
))
1345 Status
= StatAuthError
;
1346 ErrorText
= MetaIndexParser
->ErrorText
;
1350 if (!VerifyVendor(Message
))
1355 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1356 std::cerr
<< "Signature verification succeeded: "
1357 << DestFile
<< std::endl
;
1359 // Download further indexes with verification
1362 // is it a clearsigned MetaIndex file?
1363 if (DestFile
== SigFile
)
1366 // Done, move signature file into position
1367 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1368 URItoFileName(RealURI
) + ".gpg";
1369 Rename(SigFile
,VerifiedSigFile
);
1370 chmod(VerifiedSigFile
.c_str(),0644);
1373 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1376 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1377 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1378 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1381 ErrorText
= MetaIndexParser
->ErrorText
;
1385 bool transInRelease
= false;
1387 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1388 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1389 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1390 if (k
->find("Translation-") != std::string::npos
)
1392 transInRelease
= true;
1397 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1398 Target
!= IndexTargets
->end();
1401 HashString ExpectedIndexHash
;
1402 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1403 bool compressedAvailable
= false;
1406 if ((*Target
)->IsOptional() == true)
1408 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1409 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1410 if (MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".").append(*t
)) == true)
1412 compressedAvailable
= true;
1416 else if (verify
== true)
1418 Status
= StatAuthError
;
1419 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1425 ExpectedIndexHash
= Record
->Hash
;
1426 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1428 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1429 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1430 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1432 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1434 Status
= StatAuthError
;
1435 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1440 if ((*Target
)->IsOptional() == true)
1442 if ((*Target
)->IsSubIndex() == true)
1443 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1444 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1445 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1447 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1448 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true)
1449 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1450 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1452 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1457 /* Queue Packages file (either diff or full packages files, depending
1458 on the users option) - we also check if the PDiff Index file is listed
1459 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1460 instead, but passing the required info to it is to much hassle */
1461 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1462 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1463 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1464 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1466 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1470 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1472 string::size_type pos
;
1474 // check for missing sigs (that where not fatal because otherwise we had
1477 string msg
= _("There is no public key available for the "
1478 "following key IDs:\n");
1479 pos
= Message
.find("NO_PUBKEY ");
1480 if (pos
!= std::string::npos
)
1482 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1483 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1484 missingkeys
+= (Fingerprint
);
1486 if(!missingkeys
.empty())
1487 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1489 string Transformed
= MetaIndexParser
->GetExpectedDist();
1491 if (Transformed
== "../project/experimental")
1493 Transformed
= "experimental";
1496 pos
= Transformed
.rfind('/');
1497 if (pos
!= string::npos
)
1499 Transformed
= Transformed
.substr(0, pos
);
1502 if (Transformed
== ".")
1507 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1508 MetaIndexParser
->GetValidUntil() > 0) {
1509 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1510 if (invalid_since
> 0)
1511 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1512 // the time since then the file is invalid - formated in the same way as in
1513 // the download progress display (e.g. 7d 3h 42min 1s)
1514 return _error
->Error(
1515 _("Release file for %s is expired (invalid since %s). "
1516 "Updates for this repository will not be applied."),
1517 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1520 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1522 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1523 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1524 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1527 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1529 // This might become fatal one day
1530 // Status = StatAuthError;
1531 // ErrorText = "Conflicting distribution; expected "
1532 // + MetaIndexParser->GetExpectedDist() + " but got "
1533 // + MetaIndexParser->GetDist();
1535 if (!Transformed
.empty())
1537 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1538 Desc
.Description
.c_str(),
1539 Transformed
.c_str(),
1540 MetaIndexParser
->GetDist().c_str());
1547 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1548 // ---------------------------------------------------------------------
1550 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1552 if (AuthPass
== true)
1554 // gpgv method failed, if we have a good signature
1555 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1556 if (DestFile
!= SigFile
)
1557 LastGoodSigFile
.append(".gpg");
1558 LastGoodSigFile
.append(".reverify");
1560 if(FileExists(LastGoodSigFile
))
1562 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1563 if (DestFile
!= SigFile
)
1564 VerifiedSigFile
.append(".gpg");
1565 Rename(LastGoodSigFile
, VerifiedSigFile
);
1566 Status
= StatTransientNetworkError
;
1567 _error
->Warning(_("An error occurred during the signature "
1568 "verification. The repository is not updated "
1569 "and the previous index files will be used. "
1570 "GPG error: %s: %s\n"),
1571 Desc
.Description
.c_str(),
1572 LookupTag(Message
,"Message").c_str());
1573 RunScripts("APT::Update::Auth-Failure");
1575 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1576 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1577 _error
->Error(_("GPG error: %s: %s"),
1578 Desc
.Description
.c_str(),
1579 LookupTag(Message
,"Message").c_str());
1582 _error
->Warning(_("GPG error: %s: %s"),
1583 Desc
.Description
.c_str(),
1584 LookupTag(Message
,"Message").c_str());
1586 // gpgv method failed
1587 ReportMirrorFailure("GPGFailure");
1590 /* Always move the meta index, even if gpgv failed. This ensures
1591 * that PackageFile objects are correctly filled in */
1592 if (FileExists(DestFile
)) {
1593 string FinalFile
= _config
->FindDir("Dir::State::lists");
1594 FinalFile
+= URItoFileName(RealURI
);
1595 /* InRelease files become Release files, otherwise
1596 * they would be considered as trusted later on */
1597 if (SigFile
== DestFile
) {
1598 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1600 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1602 SigFile
= FinalFile
;
1604 Rename(DestFile
,FinalFile
);
1605 chmod(FinalFile
.c_str(),0644);
1607 DestFile
= FinalFile
;
1610 // No Release file was present, or verification failed, so fall
1611 // back to queueing Packages files without verification
1612 QueueIndexes(false);
1615 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1616 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1617 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1618 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1619 const vector
<struct IndexTarget
*>* IndexTargets
,
1620 indexRecords
* MetaIndexParser
) :
1621 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1622 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1623 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1627 // keep the old InRelease around in case of transistent network errors
1628 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1629 if (RealFileExists(Final
) == true)
1631 string
const LastGoodSig
= DestFile
+ ".reverify";
1632 Rename(Final
,LastGoodSig
);
1636 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1638 // if the file was never queued undo file-changes done in the constructor
1639 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1641 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1642 string
const LastGoodSig
= DestFile
+ ".reverify";
1643 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1644 Rename(LastGoodSig
, Final
);
1648 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1649 // ---------------------------------------------------------------------
1650 // FIXME: this can go away once the InRelease file is used widely
1651 string
pkgAcqMetaClearSig::Custom600Headers()
1653 string Final
= _config
->FindDir("Dir::State::lists");
1654 Final
+= URItoFileName(RealURI
);
1657 if (stat(Final
.c_str(),&Buf
) != 0)
1659 Final
= DestFile
+ ".reverify";
1660 if (stat(Final
.c_str(),&Buf
) != 0)
1661 return "\nIndex-File: true\nFail-Ignore: true\n";
1664 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1667 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1669 if (AuthPass
== false)
1671 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1672 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1673 string FinalFile
= _config
->FindDir("Dir::State::lists");
1674 FinalFile
.append(URItoFileName(RealURI
));
1675 if (FileExists(FinalFile
))
1676 unlink(FinalFile
.c_str());
1678 new pkgAcqMetaSig(Owner
,
1679 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1680 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1681 IndexTargets
, MetaIndexParser
);
1682 if (Cnf
->LocalOnly
== true ||
1683 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1687 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1690 // AcqArchive::AcqArchive - Constructor /*{{{*/
1691 // ---------------------------------------------------------------------
1692 /* This just sets up the initial fetch environment and queues the first
1694 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1695 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1696 string
&StoreFilename
) :
1697 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1698 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1701 Retries
= _config
->FindI("Acquire::Retries",0);
1703 if (Version
.Arch() == 0)
1705 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1706 "This might mean you need to manually fix this package. "
1707 "(due to missing arch)"),
1708 Version
.ParentPkg().Name());
1712 /* We need to find a filename to determine the extension. We make the
1713 assumption here that all the available sources for this version share
1714 the same extension.. */
1715 // Skip not source sources, they do not have file fields.
1716 for (; Vf
.end() == false; ++Vf
)
1718 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1723 // Does not really matter here.. we are going to fail out below
1724 if (Vf
.end() != true)
1726 // If this fails to get a file name we will bomb out below.
1727 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1728 if (_error
->PendingError() == true)
1731 // Generate the final file name as: package_version_arch.foo
1732 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1733 QuoteString(Version
.VerStr(),"_:") + '_' +
1734 QuoteString(Version
.Arch(),"_:.") +
1735 "." + flExtension(Parse
.FileName());
1738 // check if we have one trusted source for the package. if so, switch
1739 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1740 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
1741 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
1742 bool seenUntrusted
= false;
1743 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1745 pkgIndexFile
*Index
;
1746 if (Sources
->FindIndex(i
.File(),Index
) == false)
1749 if (debugAuth
== true)
1750 std::cerr
<< "Checking index: " << Index
->Describe()
1751 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
1753 if (Index
->IsTrusted() == true)
1756 if (allowUnauth
== false)
1760 seenUntrusted
= true;
1763 // "allow-unauthenticated" restores apts old fetching behaviour
1764 // that means that e.g. unauthenticated file:// uris are higher
1765 // priority than authenticated http:// uris
1766 if (allowUnauth
== true && seenUntrusted
== true)
1770 if (QueueNext() == false && _error
->PendingError() == false)
1771 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
1772 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
1775 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1776 // ---------------------------------------------------------------------
1777 /* This queues the next available file version for download. It checks if
1778 the archive is already available in the cache and stashs the MD5 for
1780 bool pkgAcqArchive::QueueNext()
1782 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1783 for (; Vf
.end() == false; ++Vf
)
1785 // Ignore not source sources
1786 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1789 // Try to cross match against the source list
1790 pkgIndexFile
*Index
;
1791 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1794 // only try to get a trusted package from another source if that source
1796 if(Trusted
&& !Index
->IsTrusted())
1799 // Grab the text package record
1800 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1801 if (_error
->PendingError() == true)
1804 string PkgFile
= Parse
.FileName();
1805 if (ForceHash
.empty() == false)
1807 if(stringcasecmp(ForceHash
, "sha512") == 0)
1808 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
1809 else if(stringcasecmp(ForceHash
, "sha256") == 0)
1810 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1811 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1812 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1814 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1819 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
1820 ExpectedHash
= HashString("SHA512", Hash
);
1821 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1822 ExpectedHash
= HashString("SHA256", Hash
);
1823 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1824 ExpectedHash
= HashString("SHA1", Hash
);
1826 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1828 if (PkgFile
.empty() == true)
1829 return _error
->Error(_("The package index files are corrupted. No Filename: "
1830 "field for package %s."),
1831 Version
.ParentPkg().Name());
1833 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1834 Desc
.Description
= Index
->ArchiveInfo(Version
);
1836 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1838 // See if we already have the file. (Legacy filenames)
1839 FileSize
= Version
->Size
;
1840 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1842 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1844 // Make sure the size matches
1845 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1850 StoreFilename
= DestFile
= FinalFile
;
1854 /* Hmm, we have a file and its size does not match, this means it is
1855 an old style mismatched arch */
1856 unlink(FinalFile
.c_str());
1859 // Check it again using the new style output filenames
1860 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1861 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1863 // Make sure the size matches
1864 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1869 StoreFilename
= DestFile
= FinalFile
;
1873 /* Hmm, we have a file and its size does not match, this shouldnt
1875 unlink(FinalFile
.c_str());
1878 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1880 // Check the destination file
1881 if (stat(DestFile
.c_str(),&Buf
) == 0)
1883 // Hmm, the partial file is too big, erase it
1884 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
1885 unlink(DestFile
.c_str());
1887 PartialSize
= Buf
.st_size
;
1890 // Disables download of archives - useful if no real installation follows,
1891 // e.g. if we are just interested in proposed installation order
1892 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
1897 StoreFilename
= DestFile
= FinalFile
;
1903 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1904 Desc
.Description
= Index
->ArchiveInfo(Version
);
1906 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1915 // AcqArchive::Done - Finished fetching /*{{{*/
1916 // ---------------------------------------------------------------------
1918 void pkgAcqArchive::Done(string Message
,unsigned long long Size
,string CalcHash
,
1919 pkgAcquire::MethodConfig
*Cfg
)
1921 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1924 if (Size
!= Version
->Size
)
1926 RenameOnError(SizeMismatch
);
1931 if(ExpectedHash
.toStr() != CalcHash
)
1933 RenameOnError(HashSumMismatch
);
1937 // Grab the output filename
1938 string FileName
= LookupTag(Message
,"Filename");
1939 if (FileName
.empty() == true)
1942 ErrorText
= "Method gave a blank filename";
1948 // Reference filename
1949 if (FileName
!= DestFile
)
1951 StoreFilename
= DestFile
= FileName
;
1956 // Done, move it into position
1957 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1958 FinalFile
+= flNotDir(StoreFilename
);
1959 Rename(DestFile
,FinalFile
);
1961 StoreFilename
= DestFile
= FinalFile
;
1965 // AcqArchive::Failed - Failure handler /*{{{*/
1966 // ---------------------------------------------------------------------
1967 /* Here we try other sources */
1968 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1970 ErrorText
= LookupTag(Message
,"Message");
1972 /* We don't really want to retry on failed media swaps, this prevents
1973 that. An interesting observation is that permanent failures are not
1975 if (Cnf
->Removable
== true &&
1976 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1978 // Vf = Version.FileList();
1979 while (Vf
.end() == false) ++Vf
;
1980 StoreFilename
= string();
1981 Item::Failed(Message
,Cnf
);
1985 if (QueueNext() == false)
1987 // This is the retry counter
1989 Cnf
->LocalOnly
== false &&
1990 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1993 Vf
= Version
.FileList();
1994 if (QueueNext() == true)
1998 StoreFilename
= string();
1999 Item::Failed(Message
,Cnf
);
2003 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2004 // ---------------------------------------------------------------------
2005 bool pkgAcqArchive::IsTrusted()
2010 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2011 // ---------------------------------------------------------------------
2013 void pkgAcqArchive::Finished()
2015 if (Status
== pkgAcquire::Item::StatDone
&&
2018 StoreFilename
= string();
2021 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2022 // ---------------------------------------------------------------------
2023 /* The file is added to the queue */
2024 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
2025 unsigned long long Size
,string Dsc
,string ShortDesc
,
2026 const string
&DestDir
, const string
&DestFilename
,
2028 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
2030 Retries
= _config
->FindI("Acquire::Retries",0);
2032 if(!DestFilename
.empty())
2033 DestFile
= DestFilename
;
2034 else if(!DestDir
.empty())
2035 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2037 DestFile
= flNotDir(URI
);
2041 Desc
.Description
= Dsc
;
2044 // Set the short description to the archive component
2045 Desc
.ShortDesc
= ShortDesc
;
2047 // Get the transfer sizes
2050 if (stat(DestFile
.c_str(),&Buf
) == 0)
2052 // Hmm, the partial file is too big, erase it
2053 if ((unsigned long long)Buf
.st_size
> Size
)
2054 unlink(DestFile
.c_str());
2056 PartialSize
= Buf
.st_size
;
2062 // AcqFile::Done - Item downloaded OK /*{{{*/
2063 // ---------------------------------------------------------------------
2065 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
2066 pkgAcquire::MethodConfig
*Cnf
)
2068 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2071 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2073 RenameOnError(HashSumMismatch
);
2077 string FileName
= LookupTag(Message
,"Filename");
2078 if (FileName
.empty() == true)
2081 ErrorText
= "Method gave a blank filename";
2087 // The files timestamp matches
2088 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2091 // We have to copy it into place
2092 if (FileName
!= DestFile
)
2095 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2096 Cnf
->Removable
== true)
2098 Desc
.URI
= "copy:" + FileName
;
2103 // Erase the file if it is a symlink so we can overwrite it
2105 if (lstat(DestFile
.c_str(),&St
) == 0)
2107 if (S_ISLNK(St
.st_mode
) != 0)
2108 unlink(DestFile
.c_str());
2112 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2114 ErrorText
= "Link to " + DestFile
+ " failure ";
2121 // AcqFile::Failed - Failure handler /*{{{*/
2122 // ---------------------------------------------------------------------
2123 /* Here we try other sources */
2124 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2126 ErrorText
= LookupTag(Message
,"Message");
2128 // This is the retry counter
2130 Cnf
->LocalOnly
== false &&
2131 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2138 Item::Failed(Message
,Cnf
);
2141 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2142 // ---------------------------------------------------------------------
2143 /* The only header we use is the last-modified header. */
2144 string
pkgAcqFile::Custom600Headers()
2147 return "\nIndex-File: true";