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>
42 // Acquire::Item::Item - Constructor /*{{{*/
43 // ---------------------------------------------------------------------
45 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
46 PartialSize(0), Mode(0), ID(0), Complete(false),
47 Local(false), QueueCounter(0)
53 // Acquire::Item::~Item - Destructor /*{{{*/
54 // ---------------------------------------------------------------------
56 pkgAcquire::Item::~Item()
61 // Acquire::Item::Failed - Item failed to download /*{{{*/
62 // ---------------------------------------------------------------------
63 /* We return to an idle state if there are still other queues that could
65 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
68 ErrorText
= LookupTag(Message
,"Message");
69 UsedMirror
= LookupTag(Message
,"UsedMirror");
70 if (QueueCounter
<= 1)
72 /* This indicates that the file is not available right now but might
73 be sometime later. If we do a retry cycle then this should be
75 if (Cnf
->LocalOnly
== true &&
76 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
87 // report mirror failure back to LP if we actually use a mirror
88 string FailReason
= LookupTag(Message
, "FailReason");
89 if(FailReason
.size() != 0)
90 ReportMirrorFailure(FailReason
);
92 ReportMirrorFailure(ErrorText
);
95 // Acquire::Item::Start - Item has begun to download /*{{{*/
96 // ---------------------------------------------------------------------
97 /* Stash status and the file size. Note that setting Complete means
98 sub-phases of the acquire process such as decompresion are operating */
99 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
101 Status
= StatFetching
;
102 if (FileSize
== 0 && Complete
== false)
106 // Acquire::Item::Done - Item downloaded OK /*{{{*/
107 // ---------------------------------------------------------------------
109 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,string Hash
,
110 pkgAcquire::MethodConfig
*Cnf
)
112 // We just downloaded something..
113 string FileName
= LookupTag(Message
,"Filename");
114 UsedMirror
= LookupTag(Message
,"UsedMirror");
115 if (Complete
== false && !Local
&& FileName
== DestFile
)
118 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
124 ErrorText
= string();
125 Owner
->Dequeue(this);
128 // Acquire::Item::Rename - Rename a file /*{{{*/
129 // ---------------------------------------------------------------------
130 /* This helper function is used by alot of item methods as thier final
132 void pkgAcquire::Item::Rename(string From
,string To
)
134 if (rename(From
.c_str(),To
.c_str()) != 0)
137 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
138 From
.c_str(),To
.c_str());
144 // Acquire::Item::ReportMirrorFailure /*{{{*/
145 // ---------------------------------------------------------------------
146 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
148 // we only act if a mirror was used at all
149 if(UsedMirror
.empty())
152 std::cerr
<< "\nReportMirrorFailure: "
154 << " Uri: " << DescURI()
156 << FailCode
<< std::endl
;
158 const char *Args
[40];
160 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
161 "/usr/lib/apt/apt-report-mirror-failure");
162 if(!FileExists(report
))
164 Args
[i
++] = report
.c_str();
165 Args
[i
++] = UsedMirror
.c_str();
166 Args
[i
++] = DescURI().c_str();
167 Args
[i
++] = FailCode
.c_str();
169 pid_t pid
= ExecFork();
172 _error
->Error("ReportMirrorFailure Fork failed");
177 execvp(Args
[0], (char**)Args
);
178 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
181 if(!ExecWait(pid
, "report-mirror-failure"))
183 _error
->Warning("Couldn't report problem to '%s'",
184 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
188 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
189 // ---------------------------------------------------------------------
190 /* Get the Index file first and see if there are languages available
191 * If so, create a pkgAcqIndexTrans for the found language(s).
193 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
194 string
const &URIDesc
, string
const &ShortDesc
,
195 HashString
const &ExpectedHash
)
196 : Item(Owner
), ExpectedHash(ExpectedHash
)
198 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
200 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
201 DestFile
+= URItoFileName(URI
);
204 Desc
.Description
= URIDesc
;
206 Desc
.ShortDesc
= ShortDesc
;
211 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
214 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
215 // ---------------------------------------------------------------------
216 /* The only header we use is the last-modified header. */
217 string
pkgAcqSubIndex::Custom600Headers()
219 string Final
= _config
->FindDir("Dir::State::lists");
220 Final
+= URItoFileName(Desc
.URI
);
223 if (stat(Final
.c_str(),&Buf
) != 0)
224 return "\nIndex-File: true\nFail-Ignore: true\n";
225 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
228 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
231 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< std::endl
;
237 // No good Index is provided, so try guessing
238 std::vector
<std::string
> langs
= APT::Configuration::getLanguages(true);
239 for (std::vector
<std::string
>::const_iterator l
= langs
.begin();
240 l
!= langs
.end(); ++l
)
242 if (*l
== "none") continue;
243 string
const file
= "Translation-" + *l
;
244 new pkgAcqIndexTrans(Owner
, Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
),
245 Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
),
250 void pkgAcqSubIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
251 pkgAcquire::MethodConfig
*Cnf
)
254 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
256 string FileName
= LookupTag(Message
,"Filename");
257 if (FileName
.empty() == true)
260 ErrorText
= "Method gave a blank filename";
264 if (FileName
!= DestFile
)
267 Desc
.URI
= "copy:" + FileName
;
272 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
274 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
276 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
277 indexRecords SubIndexParser
;
278 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
280 ErrorText
= SubIndexParser
.ErrorText
;
284 // sucess in downloading the index
287 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
288 Rename(DestFile
,FinalFile
);
289 chmod(FinalFile
.c_str(),0644);
290 DestFile
= FinalFile
;
292 if(ParseIndex(DestFile
) == false)
293 return Failed("", NULL
);
301 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
303 indexRecords SubIndexParser
;
304 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
307 std::vector
<std::string
> lang
= APT::Configuration::getLanguages(true);
308 for (std::vector
<std::string
>::const_iterator l
= lang
.begin();
309 l
!= lang
.end(); ++l
)
314 string file
= "Translation-" + *l
;
315 indexRecords::checkSum
const *Record
= SubIndexParser
.Lookup(file
);
319 // FIXME: the Index file provided by debian currently only includes bz2 records
320 Record
= SubIndexParser
.Lookup(file
+ ".bz2");
326 expected
= Record
->Hash
;
327 if (expected
.empty() == true)
332 target
.Description
= Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
);
333 target
.MetaKey
= file
;
334 target
.ShortDesc
= file
;
335 target
.URI
= Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
);
336 new pkgAcqIndexTrans(Owner
, &target
, expected
, &SubIndexParser
);
341 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
342 // ---------------------------------------------------------------------
343 /* Get the DiffIndex file first and see if there are patches availabe
344 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
345 * patches. If anything goes wrong in that process, it will fall back to
346 * the original packages file
348 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
349 string URI
,string URIDesc
,string ShortDesc
,
350 HashString ExpectedHash
)
351 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
355 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
357 Desc
.Description
= URIDesc
+ "/DiffIndex";
359 Desc
.ShortDesc
= ShortDesc
;
360 Desc
.URI
= URI
+ ".diff/Index";
362 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
363 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
366 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
368 // look for the current package file
369 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
370 CurrentPackagesFile
+= URItoFileName(RealURI
);
372 // FIXME: this file:/ check is a hack to prevent fetching
373 // from local sources. this is really silly, and
374 // should be fixed cleanly as soon as possible
375 if(!FileExists(CurrentPackagesFile
) ||
376 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
378 // we don't have a pkg file or we don't want to queue
380 std::clog
<< "No index file, local or canceld by user" << std::endl
;
386 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
387 << CurrentPackagesFile
<< std::endl
;
393 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
394 // ---------------------------------------------------------------------
395 /* The only header we use is the last-modified header. */
396 string
pkgAcqDiffIndex::Custom600Headers()
398 string Final
= _config
->FindDir("Dir::State::lists");
399 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
402 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
405 if (stat(Final
.c_str(),&Buf
) != 0)
406 return "\nIndex-File: true";
408 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
411 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
414 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
419 vector
<DiffInfo
> available_patches
;
421 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
423 if (_error
->PendingError() == true)
426 if(TF
.Step(Tags
) == true)
432 string
const tmp
= Tags
.FindS("SHA1-Current");
433 std::stringstream
ss(tmp
);
434 ss
>> ServerSha1
>> size
;
435 unsigned long const ServerSize
= atol(size
.c_str());
437 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
439 SHA1
.AddFD(fd
.Fd(), fd
.Size());
440 string
const local_sha1
= SHA1
.Result();
442 if(local_sha1
== ServerSha1
)
444 // we have the same sha1 as the server
446 std::clog
<< "Package file is up-to-date" << std::endl
;
447 // set found to true, this will queue a pkgAcqIndexDiffs with
448 // a empty availabe_patches
454 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
456 // check the historie and see what patches we need
457 string
const history
= Tags
.FindS("SHA1-History");
458 std::stringstream
hist(history
);
459 while(hist
>> d
.sha1
>> size
>> d
.file
)
461 // read until the first match is found
462 // from that point on, we probably need all diffs
463 if(d
.sha1
== local_sha1
)
465 else if (found
== false)
469 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
470 available_patches
.push_back(d
);
473 if (available_patches
.empty() == false)
475 // patching with too many files is rather slow compared to a fast download
476 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
477 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
480 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
481 << ") so fallback to complete download" << std::endl
;
485 // see if the patches are too big
486 found
= false; // it was true and it will be true again at the end
487 d
= *available_patches
.begin();
488 string
const firstPatch
= d
.file
;
489 unsigned long patchesSize
= 0;
490 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
491 while(patches
>> d
.sha1
>> size
>> d
.file
)
493 if (firstPatch
== d
.file
)
495 else if (found
== false)
498 patchesSize
+= atol(size
.c_str());
500 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
501 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
504 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
505 << ") so fallback to complete download" << std::endl
;
511 // we have something, queue the next diff
515 string::size_type
const last_space
= Description
.rfind(" ");
516 if(last_space
!= string::npos
)
517 Description
.erase(last_space
, Description
.size()-last_space
);
518 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
519 ExpectedHash
, ServerSha1
, available_patches
);
527 // Nothing found, report and return false
528 // Failing here is ok, if we return false later, the full
529 // IndexFile is queued
531 std::clog
<< "Can't find a patch in the index file" << std::endl
;
535 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
538 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
539 << "Falling back to normal index file aquire" << std::endl
;
541 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
549 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
550 pkgAcquire::MethodConfig
*Cnf
)
553 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
555 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
558 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
560 // sucess in downloading the index
562 FinalFile
+= string(".IndexDiff");
564 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
566 Rename(DestFile
,FinalFile
);
567 chmod(FinalFile
.c_str(),0644);
568 DestFile
= FinalFile
;
570 if(!ParseDiffIndex(DestFile
))
571 return Failed("", NULL
);
579 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
580 // ---------------------------------------------------------------------
581 /* The package diff is added to the queue. one object is constructed
582 * for each diff and the index
584 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
585 string URI
,string URIDesc
,string ShortDesc
,
586 HashString ExpectedHash
,
588 vector
<DiffInfo
> diffs
)
589 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
590 available_patches(diffs
), ServerSha1(ServerSha1
)
593 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
594 DestFile
+= URItoFileName(URI
);
596 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
598 Description
= URIDesc
;
600 Desc
.ShortDesc
= ShortDesc
;
602 if(available_patches
.size() == 0)
604 // we are done (yeah!)
610 State
= StateFetchDiff
;
615 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
618 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
619 << "Falling back to normal index file aquire" << std::endl
;
620 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
625 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
626 void pkgAcqIndexDiffs::Finish(bool allDone
)
628 // we restore the original name, this is required, otherwise
629 // the file will be cleaned
632 DestFile
= _config
->FindDir("Dir::State::lists");
633 DestFile
+= URItoFileName(RealURI
);
635 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
637 Status
= StatAuthError
;
638 ErrorText
= _("MD5Sum mismatch");
639 Rename(DestFile
,DestFile
+ ".FAILED");
644 // this is for the "real" finish
649 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
654 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
661 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
664 // calc sha1 of the just patched file
665 string FinalFile
= _config
->FindDir("Dir::State::lists");
666 FinalFile
+= URItoFileName(RealURI
);
668 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
670 SHA1
.AddFD(fd
.Fd(), fd
.Size());
671 string local_sha1
= string(SHA1
.Result());
673 std::clog
<< "QueueNextDiff: "
674 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
676 // final file reached before all patches are applied
677 if(local_sha1
== ServerSha1
)
683 // remove all patches until the next matching patch is found
684 // this requires the Index file to be ordered
685 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
686 available_patches
.empty() == false &&
687 I
!= available_patches
.end() &&
688 I
->sha1
!= local_sha1
;
691 available_patches
.erase(I
);
694 // error checking and falling back if no patch was found
695 if(available_patches
.empty() == true)
701 // queue the right diff
702 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
703 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
704 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
705 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
708 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
715 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
,string Md5Hash
, /*{{{*/
716 pkgAcquire::MethodConfig
*Cnf
)
719 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
721 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
724 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
726 // sucess in downloading a diff, enter ApplyDiff state
727 if(State
== StateFetchDiff
)
730 // rred excepts the patch as $FinalFile.ed
731 Rename(DestFile
,FinalFile
+".ed");
734 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
736 State
= StateApplyDiff
;
738 Desc
.URI
= "rred:" + FinalFile
;
745 // success in download/apply a diff, queue next (if needed)
746 if(State
== StateApplyDiff
)
748 // remove the just applied patch
749 available_patches
.erase(available_patches
.begin());
754 std::clog
<< "Moving patched file in place: " << std::endl
755 << DestFile
<< " -> " << FinalFile
<< std::endl
;
757 Rename(DestFile
,FinalFile
);
758 chmod(FinalFile
.c_str(),0644);
760 // see if there is more to download
761 if(available_patches
.empty() == false) {
762 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
763 ExpectedHash
, ServerSha1
, available_patches
);
770 // AcqIndex::AcqIndex - Constructor /*{{{*/
771 // ---------------------------------------------------------------------
772 /* The package file is added to the queue and a second class is
773 instantiated to fetch the revision file */
774 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
775 string URI
,string URIDesc
,string ShortDesc
,
776 HashString ExpectedHash
, string comprExt
)
777 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
779 if(comprExt
.empty() == true)
781 // autoselect the compression method
782 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
783 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
784 comprExt
.append(*t
).append(" ");
785 if (comprExt
.empty() == false)
786 comprExt
.erase(comprExt
.end()-1);
788 CompressionExtension
= comprExt
;
790 Init(URI
, URIDesc
, ShortDesc
);
792 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
793 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
794 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
796 // autoselect the compression method
797 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
798 CompressionExtension
= "";
799 if (ExpectedHash
.empty() == false)
801 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
802 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
803 CompressionExtension
.append(*t
).append(" ");
807 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
808 CompressionExtension
.append(*t
).append(" ");
810 if (CompressionExtension
.empty() == false)
811 CompressionExtension
.erase(CompressionExtension
.end()-1);
813 // only verify non-optional targets, see acquire-item.h for a FIXME
814 // to make this more flexible
815 if (Target
->IsOptional())
820 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
823 // AcqIndex::Init - defered Constructor /*{{{*/
824 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
825 Decompression
= false;
828 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
829 DestFile
+= URItoFileName(URI
);
831 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
832 if (comprExt
== "uncompressed")
835 Desc
.URI
= URI
+ '.' + comprExt
;
837 Desc
.Description
= URIDesc
;
839 Desc
.ShortDesc
= ShortDesc
;
844 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
845 // ---------------------------------------------------------------------
846 /* The only header we use is the last-modified header. */
847 string
pkgAcqIndex::Custom600Headers()
849 string Final
= _config
->FindDir("Dir::State::lists");
850 Final
+= URItoFileName(RealURI
);
851 if (_config
->FindB("Acquire::GzipIndexes",false))
854 string msg
= "\nIndex-File: true";
855 // FIXME: this really should use "IndexTarget::IsOptional()" but that
856 // seems to be difficult without breaking ABI
857 if (ShortDesc().find("Translation") != 0)
858 msg
+= "\nFail-Ignore: true";
860 if (stat(Final
.c_str(),&Buf
) == 0)
861 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
866 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
868 size_t const nextExt
= CompressionExtension
.find(' ');
869 if (nextExt
!= std::string::npos
)
871 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
872 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
876 // on decompression failure, remove bad versions in partial/
877 if (Decompression
&& Erase
) {
878 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
879 s
.append(URItoFileName(RealURI
));
883 Item::Failed(Message
,Cnf
);
886 // AcqIndex::Done - Finished a fetch /*{{{*/
887 // ---------------------------------------------------------------------
888 /* This goes through a number of states.. On the initial fetch the
889 method could possibly return an alternate filename which points
890 to the uncompressed version of the file. If this is so the file
891 is copied into the partial directory. In all other cases the file
892 is decompressed with a gzip uri. */
893 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,string Hash
,
894 pkgAcquire::MethodConfig
*Cfg
)
896 Item::Done(Message
,Size
,Hash
,Cfg
);
898 if (Decompression
== true)
900 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
902 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
903 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
906 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
908 Status
= StatAuthError
;
909 ErrorText
= _("Hash Sum mismatch");
910 Rename(DestFile
,DestFile
+ ".FAILED");
911 ReportMirrorFailure("HashChecksumFailure");
915 /* Verify the index file for correctness (all indexes must
916 * have a Package field) (LP: #346386) (Closes: #627642) */
919 FileFd
fd(DestFile
, FileFd::ReadOnly
);
923 // Only test for correctness if the file is not empty (empty is ok)
925 if (_error
->PendingError() || !tag
.Step(sec
)) {
927 _error
->DumpErrors();
928 Rename(DestFile
,DestFile
+ ".FAILED");
930 } else if (!sec
.Exists("Package")) {
932 ErrorText
= ("Encountered a section with no Package: header");
933 Rename(DestFile
,DestFile
+ ".FAILED");
939 // Done, move it into position
940 string FinalFile
= _config
->FindDir("Dir::State::lists");
941 FinalFile
+= URItoFileName(RealURI
);
942 Rename(DestFile
,FinalFile
);
943 chmod(FinalFile
.c_str(),0644);
945 /* We restore the original name to DestFile so that the clean operation
947 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
948 DestFile
+= URItoFileName(RealURI
);
950 // Remove the compressed version.
952 unlink(DestFile
.c_str());
959 // Handle the unzipd case
960 string FileName
= LookupTag(Message
,"Alt-Filename");
961 if (FileName
.empty() == false)
963 // The files timestamp matches
964 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
966 Decompression
= true;
968 DestFile
+= ".decomp";
969 Desc
.URI
= "copy:" + FileName
;
975 FileName
= LookupTag(Message
,"Filename");
976 if (FileName
.empty() == true)
979 ErrorText
= "Method gave a blank filename";
982 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
984 // The files timestamp matches
985 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
986 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
987 // Update DestFile for .gz suffix so that the clean operation keeps it
992 if (FileName
== DestFile
)
999 // If we enable compressed indexes and already have gzip, keep it
1000 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
1001 string FinalFile
= _config
->FindDir("Dir::State::lists");
1002 FinalFile
+= URItoFileName(RealURI
) + ".gz";
1003 Rename(DestFile
,FinalFile
);
1004 chmod(FinalFile
.c_str(),0644);
1006 // Update DestFile for .gz suffix so that the clean operation keeps it
1007 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1008 DestFile
+= URItoFileName(RealURI
) + ".gz";
1012 // get the binary name for your used compression type
1013 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1014 if(decompProg
.empty() == false);
1015 else if(compExt
== "uncompressed")
1016 decompProg
= "copy";
1018 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1022 Decompression
= true;
1023 DestFile
+= ".decomp";
1024 Desc
.URI
= decompProg
+ ":" + FileName
;
1026 Mode
= decompProg
.c_str();
1029 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1030 // ---------------------------------------------------------------------
1031 /* The Translation file is added to the queue */
1032 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1033 string URI
,string URIDesc
,string ShortDesc
)
1034 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1037 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1038 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1039 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1043 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1044 // ---------------------------------------------------------------------
1045 string
pkgAcqIndexTrans::Custom600Headers()
1047 string Final
= _config
->FindDir("Dir::State::lists");
1048 Final
+= URItoFileName(RealURI
);
1051 if (stat(Final
.c_str(),&Buf
) != 0)
1052 return "\nFail-Ignore: true\nIndex-File: true";
1053 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1056 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1057 // ---------------------------------------------------------------------
1059 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1061 size_t const nextExt
= CompressionExtension
.find(' ');
1062 if (nextExt
!= std::string::npos
)
1064 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1065 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1070 if (Cnf
->LocalOnly
== true ||
1071 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1080 Item::Failed(Message
,Cnf
);
1083 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1084 string URI
,string URIDesc
,string ShortDesc
,
1085 string MetaIndexURI
, string MetaIndexURIDesc
,
1086 string MetaIndexShortDesc
,
1087 const vector
<IndexTarget
*>* IndexTargets
,
1088 indexRecords
* MetaIndexParser
) :
1089 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1090 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1091 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1093 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1094 DestFile
+= URItoFileName(URI
);
1096 // remove any partial downloaded sig-file in partial/.
1097 // it may confuse proxies and is too small to warrant a
1098 // partial download anyway
1099 unlink(DestFile
.c_str());
1102 Desc
.Description
= URIDesc
;
1104 Desc
.ShortDesc
= ShortDesc
;
1107 string Final
= _config
->FindDir("Dir::State::lists");
1108 Final
+= URItoFileName(RealURI
);
1110 if (stat(Final
.c_str(),&Buf
) == 0)
1112 // File was already in place. It needs to be re-downloaded/verified
1113 // because Release might have changed, we do give it a differnt
1114 // name than DestFile because otherwise the http method will
1115 // send If-Range requests and there are too many broken servers
1116 // out there that do not understand them
1117 LastGoodSig
= DestFile
+".reverify";
1118 Rename(Final
,LastGoodSig
);
1124 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1125 // ---------------------------------------------------------------------
1126 /* The only header we use is the last-modified header. */
1127 string
pkgAcqMetaSig::Custom600Headers()
1130 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1131 return "\nIndex-File: true";
1133 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1136 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,string MD5
,
1137 pkgAcquire::MethodConfig
*Cfg
)
1139 Item::Done(Message
,Size
,MD5
,Cfg
);
1141 string FileName
= LookupTag(Message
,"Filename");
1142 if (FileName
.empty() == true)
1145 ErrorText
= "Method gave a blank filename";
1149 if (FileName
!= DestFile
)
1151 // We have to copy it into place
1153 Desc
.URI
= "copy:" + FileName
;
1160 // put the last known good file back on i-m-s hit (it will
1161 // be re-verified again)
1162 // Else do nothing, we have the new file in DestFile then
1163 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1164 Rename(LastGoodSig
, DestFile
);
1166 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1167 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1168 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1173 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1175 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1177 // if we get a network error we fail gracefully
1178 if(Status
== StatTransientNetworkError
)
1180 Item::Failed(Message
,Cnf
);
1181 // move the sigfile back on transient network failures
1182 if(FileExists(LastGoodSig
))
1183 Rename(LastGoodSig
,Final
);
1185 // set the status back to , Item::Failed likes to reset it
1186 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1190 // Delete any existing sigfile when the acquire failed
1191 unlink(Final
.c_str());
1193 // queue a pkgAcqMetaIndex with no sigfile
1194 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1195 "", IndexTargets
, MetaIndexParser
);
1197 if (Cnf
->LocalOnly
== true ||
1198 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1207 Item::Failed(Message
,Cnf
);
1210 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1211 string URI
,string URIDesc
,string ShortDesc
,
1213 const vector
<struct IndexTarget
*>* IndexTargets
,
1214 indexRecords
* MetaIndexParser
) :
1215 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1216 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1218 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1219 DestFile
+= URItoFileName(URI
);
1222 Desc
.Description
= URIDesc
;
1224 Desc
.ShortDesc
= ShortDesc
;
1230 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1231 // ---------------------------------------------------------------------
1232 /* The only header we use is the last-modified header. */
1233 string
pkgAcqMetaIndex::Custom600Headers()
1235 string Final
= _config
->FindDir("Dir::State::lists");
1236 Final
+= URItoFileName(RealURI
);
1239 if (stat(Final
.c_str(),&Buf
) != 0)
1240 return "\nIndex-File: true";
1242 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1245 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,string Hash
, /*{{{*/
1246 pkgAcquire::MethodConfig
*Cfg
)
1248 Item::Done(Message
,Size
,Hash
,Cfg
);
1250 // MetaIndexes are done in two passes: one to download the
1251 // metaindex with an appropriate method, and a second to verify it
1252 // with the gpgv method
1254 if (AuthPass
== true)
1258 // all cool, move Release file into place
1263 RetrievalDone(Message
);
1265 // Still more retrieving to do
1270 // There was no signature file, so we are finished. Download
1271 // the indexes and do only hashsum verification if possible
1272 MetaIndexParser
->Load(DestFile
);
1273 QueueIndexes(false);
1277 // There was a signature file, so pass it to gpgv for
1280 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1281 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1282 << SigFile
<< "," << DestFile
<< ")\n";
1284 Desc
.URI
= "gpgv:" + SigFile
;
1291 if (Complete
== true)
1293 string FinalFile
= _config
->FindDir("Dir::State::lists");
1294 FinalFile
+= URItoFileName(RealURI
);
1295 if (SigFile
== DestFile
)
1296 SigFile
= FinalFile
;
1297 Rename(DestFile
,FinalFile
);
1298 chmod(FinalFile
.c_str(),0644);
1299 DestFile
= FinalFile
;
1303 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1305 // We have just finished downloading a Release file (it is not
1308 string FileName
= LookupTag(Message
,"Filename");
1309 if (FileName
.empty() == true)
1312 ErrorText
= "Method gave a blank filename";
1316 if (FileName
!= DestFile
)
1319 Desc
.URI
= "copy:" + FileName
;
1324 // make sure to verify against the right file on I-M-S hit
1325 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1328 string FinalFile
= _config
->FindDir("Dir::State::lists");
1329 FinalFile
+= URItoFileName(RealURI
);
1330 if (SigFile
== DestFile
)
1331 SigFile
= FinalFile
;
1332 DestFile
= FinalFile
;
1337 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1339 // At this point, the gpgv method has succeeded, so there is a
1340 // valid signature from a key in the trusted keyring. We
1341 // perform additional verification of its contents, and use them
1342 // to verify the indexes we are about to download
1344 if (!MetaIndexParser
->Load(DestFile
))
1346 Status
= StatAuthError
;
1347 ErrorText
= MetaIndexParser
->ErrorText
;
1351 if (!VerifyVendor(Message
))
1356 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1357 std::cerr
<< "Signature verification succeeded: "
1358 << DestFile
<< std::endl
;
1360 // Download further indexes with verification
1363 // is it a clearsigned MetaIndex file?
1364 if (DestFile
== SigFile
)
1367 // Done, move signature file into position
1368 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1369 URItoFileName(RealURI
) + ".gpg";
1370 Rename(SigFile
,VerifiedSigFile
);
1371 chmod(VerifiedSigFile
.c_str(),0644);
1374 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1377 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1378 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1379 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1382 ErrorText
= MetaIndexParser
->ErrorText
;
1386 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1387 Target
!= IndexTargets
->end();
1390 HashString ExpectedIndexHash
;
1391 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1394 if (verify
== true && (*Target
)->IsOptional() == false)
1396 Status
= StatAuthError
;
1397 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1403 ExpectedIndexHash
= Record
->Hash
;
1404 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1406 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1407 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1408 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1410 if (verify
== true && ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1412 Status
= StatAuthError
;
1413 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1418 if ((*Target
)->IsOptional() == true)
1420 if ((*Target
)->IsSubIndex() == true)
1421 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1422 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1424 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1428 /* Queue Packages file (either diff or full packages files, depending
1429 on the users option) - we also check if the PDiff Index file is listed
1430 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1431 instead, but passing the required info to it is to much hassle */
1432 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1433 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1434 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1435 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1437 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1441 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1443 string::size_type pos
;
1445 // check for missing sigs (that where not fatal because otherwise we had
1448 string msg
= _("There is no public key available for the "
1449 "following key IDs:\n");
1450 pos
= Message
.find("NO_PUBKEY ");
1451 if (pos
!= std::string::npos
)
1453 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1454 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1455 missingkeys
+= (Fingerprint
);
1457 if(!missingkeys
.empty())
1458 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1460 string Transformed
= MetaIndexParser
->GetExpectedDist();
1462 if (Transformed
== "../project/experimental")
1464 Transformed
= "experimental";
1467 pos
= Transformed
.rfind('/');
1468 if (pos
!= string::npos
)
1470 Transformed
= Transformed
.substr(0, pos
);
1473 if (Transformed
== ".")
1478 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1479 MetaIndexParser
->GetValidUntil() > 0) {
1480 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1481 if (invalid_since
> 0)
1482 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1483 // the time since then the file is invalid - formated in the same way as in
1484 // the download progress display (e.g. 7d 3h 42min 1s)
1485 return _error
->Error(
1486 _("Release file for %s is expired (invalid since %s). "
1487 "Updates for this repository will not be applied."),
1488 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1491 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1493 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1494 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1495 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1498 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1500 // This might become fatal one day
1501 // Status = StatAuthError;
1502 // ErrorText = "Conflicting distribution; expected "
1503 // + MetaIndexParser->GetExpectedDist() + " but got "
1504 // + MetaIndexParser->GetDist();
1506 if (!Transformed
.empty())
1508 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1509 Desc
.Description
.c_str(),
1510 Transformed
.c_str(),
1511 MetaIndexParser
->GetDist().c_str());
1518 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1519 // ---------------------------------------------------------------------
1521 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1523 if (AuthPass
== true)
1525 // gpgv method failed, if we have a good signature
1526 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists");
1527 if (DestFile
== SigFile
)
1528 LastGoodSigFile
.append(URItoFileName(RealURI
));
1530 LastGoodSigFile
.append("partial/").append(URItoFileName(RealURI
)).append(".gpg.reverify");
1532 if(FileExists(LastGoodSigFile
))
1534 if (DestFile
!= SigFile
)
1536 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1537 URItoFileName(RealURI
) + ".gpg";
1538 Rename(LastGoodSigFile
,VerifiedSigFile
);
1540 Status
= StatTransientNetworkError
;
1541 _error
->Warning(_("A error occurred during the signature "
1542 "verification. The repository is not updated "
1543 "and the previous index files will be used. "
1544 "GPG error: %s: %s\n"),
1545 Desc
.Description
.c_str(),
1546 LookupTag(Message
,"Message").c_str());
1547 RunScripts("APT::Update::Auth-Failure");
1549 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1550 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1551 _error
->Error(_("GPG error: %s: %s"),
1552 Desc
.Description
.c_str(),
1553 LookupTag(Message
,"Message").c_str());
1556 _error
->Warning(_("GPG error: %s: %s"),
1557 Desc
.Description
.c_str(),
1558 LookupTag(Message
,"Message").c_str());
1560 // gpgv method failed
1561 ReportMirrorFailure("GPGFailure");
1564 /* Always move the meta index, even if gpgv failed. This ensures
1565 * that PackageFile objects are correctly filled in */
1566 if (FileExists(DestFile
)) {
1567 string FinalFile
= _config
->FindDir("Dir::State::lists");
1568 FinalFile
+= URItoFileName(RealURI
);
1569 /* InRelease files become Release files, otherwise
1570 * they would be considered as trusted later on */
1571 if (SigFile
== DestFile
) {
1572 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1574 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1576 SigFile
= FinalFile
;
1578 Rename(DestFile
,FinalFile
);
1579 chmod(FinalFile
.c_str(),0644);
1581 DestFile
= FinalFile
;
1584 // No Release file was present, or verification failed, so fall
1585 // back to queueing Packages files without verification
1586 QueueIndexes(false);
1589 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1590 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1591 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1592 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1593 const vector
<struct IndexTarget
*>* IndexTargets
,
1594 indexRecords
* MetaIndexParser
) :
1595 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1596 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1597 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1602 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1603 // ---------------------------------------------------------------------
1604 // FIXME: this can go away once the InRelease file is used widely
1605 string
pkgAcqMetaClearSig::Custom600Headers()
1607 string Final
= _config
->FindDir("Dir::State::lists");
1608 Final
+= URItoFileName(RealURI
);
1611 if (stat(Final
.c_str(),&Buf
) != 0)
1612 return "\nIndex-File: true\nFail-Ignore: true\n";
1614 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1617 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1619 if (AuthPass
== false)
1621 new pkgAcqMetaSig(Owner
,
1622 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1623 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1624 IndexTargets
, MetaIndexParser
);
1625 if (Cnf
->LocalOnly
== true ||
1626 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1630 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1633 // AcqArchive::AcqArchive - Constructor /*{{{*/
1634 // ---------------------------------------------------------------------
1635 /* This just sets up the initial fetch environment and queues the first
1637 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1638 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1639 string
&StoreFilename
) :
1640 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1641 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1644 Retries
= _config
->FindI("Acquire::Retries",0);
1646 if (Version
.Arch() == 0)
1648 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1649 "This might mean you need to manually fix this package. "
1650 "(due to missing arch)"),
1651 Version
.ParentPkg().Name());
1655 /* We need to find a filename to determine the extension. We make the
1656 assumption here that all the available sources for this version share
1657 the same extension.. */
1658 // Skip not source sources, they do not have file fields.
1659 for (; Vf
.end() == false; Vf
++)
1661 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1666 // Does not really matter here.. we are going to fail out below
1667 if (Vf
.end() != true)
1669 // If this fails to get a file name we will bomb out below.
1670 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1671 if (_error
->PendingError() == true)
1674 // Generate the final file name as: package_version_arch.foo
1675 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1676 QuoteString(Version
.VerStr(),"_:") + '_' +
1677 QuoteString(Version
.Arch(),"_:.") +
1678 "." + flExtension(Parse
.FileName());
1681 // check if we have one trusted source for the package. if so, switch
1682 // to "TrustedOnly" mode
1683 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1685 pkgIndexFile
*Index
;
1686 if (Sources
->FindIndex(i
.File(),Index
) == false)
1688 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1690 std::cerr
<< "Checking index: " << Index
->Describe()
1691 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1693 if (Index
->IsTrusted()) {
1699 // "allow-unauthenticated" restores apts old fetching behaviour
1700 // that means that e.g. unauthenticated file:// uris are higher
1701 // priority than authenticated http:// uris
1702 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1706 if (QueueNext() == false && _error
->PendingError() == false)
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 Version
.ParentPkg().Name());
1712 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1713 // ---------------------------------------------------------------------
1714 /* This queues the next available file version for download. It checks if
1715 the archive is already available in the cache and stashs the MD5 for
1717 bool pkgAcqArchive::QueueNext()
1719 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1720 for (; Vf
.end() == false; ++Vf
)
1722 // Ignore not source sources
1723 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1726 // Try to cross match against the source list
1727 pkgIndexFile
*Index
;
1728 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1731 // only try to get a trusted package from another source if that source
1733 if(Trusted
&& !Index
->IsTrusted())
1736 // Grab the text package record
1737 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1738 if (_error
->PendingError() == true)
1741 string PkgFile
= Parse
.FileName();
1742 if (ForceHash
.empty() == false)
1744 if(stringcasecmp(ForceHash
, "sha512") == 0)
1745 ExpectedHash
= HashString("SHA512", Parse
.SHA512Hash());
1746 if(stringcasecmp(ForceHash
, "sha256") == 0)
1747 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1748 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1749 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1751 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1756 if ((Hash
= Parse
.SHA512Hash()).empty() == false)
1757 ExpectedHash
= HashString("SHA512", Hash
);
1758 else if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1759 ExpectedHash
= HashString("SHA256", Hash
);
1760 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1761 ExpectedHash
= HashString("SHA1", Hash
);
1763 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1765 if (PkgFile
.empty() == true)
1766 return _error
->Error(_("The package index files are corrupted. No Filename: "
1767 "field for package %s."),
1768 Version
.ParentPkg().Name());
1770 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1771 Desc
.Description
= Index
->ArchiveInfo(Version
);
1773 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1775 // See if we already have the file. (Legacy filenames)
1776 FileSize
= Version
->Size
;
1777 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1779 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1781 // Make sure the size matches
1782 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1787 StoreFilename
= DestFile
= FinalFile
;
1791 /* Hmm, we have a file and its size does not match, this means it is
1792 an old style mismatched arch */
1793 unlink(FinalFile
.c_str());
1796 // Check it again using the new style output filenames
1797 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1798 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1800 // Make sure the size matches
1801 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
1806 StoreFilename
= DestFile
= FinalFile
;
1810 /* Hmm, we have a file and its size does not match, this shouldnt
1812 unlink(FinalFile
.c_str());
1815 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1817 // Check the destination file
1818 if (stat(DestFile
.c_str(),&Buf
) == 0)
1820 // Hmm, the partial file is too big, erase it
1821 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
1822 unlink(DestFile
.c_str());
1824 PartialSize
= Buf
.st_size
;
1829 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1830 Desc
.Description
= Index
->ArchiveInfo(Version
);
1832 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1841 // AcqArchive::Done - Finished fetching /*{{{*/
1842 // ---------------------------------------------------------------------
1844 void pkgAcqArchive::Done(string Message
,unsigned long long Size
,string CalcHash
,
1845 pkgAcquire::MethodConfig
*Cfg
)
1847 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1850 if (Size
!= Version
->Size
)
1853 ErrorText
= _("Size mismatch");
1858 if(ExpectedHash
.toStr() != CalcHash
)
1861 ErrorText
= _("Hash Sum mismatch");
1862 if(FileExists(DestFile
))
1863 Rename(DestFile
,DestFile
+ ".FAILED");
1867 // Grab the output filename
1868 string FileName
= LookupTag(Message
,"Filename");
1869 if (FileName
.empty() == true)
1872 ErrorText
= "Method gave a blank filename";
1878 // Reference filename
1879 if (FileName
!= DestFile
)
1881 StoreFilename
= DestFile
= FileName
;
1886 // Done, move it into position
1887 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1888 FinalFile
+= flNotDir(StoreFilename
);
1889 Rename(DestFile
,FinalFile
);
1891 StoreFilename
= DestFile
= FinalFile
;
1895 // AcqArchive::Failed - Failure handler /*{{{*/
1896 // ---------------------------------------------------------------------
1897 /* Here we try other sources */
1898 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1900 ErrorText
= LookupTag(Message
,"Message");
1902 /* We don't really want to retry on failed media swaps, this prevents
1903 that. An interesting observation is that permanent failures are not
1905 if (Cnf
->Removable
== true &&
1906 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1908 // Vf = Version.FileList();
1909 while (Vf
.end() == false) ++Vf
;
1910 StoreFilename
= string();
1911 Item::Failed(Message
,Cnf
);
1915 if (QueueNext() == false)
1917 // This is the retry counter
1919 Cnf
->LocalOnly
== false &&
1920 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1923 Vf
= Version
.FileList();
1924 if (QueueNext() == true)
1928 StoreFilename
= string();
1929 Item::Failed(Message
,Cnf
);
1933 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1934 // ---------------------------------------------------------------------
1935 bool pkgAcqArchive::IsTrusted()
1940 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1941 // ---------------------------------------------------------------------
1943 void pkgAcqArchive::Finished()
1945 if (Status
== pkgAcquire::Item::StatDone
&&
1948 StoreFilename
= string();
1951 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1952 // ---------------------------------------------------------------------
1953 /* The file is added to the queue */
1954 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1955 unsigned long long Size
,string Dsc
,string ShortDesc
,
1956 const string
&DestDir
, const string
&DestFilename
,
1958 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
1960 Retries
= _config
->FindI("Acquire::Retries",0);
1962 if(!DestFilename
.empty())
1963 DestFile
= DestFilename
;
1964 else if(!DestDir
.empty())
1965 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1967 DestFile
= flNotDir(URI
);
1971 Desc
.Description
= Dsc
;
1974 // Set the short description to the archive component
1975 Desc
.ShortDesc
= ShortDesc
;
1977 // Get the transfer sizes
1980 if (stat(DestFile
.c_str(),&Buf
) == 0)
1982 // Hmm, the partial file is too big, erase it
1983 if ((unsigned long long)Buf
.st_size
> Size
)
1984 unlink(DestFile
.c_str());
1986 PartialSize
= Buf
.st_size
;
1992 // AcqFile::Done - Item downloaded OK /*{{{*/
1993 // ---------------------------------------------------------------------
1995 void pkgAcqFile::Done(string Message
,unsigned long long Size
,string CalcHash
,
1996 pkgAcquire::MethodConfig
*Cnf
)
1998 Item::Done(Message
,Size
,CalcHash
,Cnf
);
2001 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
2004 ErrorText
= _("Hash Sum mismatch");
2005 Rename(DestFile
,DestFile
+ ".FAILED");
2009 string FileName
= LookupTag(Message
,"Filename");
2010 if (FileName
.empty() == true)
2013 ErrorText
= "Method gave a blank filename";
2019 // The files timestamp matches
2020 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2023 // We have to copy it into place
2024 if (FileName
!= DestFile
)
2027 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2028 Cnf
->Removable
== true)
2030 Desc
.URI
= "copy:" + FileName
;
2035 // Erase the file if it is a symlink so we can overwrite it
2037 if (lstat(DestFile
.c_str(),&St
) == 0)
2039 if (S_ISLNK(St
.st_mode
) != 0)
2040 unlink(DestFile
.c_str());
2044 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2046 ErrorText
= "Link to " + DestFile
+ " failure ";
2053 // AcqFile::Failed - Failure handler /*{{{*/
2054 // ---------------------------------------------------------------------
2055 /* Here we try other sources */
2056 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2058 ErrorText
= LookupTag(Message
,"Message");
2060 // This is the retry counter
2062 Cnf
->LocalOnly
== false &&
2063 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2070 Item::Failed(Message
,Cnf
);
2073 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2074 // ---------------------------------------------------------------------
2075 /* The only header we use is the last-modified header. */
2076 string
pkgAcqFile::Custom600Headers()
2079 return "\nIndex-File: true";