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 so we are done here
433 std::clog
<< "Package file is up-to-date" << std::endl
;
434 // list cleanup needs to know that this file as well as the already
435 // present index is ours, so we create an empty diff to save it for us
436 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
437 ExpectedHash
, ServerSha1
, available_patches
);
443 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
445 // check the historie and see what patches we need
446 string
const history
= Tags
.FindS("SHA1-History");
447 std::stringstream
hist(history
);
448 while(hist
>> d
.sha1
>> size
>> d
.file
)
450 // read until the first match is found
451 // from that point on, we probably need all diffs
452 if(d
.sha1
== local_sha1
)
454 else if (found
== false)
458 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
459 available_patches
.push_back(d
);
462 if (available_patches
.empty() == false)
464 // patching with too many files is rather slow compared to a fast download
465 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 20);
466 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
469 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
470 << ") so fallback to complete download" << std::endl
;
474 // see if the patches are too big
475 found
= false; // it was true and it will be true again at the end
476 d
= *available_patches
.begin();
477 string
const firstPatch
= d
.file
;
478 unsigned long patchesSize
= 0;
479 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
480 while(patches
>> d
.sha1
>> size
>> d
.file
)
482 if (firstPatch
== d
.file
)
484 else if (found
== false)
487 patchesSize
+= atol(size
.c_str());
489 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
490 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
493 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
494 << ") so fallback to complete download" << std::endl
;
500 // we have something, queue the next diff
504 string::size_type
const last_space
= Description
.rfind(" ");
505 if(last_space
!= string::npos
)
506 Description
.erase(last_space
, Description
.size()-last_space
);
507 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
508 ExpectedHash
, ServerSha1
, available_patches
);
516 // Nothing found, report and return false
517 // Failing here is ok, if we return false later, the full
518 // IndexFile is queued
520 std::clog
<< "Can't find a patch in the index file" << std::endl
;
524 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
527 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
528 << "Falling back to normal index file aquire" << std::endl
;
530 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
538 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
539 pkgAcquire::MethodConfig
*Cnf
)
542 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
544 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
547 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
549 // sucess in downloading the index
551 FinalFile
+= string(".IndexDiff");
553 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
555 Rename(DestFile
,FinalFile
);
556 chmod(FinalFile
.c_str(),0644);
557 DestFile
= FinalFile
;
559 if(!ParseDiffIndex(DestFile
))
560 return Failed("", NULL
);
568 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
569 // ---------------------------------------------------------------------
570 /* The package diff is added to the queue. one object is constructed
571 * for each diff and the index
573 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
574 string URI
,string URIDesc
,string ShortDesc
,
575 HashString ExpectedHash
,
577 vector
<DiffInfo
> diffs
)
578 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
579 available_patches(diffs
), ServerSha1(ServerSha1
)
582 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
583 DestFile
+= URItoFileName(URI
);
585 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
587 Description
= URIDesc
;
589 Desc
.ShortDesc
= ShortDesc
;
591 if(available_patches
.empty() == true)
593 // we are done (yeah!)
599 State
= StateFetchDiff
;
604 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
607 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
608 << "Falling back to normal index file aquire" << std::endl
;
609 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
614 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
615 void pkgAcqIndexDiffs::Finish(bool allDone
)
617 // we restore the original name, this is required, otherwise
618 // the file will be cleaned
621 DestFile
= _config
->FindDir("Dir::State::lists");
622 DestFile
+= URItoFileName(RealURI
);
624 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
626 RenameOnError(HashSumMismatch
);
631 // this is for the "real" finish
636 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
641 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
648 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
651 // calc sha1 of the just patched file
652 string FinalFile
= _config
->FindDir("Dir::State::lists");
653 FinalFile
+= URItoFileName(RealURI
);
655 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
658 string local_sha1
= string(SHA1
.Result());
660 std::clog
<< "QueueNextDiff: "
661 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
663 // final file reached before all patches are applied
664 if(local_sha1
== ServerSha1
)
670 // remove all patches until the next matching patch is found
671 // this requires the Index file to be ordered
672 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
673 available_patches
.empty() == false &&
674 I
!= available_patches
.end() &&
675 I
->sha1
!= local_sha1
;
678 available_patches
.erase(I
);
681 // error checking and falling back if no patch was found
682 if(available_patches
.empty() == true)
688 // queue the right diff
689 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
690 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
691 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
692 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
695 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
702 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
703 pkgAcquire::MethodConfig
*Cnf
)
706 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
708 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
711 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
713 // sucess in downloading a diff, enter ApplyDiff state
714 if(State
== StateFetchDiff
)
717 // rred excepts the patch as $FinalFile.ed
718 Rename(DestFile
,FinalFile
+".ed");
721 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
723 State
= StateApplyDiff
;
725 Desc
.URI
= "rred:" + FinalFile
;
732 // success in download/apply a diff, queue next (if needed)
733 if(State
== StateApplyDiff
)
735 // remove the just applied patch
736 available_patches
.erase(available_patches
.begin());
741 std::clog
<< "Moving patched file in place: " << std::endl
742 << DestFile
<< " -> " << FinalFile
<< std::endl
;
744 Rename(DestFile
,FinalFile
);
745 chmod(FinalFile
.c_str(),0644);
747 // see if there is more to download
748 if(available_patches
.empty() == false) {
749 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
750 ExpectedHash
, ServerSha1
, available_patches
);
757 // AcqIndex::AcqIndex - Constructor /*{{{*/
758 // ---------------------------------------------------------------------
759 /* The package file is added to the queue and a second class is
760 instantiated to fetch the revision file */
761 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
762 string URI
,string URIDesc
,string ShortDesc
,
763 HashString ExpectedHash
, string comprExt
)
764 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
766 if(comprExt
.empty() == true)
768 // autoselect the compression method
769 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
770 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
771 comprExt
.append(*t
).append(" ");
772 if (comprExt
.empty() == false)
773 comprExt
.erase(comprExt
.end()-1);
775 CompressionExtension
= comprExt
;
777 Init(URI
, URIDesc
, ShortDesc
);
779 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
780 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
781 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
783 // autoselect the compression method
784 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
785 CompressionExtension
= "";
786 if (ExpectedHash
.empty() == false)
788 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
789 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
790 CompressionExtension
.append(*t
).append(" ");
794 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
795 CompressionExtension
.append(*t
).append(" ");
797 if (CompressionExtension
.empty() == false)
798 CompressionExtension
.erase(CompressionExtension
.end()-1);
800 // only verify non-optional targets, see acquire-item.h for a FIXME
801 // to make this more flexible
802 if (Target
->IsOptional())
807 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
810 // AcqIndex::Init - defered Constructor /*{{{*/
811 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
812 Decompression
= false;
815 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
816 DestFile
+= URItoFileName(URI
);
818 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
819 if (comprExt
== "uncompressed")
822 Desc
.URI
= URI
+ '.' + comprExt
;
824 Desc
.Description
= URIDesc
;
826 Desc
.ShortDesc
= ShortDesc
;
831 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
832 // ---------------------------------------------------------------------
833 /* The only header we use is the last-modified header. */
834 string
pkgAcqIndex::Custom600Headers()
836 string Final
= _config
->FindDir("Dir::State::lists");
837 Final
+= URItoFileName(RealURI
);
838 if (_config
->FindB("Acquire::GzipIndexes",false))
841 string msg
= "\nIndex-File: true";
842 // FIXME: this really should use "IndexTarget::IsOptional()" but that
843 // seems to be difficult without breaking ABI
844 if (ShortDesc().find("Translation") != 0)
845 msg
+= "\nFail-Ignore: true";
847 if (stat(Final
.c_str(),&Buf
) == 0)
848 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
853 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
855 size_t const nextExt
= CompressionExtension
.find(' ');
856 if (nextExt
!= std::string::npos
)
858 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
859 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
863 // on decompression failure, remove bad versions in partial/
864 if (Decompression
&& Erase
) {
865 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
866 s
.append(URItoFileName(RealURI
));
870 Item::Failed(Message
,Cnf
);
873 // AcqIndex::Done - Finished a fetch /*{{{*/
874 // ---------------------------------------------------------------------
875 /* This goes through a number of states.. On the initial fetch the
876 method could possibly return an alternate filename which points
877 to the uncompressed version of the file. If this is so the file
878 is copied into the partial directory. In all other cases the file
879 is decompressed with a gzip uri. */
880 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
881 pkgAcquire::MethodConfig
*Cfg
)
883 Item::Done(Message
,Size
,Hash
,Cfg
);
885 if (Decompression
== true)
887 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
889 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
890 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
893 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
895 RenameOnError(HashSumMismatch
);
899 /* Verify the index file for correctness (all indexes must
900 * have a Package field) (LP: #346386) (Closes: #627642) */
903 FileFd
fd(DestFile
, FileFd::ReadOnly
);
904 // Only test for correctness if the file is not empty (empty is ok)
905 if (fd
.FileSize() > 0)
910 // all our current indexes have a field 'Package' in each section
911 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
913 RenameOnError(InvalidFormat
);
919 // Done, move it into position
920 string FinalFile
= _config
->FindDir("Dir::State::lists");
921 FinalFile
+= URItoFileName(RealURI
);
922 Rename(DestFile
,FinalFile
);
923 chmod(FinalFile
.c_str(),0644);
925 /* We restore the original name to DestFile so that the clean operation
927 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
928 DestFile
+= URItoFileName(RealURI
);
930 // Remove the compressed version.
932 unlink(DestFile
.c_str());
939 // Handle the unzipd case
940 string FileName
= LookupTag(Message
,"Alt-Filename");
941 if (FileName
.empty() == false)
943 // The files timestamp matches
944 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
946 Decompression
= true;
948 DestFile
+= ".decomp";
949 Desc
.URI
= "copy:" + FileName
;
955 FileName
= LookupTag(Message
,"Filename");
956 if (FileName
.empty() == true)
959 ErrorText
= "Method gave a blank filename";
962 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
964 // The files timestamp matches
965 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
966 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
967 // Update DestFile for .gz suffix so that the clean operation keeps it
972 if (FileName
== DestFile
)
979 // If we enable compressed indexes and already have gzip, keep it
980 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
981 string FinalFile
= _config
->FindDir("Dir::State::lists");
982 FinalFile
+= URItoFileName(RealURI
) + ".gz";
983 Rename(DestFile
,FinalFile
);
984 chmod(FinalFile
.c_str(),0644);
986 // Update DestFile for .gz suffix so that the clean operation keeps it
987 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
988 DestFile
+= URItoFileName(RealURI
) + ".gz";
992 // get the binary name for your used compression type
993 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
994 if(decompProg
.empty() == false);
995 else if(compExt
== "uncompressed")
998 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1002 Decompression
= true;
1003 DestFile
+= ".decomp";
1004 Desc
.URI
= decompProg
+ ":" + FileName
;
1007 // FIXME: this points to a c++ string that goes out of scope
1008 Mode
= decompProg
.c_str();
1011 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1012 // ---------------------------------------------------------------------
1013 /* The Translation file is added to the queue */
1014 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1015 string URI
,string URIDesc
,string ShortDesc
)
1016 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1019 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1020 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1021 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1025 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1026 // ---------------------------------------------------------------------
1027 string
pkgAcqIndexTrans::Custom600Headers()
1029 string Final
= _config
->FindDir("Dir::State::lists");
1030 Final
+= URItoFileName(RealURI
);
1033 if (stat(Final
.c_str(),&Buf
) != 0)
1034 return "\nFail-Ignore: true\nIndex-File: true";
1035 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1038 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1039 // ---------------------------------------------------------------------
1041 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1043 size_t const nextExt
= CompressionExtension
.find(' ');
1044 if (nextExt
!= std::string::npos
)
1046 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1047 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1052 if (Cnf
->LocalOnly
== true ||
1053 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1062 Item::Failed(Message
,Cnf
);
1065 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1066 string URI
,string URIDesc
,string ShortDesc
,
1067 string MetaIndexURI
, string MetaIndexURIDesc
,
1068 string MetaIndexShortDesc
,
1069 const vector
<IndexTarget
*>* IndexTargets
,
1070 indexRecords
* MetaIndexParser
) :
1071 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1072 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1073 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1075 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1076 DestFile
+= URItoFileName(URI
);
1078 // remove any partial downloaded sig-file in partial/.
1079 // it may confuse proxies and is too small to warrant a
1080 // partial download anyway
1081 unlink(DestFile
.c_str());
1084 Desc
.Description
= URIDesc
;
1086 Desc
.ShortDesc
= ShortDesc
;
1089 string Final
= _config
->FindDir("Dir::State::lists");
1090 Final
+= URItoFileName(RealURI
);
1091 if (RealFileExists(Final
) == true)
1093 // File was already in place. It needs to be re-downloaded/verified
1094 // because Release might have changed, we do give it a differnt
1095 // name than DestFile because otherwise the http method will
1096 // send If-Range requests and there are too many broken servers
1097 // out there that do not understand them
1098 LastGoodSig
= DestFile
+".reverify";
1099 Rename(Final
,LastGoodSig
);
1105 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1107 // if the file was never queued undo file-changes done in the constructor
1108 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false &&
1109 LastGoodSig
.empty() == false)
1111 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1112 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1113 Rename(LastGoodSig
, Final
);
1118 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1119 // ---------------------------------------------------------------------
1120 /* The only header we use is the last-modified header. */
1121 string
pkgAcqMetaSig::Custom600Headers()
1124 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1125 return "\nIndex-File: true";
1127 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1130 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1131 pkgAcquire::MethodConfig
*Cfg
)
1133 Item::Done(Message
,Size
,MD5
,Cfg
);
1135 string FileName
= LookupTag(Message
,"Filename");
1136 if (FileName
.empty() == true)
1139 ErrorText
= "Method gave a blank filename";
1143 if (FileName
!= DestFile
)
1145 // We have to copy it into place
1147 Desc
.URI
= "copy:" + FileName
;
1154 // put the last known good file back on i-m-s hit (it will
1155 // be re-verified again)
1156 // Else do nothing, we have the new file in DestFile then
1157 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1158 Rename(LastGoodSig
, DestFile
);
1160 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1161 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1162 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1167 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1169 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1171 // if we get a network error we fail gracefully
1172 if(Status
== StatTransientNetworkError
)
1174 Item::Failed(Message
,Cnf
);
1175 // move the sigfile back on transient network failures
1176 if(FileExists(LastGoodSig
))
1177 Rename(LastGoodSig
,Final
);
1179 // set the status back to , Item::Failed likes to reset it
1180 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1184 // Delete any existing sigfile when the acquire failed
1185 unlink(Final
.c_str());
1187 // queue a pkgAcqMetaIndex with no sigfile
1188 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1189 "", IndexTargets
, MetaIndexParser
);
1191 if (Cnf
->LocalOnly
== true ||
1192 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1201 Item::Failed(Message
,Cnf
);
1204 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1205 string URI
,string URIDesc
,string ShortDesc
,
1207 const vector
<struct IndexTarget
*>* IndexTargets
,
1208 indexRecords
* MetaIndexParser
) :
1209 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1210 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1212 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1213 DestFile
+= URItoFileName(URI
);
1216 Desc
.Description
= URIDesc
;
1218 Desc
.ShortDesc
= ShortDesc
;
1224 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1225 // ---------------------------------------------------------------------
1226 /* The only header we use is the last-modified header. */
1227 string
pkgAcqMetaIndex::Custom600Headers()
1229 string Final
= _config
->FindDir("Dir::State::lists");
1230 Final
+= URItoFileName(RealURI
);
1233 if (stat(Final
.c_str(),&Buf
) != 0)
1234 return "\nIndex-File: true";
1236 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1239 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1240 pkgAcquire::MethodConfig
*Cfg
)
1242 Item::Done(Message
,Size
,Hash
,Cfg
);
1244 // MetaIndexes are done in two passes: one to download the
1245 // metaindex with an appropriate method, and a second to verify it
1246 // with the gpgv method
1248 if (AuthPass
== true)
1252 // all cool, move Release file into place
1257 RetrievalDone(Message
);
1259 // Still more retrieving to do
1264 // There was no signature file, so we are finished. Download
1265 // the indexes and do only hashsum verification if possible
1266 MetaIndexParser
->Load(DestFile
);
1267 QueueIndexes(false);
1271 // There was a signature file, so pass it to gpgv for
1274 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1275 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1276 << SigFile
<< "," << DestFile
<< ")\n";
1278 Desc
.URI
= "gpgv:" + SigFile
;
1285 if (Complete
== true)
1287 string FinalFile
= _config
->FindDir("Dir::State::lists");
1288 FinalFile
+= URItoFileName(RealURI
);
1289 if (SigFile
== DestFile
)
1290 SigFile
= FinalFile
;
1291 Rename(DestFile
,FinalFile
);
1292 chmod(FinalFile
.c_str(),0644);
1293 DestFile
= FinalFile
;
1297 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1299 // We have just finished downloading a Release file (it is not
1302 string FileName
= LookupTag(Message
,"Filename");
1303 if (FileName
.empty() == true)
1306 ErrorText
= "Method gave a blank filename";
1310 if (FileName
!= DestFile
)
1313 Desc
.URI
= "copy:" + FileName
;
1318 // make sure to verify against the right file on I-M-S hit
1319 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1322 string FinalFile
= _config
->FindDir("Dir::State::lists");
1323 FinalFile
+= URItoFileName(RealURI
);
1324 if (SigFile
== DestFile
)
1326 SigFile
= FinalFile
;
1327 // constructor of pkgAcqMetaClearSig moved it out of the way,
1328 // now move it back in on IMS hit for the 'old' file
1329 string
const OldClearSig
= DestFile
+ ".reverify";
1330 if (RealFileExists(OldClearSig
) == true)
1331 Rename(OldClearSig
, FinalFile
);
1333 DestFile
= FinalFile
;
1338 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1340 // At this point, the gpgv method has succeeded, so there is a
1341 // valid signature from a key in the trusted keyring. We
1342 // perform additional verification of its contents, and use them
1343 // to verify the indexes we are about to download
1345 if (!MetaIndexParser
->Load(DestFile
))
1347 Status
= StatAuthError
;
1348 ErrorText
= MetaIndexParser
->ErrorText
;
1352 if (!VerifyVendor(Message
))
1357 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1358 std::cerr
<< "Signature verification succeeded: "
1359 << DestFile
<< std::endl
;
1361 // Download further indexes with verification
1364 // is it a clearsigned MetaIndex file?
1365 if (DestFile
== SigFile
)
1368 // Done, move signature file into position
1369 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1370 URItoFileName(RealURI
) + ".gpg";
1371 Rename(SigFile
,VerifiedSigFile
);
1372 chmod(VerifiedSigFile
.c_str(),0644);
1375 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1378 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1379 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1380 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1383 ErrorText
= MetaIndexParser
->ErrorText
;
1387 bool transInRelease
= false;
1389 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1390 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1391 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1392 if (k
->find("Translation-") != std::string::npos
)
1394 transInRelease
= true;
1399 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1400 Target
!= IndexTargets
->end();
1403 HashString ExpectedIndexHash
;
1404 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1405 bool compressedAvailable
= false;
1408 if ((*Target
)->IsOptional() == true)
1410 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1411 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1412 if (MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".").append(*t
)) == true)
1414 compressedAvailable
= true;
1418 else if (verify
== true)
1420 Status
= StatAuthError
;
1421 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1427 ExpectedIndexHash
= Record
->Hash
;
1428 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1430 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1431 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1432 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1434 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1436 Status
= StatAuthError
;
1437 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1442 if ((*Target
)->IsOptional() == true)
1444 if ((*Target
)->IsSubIndex() == true)
1445 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1446 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1447 else if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1449 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1450 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true)
1451 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1452 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1454 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1459 /* Queue Packages file (either diff or full packages files, depending
1460 on the users option) - we also check if the PDiff Index file is listed
1461 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1462 instead, but passing the required info to it is to much hassle */
1463 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1464 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1465 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1466 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1468 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1472 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1474 string::size_type pos
;
1476 // check for missing sigs (that where not fatal because otherwise we had
1479 string msg
= _("There is no public key available for the "
1480 "following key IDs:\n");
1481 pos
= Message
.find("NO_PUBKEY ");
1482 if (pos
!= std::string::npos
)
1484 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1485 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1486 missingkeys
+= (Fingerprint
);
1488 if(!missingkeys
.empty())
1489 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1491 string Transformed
= MetaIndexParser
->GetExpectedDist();
1493 if (Transformed
== "../project/experimental")
1495 Transformed
= "experimental";
1498 pos
= Transformed
.rfind('/');
1499 if (pos
!= string::npos
)
1501 Transformed
= Transformed
.substr(0, pos
);
1504 if (Transformed
== ".")
1509 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1510 MetaIndexParser
->GetValidUntil() > 0) {
1511 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1512 if (invalid_since
> 0)
1513 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1514 // the time since then the file is invalid - formated in the same way as in
1515 // the download progress display (e.g. 7d 3h 42min 1s)
1516 return _error
->Error(
1517 _("Release file for %s is expired (invalid since %s). "
1518 "Updates for this repository will not be applied."),
1519 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1522 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1524 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1525 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1526 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1529 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1531 // This might become fatal one day
1532 // Status = StatAuthError;
1533 // ErrorText = "Conflicting distribution; expected "
1534 // + MetaIndexParser->GetExpectedDist() + " but got "
1535 // + MetaIndexParser->GetDist();
1537 if (!Transformed
.empty())
1539 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1540 Desc
.Description
.c_str(),
1541 Transformed
.c_str(),
1542 MetaIndexParser
->GetDist().c_str());
1549 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1550 // ---------------------------------------------------------------------
1552 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1554 if (AuthPass
== true)
1556 // gpgv method failed, if we have a good signature
1557 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1558 if (DestFile
!= SigFile
)
1559 LastGoodSigFile
.append(".gpg");
1560 LastGoodSigFile
.append(".reverify");
1562 if(FileExists(LastGoodSigFile
))
1564 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1565 if (DestFile
!= SigFile
)
1566 VerifiedSigFile
.append(".gpg");
1567 Rename(LastGoodSigFile
, VerifiedSigFile
);
1568 Status
= StatTransientNetworkError
;
1569 _error
->Warning(_("An error occurred during the signature "
1570 "verification. The repository is not updated "
1571 "and the previous index files will be used. "
1572 "GPG error: %s: %s\n"),
1573 Desc
.Description
.c_str(),
1574 LookupTag(Message
,"Message").c_str());
1575 RunScripts("APT::Update::Auth-Failure");
1577 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1578 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1579 _error
->Error(_("GPG error: %s: %s"),
1580 Desc
.Description
.c_str(),
1581 LookupTag(Message
,"Message").c_str());
1584 _error
->Warning(_("GPG error: %s: %s"),
1585 Desc
.Description
.c_str(),
1586 LookupTag(Message
,"Message").c_str());
1588 // gpgv method failed
1589 ReportMirrorFailure("GPGFailure");
1592 /* Always move the meta index, even if gpgv failed. This ensures
1593 * that PackageFile objects are correctly filled in */
1594 if (FileExists(DestFile
)) {
1595 string FinalFile
= _config
->FindDir("Dir::State::lists");
1596 FinalFile
+= URItoFileName(RealURI
);
1597 /* InRelease files become Release files, otherwise
1598 * they would be considered as trusted later on */
1599 if (SigFile
== DestFile
) {
1600 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1602 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1604 SigFile
= FinalFile
;
1606 Rename(DestFile
,FinalFile
);
1607 chmod(FinalFile
.c_str(),0644);
1609 DestFile
= FinalFile
;
1612 // No Release file was present, or verification failed, so fall
1613 // back to queueing Packages files without verification
1614 QueueIndexes(false);
1617 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1618 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1619 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1620 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1621 const vector
<struct IndexTarget
*>* IndexTargets
,
1622 indexRecords
* MetaIndexParser
) :
1623 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1624 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1625 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1629 // keep the old InRelease around in case of transistent network errors
1630 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1631 if (RealFileExists(Final
) == true)
1633 string
const LastGoodSig
= DestFile
+ ".reverify";
1634 Rename(Final
,LastGoodSig
);
1638 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1640 // if the file was never queued undo file-changes done in the constructor
1641 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1643 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1644 string
const LastGoodSig
= DestFile
+ ".reverify";
1645 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1646 Rename(LastGoodSig
, Final
);
1650 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1651 // ---------------------------------------------------------------------
1652 // FIXME: this can go away once the InRelease file is used widely
1653 string
pkgAcqMetaClearSig::Custom600Headers()
1655 string Final
= _config
->FindDir("Dir::State::lists");
1656 Final
+= URItoFileName(RealURI
);
1659 if (stat(Final
.c_str(),&Buf
) != 0)
1661 Final
= DestFile
+ ".reverify";
1662 if (stat(Final
.c_str(),&Buf
) != 0)
1663 return "\nIndex-File: true\nFail-Ignore: true\n";
1666 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1669 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1671 if (AuthPass
== false)
1673 // Remove the 'old' InRelease file if we try Release.gpg now as otherwise
1674 // the file will stay around and gives a false-auth impression (CVE-2012-0214)
1675 string FinalFile
= _config
->FindDir("Dir::State::lists");
1676 FinalFile
.append(URItoFileName(RealURI
));
1677 if (FileExists(FinalFile
))
1678 unlink(FinalFile
.c_str());
1680 new pkgAcqMetaSig(Owner
,
1681 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1682 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1683 IndexTargets
, MetaIndexParser
);
1684 if (Cnf
->LocalOnly
== true ||
1685 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1689 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1692 // AcqArchive::AcqArchive - Constructor /*{{{*/
1693 // ---------------------------------------------------------------------
1694 /* This just sets up the initial fetch environment and queues the first
1696 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1697 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1698 string
&StoreFilename
) :
1699 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1700 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1703 Retries
= _config
->FindI("Acquire::Retries",0);
1705 if (Version
.Arch() == 0)
1707 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1708 "This might mean you need to manually fix this package. "
1709 "(due to missing arch)"),
1710 Version
.ParentPkg().Name());
1714 /* We need to find a filename to determine the extension. We make the
1715 assumption here that all the available sources for this version share
1716 the same extension.. */
1717 // Skip not source sources, they do not have file fields.
1718 for (; Vf
.end() == false; ++Vf
)
1720 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1725 // Does not really matter here.. we are going to fail out below
1726 if (Vf
.end() != true)
1728 // If this fails to get a file name we will bomb out below.
1729 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1730 if (_error
->PendingError() == true)
1733 // Generate the final file name as: package_version_arch.foo
1734 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1735 QuoteString(Version
.VerStr(),"_:") + '_' +
1736 QuoteString(Version
.Arch(),"_:.") +
1737 "." + flExtension(Parse
.FileName());
1740 // check if we have one trusted source for the package. if so, switch
1741 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
1742 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
1743 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
1744 bool seenUntrusted
= false;
1745 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1747 pkgIndexFile
*Index
;
1748 if (Sources
->FindIndex(i
.File(),Index
) == false)
1751 if (debugAuth
== true)
1752 std::cerr
<< "Checking index: " << Index
->Describe()
1753 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
1755 if (Index
->IsTrusted() == true)
1758 if (allowUnauth
== false)
1762 seenUntrusted
= true;
1765 // "allow-unauthenticated" restores apts old fetching behaviour
1766 // that means that e.g. unauthenticated file:// uris are higher
1767 // priority than authenticated http:// uris
1768 if (allowUnauth
== true && seenUntrusted
== true)
1772 if (QueueNext() == false && _error
->PendingError() == false)
1773 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
1774 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
1777 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1778 // ---------------------------------------------------------------------
1779 /* This queues the next available file version for download. It checks if
1780 the archive is already available in the cache and stashs the MD5 for
1782 bool pkgAcqArchive::QueueNext()
1784 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1785 for (; Vf
.end() == false; ++Vf
)
1787 // Ignore not source sources
1788 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1791 // Try to cross match against the source list
1792 pkgIndexFile
*Index
;
1793 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1796 // only try to get a trusted package from another source if that source
1798 if(Trusted
&& !Index
->IsTrusted())
1801 // Grab the text package record
1802 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1803 if (_error
->PendingError() == true)
1806 string PkgFile
= Parse
.FileName();
1807 if (ForceHash
.empty() == false)
1809 if(stringcasecmp(ForceHash
, "sha512") == 0)
1810 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
1811 else if(stringcasecmp(ForceHash
, "sha256") == 0)
1812 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1813 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1814 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1816 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1821 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
1822 ExpectedHash
= HashString("SHA512", Hash
);
1823 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1824 ExpectedHash
= HashString("SHA256", Hash
);
1825 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1826 ExpectedHash
= HashString("SHA1", Hash
);
1828 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1830 if (PkgFile
.empty() == true)
1831 return _error
->Error(_("The package index files are corrupted. No Filename: "
1832 "field for package %s."),
1833 Version
.ParentPkg().Name());
1835 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1836 Desc
.Description
= Index
->ArchiveInfo(Version
);
1838 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1840 // See if we already have the file. (Legacy filenames)
1841 FileSize
= Version
->Size
;
1842 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1844 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1846 // Make sure the size matches
1847 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1852 StoreFilename
= DestFile
= FinalFile
;
1856 /* Hmm, we have a file and its size does not match, this means it is
1857 an old style mismatched arch */
1858 unlink(FinalFile
.c_str());
1861 // Check it again using the new style output filenames
1862 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1863 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1865 // Make sure the size matches
1866 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1871 StoreFilename
= DestFile
= FinalFile
;
1875 /* Hmm, we have a file and its size does not match, this shouldnt
1877 unlink(FinalFile
.c_str());
1880 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1882 // Check the destination file
1883 if (stat(DestFile
.c_str(),&Buf
) == 0)
1885 // Hmm, the partial file is too big, erase it
1886 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
1887 unlink(DestFile
.c_str());
1889 PartialSize
= Buf
.st_size
;
1892 // Disables download of archives - useful if no real installation follows,
1893 // e.g. if we are just interested in proposed installation order
1894 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
1899 StoreFilename
= DestFile
= FinalFile
;
1905 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1906 Desc
.Description
= Index
->ArchiveInfo(Version
);
1908 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1917 // AcqArchive::Done - Finished fetching /*{{{*/
1918 // ---------------------------------------------------------------------
1920 void pkgAcqArchive::Done(string Message
,unsigned long long Size
,string CalcHash
,
1921 pkgAcquire::MethodConfig
*Cfg
)
1923 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1926 if (Size
!= Version
->Size
)
1928 RenameOnError(SizeMismatch
);
1933 if(ExpectedHash
.toStr() != CalcHash
)
1935 RenameOnError(HashSumMismatch
);
1939 // Grab the output filename
1940 string FileName
= LookupTag(Message
,"Filename");
1941 if (FileName
.empty() == true)
1944 ErrorText
= "Method gave a blank filename";
1950 // Reference filename
1951 if (FileName
!= DestFile
)
1953 StoreFilename
= DestFile
= FileName
;
1958 // Done, move it into position
1959 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1960 FinalFile
+= flNotDir(StoreFilename
);
1961 Rename(DestFile
,FinalFile
);
1963 StoreFilename
= DestFile
= FinalFile
;
1967 // AcqArchive::Failed - Failure handler /*{{{*/
1968 // ---------------------------------------------------------------------
1969 /* Here we try other sources */
1970 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1972 ErrorText
= LookupTag(Message
,"Message");
1974 /* We don't really want to retry on failed media swaps, this prevents
1975 that. An interesting observation is that permanent failures are not
1977 if (Cnf
->Removable
== true &&
1978 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1980 // Vf = Version.FileList();
1981 while (Vf
.end() == false) ++Vf
;
1982 StoreFilename
= string();
1983 Item::Failed(Message
,Cnf
);
1987 if (QueueNext() == false)
1989 // This is the retry counter
1991 Cnf
->LocalOnly
== false &&
1992 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1995 Vf
= Version
.FileList();
1996 if (QueueNext() == true)
2000 StoreFilename
= string();
2001 Item::Failed(Message
,Cnf
);
2005 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2006 // ---------------------------------------------------------------------
2007 bool pkgAcqArchive::IsTrusted()
2012 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2013 // ---------------------------------------------------------------------
2015 void pkgAcqArchive::Finished()
2017 if (Status
== pkgAcquire::Item::StatDone
&&
2020 StoreFilename
= string();
2023 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2024 // ---------------------------------------------------------------------
2025 /* The file is added to the queue */
2026 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
2027 unsigned long long Size
,string Dsc
,string ShortDesc
,
2028 const string
&DestDir
, const string
&DestFilename
,
2030 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
2032 Retries
= _config
->FindI("Acquire::Retries",0);
2034 if(!DestFilename
.empty())
2035 DestFile
= DestFilename
;
2036 else if(!DestDir
.empty())
2037 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2039 DestFile
= flNotDir(URI
);
2043 Desc
.Description
= Dsc
;
2046 // Set the short description to the archive component
2047 Desc
.ShortDesc
= ShortDesc
;
2049 // Get the transfer sizes
2052 if (stat(DestFile
.c_str(),&Buf
) == 0)
2054 // Hmm, the partial file is too big, erase it
2055 if ((unsigned long long)Buf
.st_size
> Size
)
2056 unlink(DestFile
.c_str());
2058 PartialSize
= Buf
.st_size
;
2064 // AcqFile::Done - Item downloaded OK /*{{{*/
2065 // ---------------------------------------------------------------------
2067 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
2068 pkgAcquire::MethodConfig
*Cnf
)
2070 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2073 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2075 RenameOnError(HashSumMismatch
);
2079 string FileName
= LookupTag(Message
,"Filename");
2080 if (FileName
.empty() == true)
2083 ErrorText
= "Method gave a blank filename";
2089 // The files timestamp matches
2090 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2093 // We have to copy it into place
2094 if (FileName
!= DestFile
)
2097 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2098 Cnf
->Removable
== true)
2100 Desc
.URI
= "copy:" + FileName
;
2105 // Erase the file if it is a symlink so we can overwrite it
2107 if (lstat(DestFile
.c_str(),&St
) == 0)
2109 if (S_ISLNK(St
.st_mode
) != 0)
2110 unlink(DestFile
.c_str());
2114 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2116 ErrorText
= "Link to " + DestFile
+ " failure ";
2123 // AcqFile::Failed - Failure handler /*{{{*/
2124 // ---------------------------------------------------------------------
2125 /* Here we try other sources */
2126 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2128 ErrorText
= LookupTag(Message
,"Message");
2130 // This is the retry counter
2132 Cnf
->LocalOnly
== false &&
2133 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2140 Item::Failed(Message
,Cnf
);
2143 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2144 // ---------------------------------------------------------------------
2145 /* The only header we use is the last-modified header. */
2146 string
pkgAcqFile::Custom600Headers()
2149 return "\nIndex-File: true";