1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
4 /* ######################################################################
6 Acquire Item - Item to acquire
8 Each item can download to exactly one file at a time. This means you
9 cannot create an item that fetches two uri's to two files at the same
10 time. The pkgAcqIndex class creates a second class upon instantiation
11 to fetch the other index files because of this.
13 ##################################################################### */
15 // Include Files /*{{{*/
16 #include <apt-pkg/acquire-item.h>
17 #include <apt-pkg/configuration.h>
18 #include <apt-pkg/aptconfiguration.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/error.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/fileutl.h>
23 #include <apt-pkg/md5.h>
24 #include <apt-pkg/sha1.h>
25 #include <apt-pkg/tagfile.h>
40 // Acquire::Item::Item - Constructor /*{{{*/
41 // ---------------------------------------------------------------------
43 pkgAcquire::Item::Item(pkgAcquire
*Owner
) : Owner(Owner
), FileSize(0),
44 PartialSize(0), Mode(0), ID(0), Complete(false),
45 Local(false), QueueCounter(0)
51 // Acquire::Item::~Item - Destructor /*{{{*/
52 // ---------------------------------------------------------------------
54 pkgAcquire::Item::~Item()
59 // Acquire::Item::Failed - Item failed to download /*{{{*/
60 // ---------------------------------------------------------------------
61 /* We return to an idle state if there are still other queues that could
63 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
66 ErrorText
= LookupTag(Message
,"Message");
67 UsedMirror
= LookupTag(Message
,"UsedMirror");
68 if (QueueCounter
<= 1)
70 /* This indicates that the file is not available right now but might
71 be sometime later. If we do a retry cycle then this should be
73 if (Cnf
->LocalOnly
== true &&
74 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
85 // report mirror failure back to LP if we actually use a mirror
86 string FailReason
= LookupTag(Message
, "FailReason");
87 if(FailReason
.size() != 0)
88 ReportMirrorFailure(FailReason
);
90 ReportMirrorFailure(ErrorText
);
93 // Acquire::Item::Start - Item has begun to download /*{{{*/
94 // ---------------------------------------------------------------------
95 /* Stash status and the file size. Note that setting Complete means
96 sub-phases of the acquire process such as decompresion are operating */
97 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long Size
)
99 Status
= StatFetching
;
100 if (FileSize
== 0 && Complete
== false)
104 // Acquire::Item::Done - Item downloaded OK /*{{{*/
105 // ---------------------------------------------------------------------
107 void pkgAcquire::Item::Done(string Message
,unsigned long Size
,string Hash
,
108 pkgAcquire::MethodConfig
*Cnf
)
110 // We just downloaded something..
111 string FileName
= LookupTag(Message
,"Filename");
112 UsedMirror
= LookupTag(Message
,"UsedMirror");
113 if (Complete
== false && !Local
&& FileName
== DestFile
)
116 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
122 ErrorText
= string();
123 Owner
->Dequeue(this);
126 // Acquire::Item::Rename - Rename a file /*{{{*/
127 // ---------------------------------------------------------------------
128 /* This helper function is used by alot of item methods as thier final
130 void pkgAcquire::Item::Rename(string From
,string To
)
132 if (rename(From
.c_str(),To
.c_str()) != 0)
135 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
136 From
.c_str(),To
.c_str());
142 // Acquire::Item::ReportMirrorFailure /*{{{*/
143 // ---------------------------------------------------------------------
144 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
146 // we only act if a mirror was used at all
147 if(UsedMirror
.empty())
150 std::cerr
<< "\nReportMirrorFailure: "
152 << " Uri: " << DescURI()
154 << FailCode
<< std::endl
;
156 const char *Args
[40];
158 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
159 "/usr/lib/apt/apt-report-mirror-failure");
160 if(!FileExists(report
))
162 Args
[i
++] = report
.c_str();
163 Args
[i
++] = UsedMirror
.c_str();
164 Args
[i
++] = DescURI().c_str();
165 Args
[i
++] = FailCode
.c_str();
167 pid_t pid
= ExecFork();
170 _error
->Error("ReportMirrorFailure Fork failed");
175 execvp(Args
[0], (char**)Args
);
176 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
179 if(!ExecWait(pid
, "report-mirror-failure"))
181 _error
->Warning("Couldn't report problem to '%s'",
182 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
186 // AcqSubIndex::AcqSubIndex - Constructor /*{{{*/
187 // ---------------------------------------------------------------------
188 /* Get the Index file first and see if there are languages available
189 * If so, create a pkgAcqIndexTrans for the found language(s).
191 pkgAcqSubIndex::pkgAcqSubIndex(pkgAcquire
*Owner
, string
const &URI
,
192 string
const &URIDesc
, string
const &ShortDesc
,
193 HashString
const &ExpectedHash
)
194 : Item(Owner
), ExpectedHash(ExpectedHash
)
196 Debug
= _config
->FindB("Debug::pkgAcquire::SubIndex",false);
198 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
199 DestFile
+= URItoFileName(URI
);
202 Desc
.Description
= URIDesc
;
204 Desc
.ShortDesc
= ShortDesc
;
209 std::clog
<< "pkgAcqSubIndex: " << Desc
.URI
<< std::endl
;
212 // AcqSubIndex::Custom600Headers - Insert custom request headers /*{{{*/
213 // ---------------------------------------------------------------------
214 /* The only header we use is the last-modified header. */
215 string
pkgAcqSubIndex::Custom600Headers()
217 string Final
= _config
->FindDir("Dir::State::lists");
218 Final
+= URItoFileName(Desc
.URI
);
221 if (stat(Final
.c_str(),&Buf
) != 0)
222 return "\nIndex-File: true\nFail-Ignore: true\n";
223 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
226 void pkgAcqSubIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
229 std::clog
<< "pkgAcqSubIndex failed: " << Desc
.URI
<< std::endl
;
235 // No good Index is provided, so try guessing
236 std::vector
<std::string
> langs
= APT::Configuration::getLanguages(true);
237 for (std::vector
<std::string
>::const_iterator l
= langs
.begin();
238 l
!= langs
.end(); ++l
)
240 if (*l
== "none") continue;
241 string
const file
= "Translation-" + *l
;
242 new pkgAcqIndexTrans(Owner
, Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
),
243 Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
),
248 void pkgAcqSubIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
249 pkgAcquire::MethodConfig
*Cnf
)
252 std::clog
<< "pkgAcqSubIndex::Done(): " << Desc
.URI
<< std::endl
;
254 string FileName
= LookupTag(Message
,"Filename");
255 if (FileName
.empty() == true)
258 ErrorText
= "Method gave a blank filename";
262 if (FileName
!= DestFile
)
265 Desc
.URI
= "copy:" + FileName
;
270 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
272 string FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(Desc
.URI
);
274 // sucess in downloading the index
277 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
278 Rename(DestFile
,FinalFile
);
279 chmod(FinalFile
.c_str(),0644);
280 DestFile
= FinalFile
;
282 if(ParseIndex(DestFile
) == false)
283 return Failed("", NULL
);
291 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
293 indexRecords SubIndexParser
;
294 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
297 std::vector
<std::string
> lang
= APT::Configuration::getLanguages(true);
298 for (std::vector
<std::string
>::const_iterator l
= lang
.begin();
299 l
!= lang
.end(); ++l
)
304 string file
= "Translation-" + *l
;
305 indexRecords::checkSum
const *Record
= SubIndexParser
.Lookup(file
);
309 // FIXME: the Index file provided by debian currently only includes bz2 records
310 Record
= SubIndexParser
.Lookup(file
+ ".bz2");
316 expected
= Record
->Hash
;
317 if (expected
.empty() == true)
322 target
.Description
= Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
);
323 target
.MetaKey
= file
;
324 target
.ShortDesc
= file
;
325 target
.URI
= Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
);
326 new pkgAcqIndexTrans(Owner
, &target
, expected
, &SubIndexParser
);
331 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
332 // ---------------------------------------------------------------------
333 /* Get the DiffIndex file first and see if there are patches availabe
334 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
335 * patches. If anything goes wrong in that process, it will fall back to
336 * the original packages file
338 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
339 string URI
,string URIDesc
,string ShortDesc
,
340 HashString ExpectedHash
)
341 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
345 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
347 Desc
.Description
= URIDesc
+ "/DiffIndex";
349 Desc
.ShortDesc
= ShortDesc
;
350 Desc
.URI
= URI
+ ".diff/Index";
352 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
353 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
356 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
358 // look for the current package file
359 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
360 CurrentPackagesFile
+= URItoFileName(RealURI
);
362 // FIXME: this file:/ check is a hack to prevent fetching
363 // from local sources. this is really silly, and
364 // should be fixed cleanly as soon as possible
365 if(!FileExists(CurrentPackagesFile
) ||
366 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
368 // we don't have a pkg file or we don't want to queue
370 std::clog
<< "No index file, local or canceld by user" << std::endl
;
376 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
377 << CurrentPackagesFile
<< std::endl
;
383 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
384 // ---------------------------------------------------------------------
385 /* The only header we use is the last-modified header. */
386 string
pkgAcqDiffIndex::Custom600Headers()
388 string Final
= _config
->FindDir("Dir::State::lists");
389 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
392 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
395 if (stat(Final
.c_str(),&Buf
) != 0)
396 return "\nIndex-File: true";
398 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
401 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
404 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
409 vector
<DiffInfo
> available_patches
;
411 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
413 if (_error
->PendingError() == true)
416 if(TF
.Step(Tags
) == true)
422 string
const tmp
= Tags
.FindS("SHA1-Current");
423 std::stringstream
ss(tmp
);
424 ss
>> ServerSha1
>> size
;
425 unsigned long const ServerSize
= atol(size
.c_str());
427 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
429 SHA1
.AddFD(fd
.Fd(), fd
.Size());
430 string
const local_sha1
= SHA1
.Result();
432 if(local_sha1
== ServerSha1
)
434 // we have the same sha1 as the server
436 std::clog
<< "Package file is up-to-date" << std::endl
;
437 // set found to true, this will queue a pkgAcqIndexDiffs with
438 // a empty availabe_patches
444 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
446 // check the historie and see what patches we need
447 string
const history
= Tags
.FindS("SHA1-History");
448 std::stringstream
hist(history
);
449 while(hist
>> d
.sha1
>> size
>> d
.file
)
451 // read until the first match is found
452 // from that point on, we probably need all diffs
453 if(d
.sha1
== local_sha1
)
455 else if (found
== false)
459 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
460 available_patches
.push_back(d
);
463 if (available_patches
.empty() == false)
465 // patching with too many files is rather slow compared to a fast download
466 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
467 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
470 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
471 << ") so fallback to complete download" << std::endl
;
475 // see if the patches are too big
476 found
= false; // it was true and it will be true again at the end
477 d
= *available_patches
.begin();
478 string
const firstPatch
= d
.file
;
479 unsigned long patchesSize
= 0;
480 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
481 while(patches
>> d
.sha1
>> size
>> d
.file
)
483 if (firstPatch
== d
.file
)
485 else if (found
== false)
488 patchesSize
+= atol(size
.c_str());
490 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
491 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
494 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
495 << ") so fallback to complete download" << std::endl
;
501 // we have something, queue the next diff
505 string::size_type
const last_space
= Description
.rfind(" ");
506 if(last_space
!= string::npos
)
507 Description
.erase(last_space
, Description
.size()-last_space
);
508 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
509 ExpectedHash
, ServerSha1
, available_patches
);
517 // Nothing found, report and return false
518 // Failing here is ok, if we return false later, the full
519 // IndexFile is queued
521 std::clog
<< "Can't find a patch in the index file" << std::endl
;
525 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
528 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
529 << "Falling back to normal index file aquire" << std::endl
;
531 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
539 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
540 pkgAcquire::MethodConfig
*Cnf
)
543 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
545 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
548 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
550 // sucess in downloading the index
552 FinalFile
+= string(".IndexDiff");
554 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
556 Rename(DestFile
,FinalFile
);
557 chmod(FinalFile
.c_str(),0644);
558 DestFile
= FinalFile
;
560 if(!ParseDiffIndex(DestFile
))
561 return Failed("", NULL
);
569 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
570 // ---------------------------------------------------------------------
571 /* The package diff is added to the queue. one object is constructed
572 * for each diff and the index
574 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
575 string URI
,string URIDesc
,string ShortDesc
,
576 HashString ExpectedHash
,
578 vector
<DiffInfo
> diffs
)
579 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
580 available_patches(diffs
), ServerSha1(ServerSha1
)
583 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
584 DestFile
+= URItoFileName(URI
);
586 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
588 Description
= URIDesc
;
590 Desc
.ShortDesc
= ShortDesc
;
592 if(available_patches
.size() == 0)
594 // we are done (yeah!)
600 State
= StateFetchDiff
;
605 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
608 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
609 << "Falling back to normal index file aquire" << std::endl
;
610 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
615 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
616 void pkgAcqIndexDiffs::Finish(bool allDone
)
618 // we restore the original name, this is required, otherwise
619 // the file will be cleaned
622 DestFile
= _config
->FindDir("Dir::State::lists");
623 DestFile
+= URItoFileName(RealURI
);
625 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
627 Status
= StatAuthError
;
628 ErrorText
= _("MD5Sum mismatch");
629 Rename(DestFile
,DestFile
+ ".FAILED");
634 // this is for the "real" finish
639 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
644 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
651 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
654 // calc sha1 of the just patched file
655 string FinalFile
= _config
->FindDir("Dir::State::lists");
656 FinalFile
+= URItoFileName(RealURI
);
658 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
660 SHA1
.AddFD(fd
.Fd(), fd
.Size());
661 string local_sha1
= string(SHA1
.Result());
663 std::clog
<< "QueueNextDiff: "
664 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
666 // final file reached before all patches are applied
667 if(local_sha1
== ServerSha1
)
673 // remove all patches until the next matching patch is found
674 // this requires the Index file to be ordered
675 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
676 available_patches
.size() > 0 &&
677 I
!= available_patches
.end() &&
678 (*I
).sha1
!= local_sha1
;
681 available_patches
.erase(I
);
684 // error checking and falling back if no patch was found
685 if(available_patches
.size() == 0)
691 // queue the right diff
692 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
693 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
694 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
695 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
698 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
705 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
706 pkgAcquire::MethodConfig
*Cnf
)
709 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
711 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
714 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
716 // sucess in downloading a diff, enter ApplyDiff state
717 if(State
== StateFetchDiff
)
720 // rred excepts the patch as $FinalFile.ed
721 Rename(DestFile
,FinalFile
+".ed");
724 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
726 State
= StateApplyDiff
;
728 Desc
.URI
= "rred:" + FinalFile
;
735 // success in download/apply a diff, queue next (if needed)
736 if(State
== StateApplyDiff
)
738 // remove the just applied patch
739 available_patches
.erase(available_patches
.begin());
744 std::clog
<< "Moving patched file in place: " << std::endl
745 << DestFile
<< " -> " << FinalFile
<< std::endl
;
747 Rename(DestFile
,FinalFile
);
748 chmod(FinalFile
.c_str(),0644);
750 // see if there is more to download
751 if(available_patches
.size() > 0) {
752 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
753 ExpectedHash
, ServerSha1
, available_patches
);
760 // AcqIndex::AcqIndex - Constructor /*{{{*/
761 // ---------------------------------------------------------------------
762 /* The package file is added to the queue and a second class is
763 instantiated to fetch the revision file */
764 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
765 string URI
,string URIDesc
,string ShortDesc
,
766 HashString ExpectedHash
, string comprExt
)
767 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
769 if(comprExt
.empty() == true)
771 // autoselect the compression method
772 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
773 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
774 comprExt
.append(*t
).append(" ");
775 if (comprExt
.empty() == false)
776 comprExt
.erase(comprExt
.end()-1);
778 CompressionExtension
= comprExt
;
780 Init(URI
, URIDesc
, ShortDesc
);
782 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
783 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
784 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
786 // autoselect the compression method
787 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
788 CompressionExtension
= "";
789 if (ExpectedHash
.empty() == false)
791 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
792 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
793 CompressionExtension
.append(*t
).append(" ");
797 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
798 CompressionExtension
.append(*t
).append(" ");
800 if (CompressionExtension
.empty() == false)
801 CompressionExtension
.erase(CompressionExtension
.end()-1);
803 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
806 // AcqIndex::Init - defered Constructor /*{{{*/
807 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
808 Decompression
= false;
811 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
812 DestFile
+= URItoFileName(URI
);
814 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
815 if (comprExt
== "uncompressed")
818 Desc
.URI
= URI
+ '.' + comprExt
;
820 Desc
.Description
= URIDesc
;
822 Desc
.ShortDesc
= ShortDesc
;
827 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
828 // ---------------------------------------------------------------------
829 /* The only header we use is the last-modified header. */
830 string
pkgAcqIndex::Custom600Headers()
832 string Final
= _config
->FindDir("Dir::State::lists");
833 Final
+= URItoFileName(RealURI
);
834 if (_config
->FindB("Acquire::GzipIndexes",false))
837 string msg
= "\nIndex-File: true";
838 // FIXME: this really should use "IndexTarget::IsOptional()" but that
839 // seems to be difficult without breaking ABI
840 if (ShortDesc().find("Translation") != 0)
841 msg
+= "\nFail-Ignore: true";
843 if (stat(Final
.c_str(),&Buf
) == 0)
844 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
849 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
851 size_t const nextExt
= CompressionExtension
.find(' ');
852 if (nextExt
!= std::string::npos
)
854 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
855 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
859 // on decompression failure, remove bad versions in partial/
860 if (Decompression
&& Erase
) {
861 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
862 s
.append(URItoFileName(RealURI
));
866 Item::Failed(Message
,Cnf
);
869 // AcqIndex::Done - Finished a fetch /*{{{*/
870 // ---------------------------------------------------------------------
871 /* This goes through a number of states.. On the initial fetch the
872 method could possibly return an alternate filename which points
873 to the uncompressed version of the file. If this is so the file
874 is copied into the partial directory. In all other cases the file
875 is decompressed with a gzip uri. */
876 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string Hash
,
877 pkgAcquire::MethodConfig
*Cfg
)
879 Item::Done(Message
,Size
,Hash
,Cfg
);
881 if (Decompression
== true)
883 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
885 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
886 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
889 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
891 Status
= StatAuthError
;
892 ErrorText
= _("Hash Sum mismatch");
893 Rename(DestFile
,DestFile
+ ".FAILED");
894 ReportMirrorFailure("HashChecksumFailure");
897 // Done, move it into position
898 string FinalFile
= _config
->FindDir("Dir::State::lists");
899 FinalFile
+= URItoFileName(RealURI
);
900 Rename(DestFile
,FinalFile
);
901 chmod(FinalFile
.c_str(),0644);
903 /* We restore the original name to DestFile so that the clean operation
905 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
906 DestFile
+= URItoFileName(RealURI
);
908 // Remove the compressed version.
910 unlink(DestFile
.c_str());
917 // Handle the unzipd case
918 string FileName
= LookupTag(Message
,"Alt-Filename");
919 if (FileName
.empty() == false)
921 // The files timestamp matches
922 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
924 Decompression
= true;
926 DestFile
+= ".decomp";
927 Desc
.URI
= "copy:" + FileName
;
933 FileName
= LookupTag(Message
,"Filename");
934 if (FileName
.empty() == true)
937 ErrorText
= "Method gave a blank filename";
940 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
942 // The files timestamp matches
943 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
944 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
945 // Update DestFile for .gz suffix so that the clean operation keeps it
950 if (FileName
== DestFile
)
957 // If we enable compressed indexes and already have gzip, keep it
958 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
959 string FinalFile
= _config
->FindDir("Dir::State::lists");
960 FinalFile
+= URItoFileName(RealURI
) + ".gz";
961 Rename(DestFile
,FinalFile
);
962 chmod(FinalFile
.c_str(),0644);
964 // Update DestFile for .gz suffix so that the clean operation keeps it
965 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
966 DestFile
+= URItoFileName(RealURI
) + ".gz";
970 // get the binary name for your used compression type
971 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
972 if(decompProg
.empty() == false);
973 else if(compExt
== "uncompressed")
976 _error
->Error("Unsupported extension: %s", compExt
.c_str());
980 Decompression
= true;
981 DestFile
+= ".decomp";
982 Desc
.URI
= decompProg
+ ":" + FileName
;
984 Mode
= decompProg
.c_str();
987 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
988 // ---------------------------------------------------------------------
989 /* The Translation file is added to the queue */
990 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
991 string URI
,string URIDesc
,string ShortDesc
)
992 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
995 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
996 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
997 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1001 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1002 // ---------------------------------------------------------------------
1003 string
pkgAcqIndexTrans::Custom600Headers()
1005 string Final
= _config
->FindDir("Dir::State::lists");
1006 Final
+= URItoFileName(RealURI
);
1009 if (stat(Final
.c_str(),&Buf
) != 0)
1010 return "\nFail-Ignore: true\nIndex-File: true";
1011 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1014 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1015 // ---------------------------------------------------------------------
1017 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1019 size_t const nextExt
= CompressionExtension
.find(' ');
1020 if (nextExt
!= std::string::npos
)
1022 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1023 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1028 if (Cnf
->LocalOnly
== true ||
1029 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1038 Item::Failed(Message
,Cnf
);
1041 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1042 string URI
,string URIDesc
,string ShortDesc
,
1043 string MetaIndexURI
, string MetaIndexURIDesc
,
1044 string MetaIndexShortDesc
,
1045 const vector
<IndexTarget
*>* IndexTargets
,
1046 indexRecords
* MetaIndexParser
) :
1047 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1048 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1049 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1051 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1052 DestFile
+= URItoFileName(URI
);
1054 // remove any partial downloaded sig-file in partial/.
1055 // it may confuse proxies and is too small to warrant a
1056 // partial download anyway
1057 unlink(DestFile
.c_str());
1060 Desc
.Description
= URIDesc
;
1062 Desc
.ShortDesc
= ShortDesc
;
1065 string Final
= _config
->FindDir("Dir::State::lists");
1066 Final
+= URItoFileName(RealURI
);
1068 if (stat(Final
.c_str(),&Buf
) == 0)
1070 // File was already in place. It needs to be re-downloaded/verified
1071 // because Release might have changed, we do give it a differnt
1072 // name than DestFile because otherwise the http method will
1073 // send If-Range requests and there are too many broken servers
1074 // out there that do not understand them
1075 LastGoodSig
= DestFile
+".reverify";
1076 Rename(Final
,LastGoodSig
);
1082 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1083 // ---------------------------------------------------------------------
1084 /* The only header we use is the last-modified header. */
1085 string
pkgAcqMetaSig::Custom600Headers()
1088 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1089 return "\nIndex-File: true";
1091 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1094 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
1095 pkgAcquire::MethodConfig
*Cfg
)
1097 Item::Done(Message
,Size
,MD5
,Cfg
);
1099 string FileName
= LookupTag(Message
,"Filename");
1100 if (FileName
.empty() == true)
1103 ErrorText
= "Method gave a blank filename";
1107 if (FileName
!= DestFile
)
1109 // We have to copy it into place
1111 Desc
.URI
= "copy:" + FileName
;
1118 // put the last known good file back on i-m-s hit (it will
1119 // be re-verified again)
1120 // Else do nothing, we have the new file in DestFile then
1121 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1122 Rename(LastGoodSig
, DestFile
);
1124 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1125 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1126 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1131 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1133 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1135 // if we get a network error we fail gracefully
1136 if(Status
== StatTransientNetworkError
)
1138 Item::Failed(Message
,Cnf
);
1139 // move the sigfile back on transient network failures
1140 if(FileExists(LastGoodSig
))
1141 Rename(LastGoodSig
,Final
);
1143 // set the status back to , Item::Failed likes to reset it
1144 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1148 // Delete any existing sigfile when the acquire failed
1149 unlink(Final
.c_str());
1151 // queue a pkgAcqMetaIndex with no sigfile
1152 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1153 "", IndexTargets
, MetaIndexParser
);
1155 if (Cnf
->LocalOnly
== true ||
1156 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1165 Item::Failed(Message
,Cnf
);
1168 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1169 string URI
,string URIDesc
,string ShortDesc
,
1171 const vector
<struct IndexTarget
*>* IndexTargets
,
1172 indexRecords
* MetaIndexParser
) :
1173 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1174 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1176 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1177 DestFile
+= URItoFileName(URI
);
1180 Desc
.Description
= URIDesc
;
1182 Desc
.ShortDesc
= ShortDesc
;
1188 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1189 // ---------------------------------------------------------------------
1190 /* The only header we use is the last-modified header. */
1191 string
pkgAcqMetaIndex::Custom600Headers()
1193 string Final
= _config
->FindDir("Dir::State::lists");
1194 Final
+= URItoFileName(RealURI
);
1197 if (stat(Final
.c_str(),&Buf
) != 0)
1198 return "\nIndex-File: true";
1200 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1203 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string Hash
, /*{{{*/
1204 pkgAcquire::MethodConfig
*Cfg
)
1206 Item::Done(Message
,Size
,Hash
,Cfg
);
1208 // MetaIndexes are done in two passes: one to download the
1209 // metaindex with an appropriate method, and a second to verify it
1210 // with the gpgv method
1212 if (AuthPass
== true)
1216 // all cool, move Release file into place
1221 RetrievalDone(Message
);
1223 // Still more retrieving to do
1228 // There was no signature file, so we are finished. Download
1229 // the indexes without verification.
1230 QueueIndexes(false);
1234 // There was a signature file, so pass it to gpgv for
1237 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1238 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1239 << SigFile
<< "," << DestFile
<< ")\n";
1241 Desc
.URI
= "gpgv:" + SigFile
;
1248 if (Complete
== true)
1250 string FinalFile
= _config
->FindDir("Dir::State::lists");
1251 FinalFile
+= URItoFileName(RealURI
);
1252 if (SigFile
== DestFile
)
1253 SigFile
= FinalFile
;
1254 Rename(DestFile
,FinalFile
);
1255 chmod(FinalFile
.c_str(),0644);
1256 DestFile
= FinalFile
;
1260 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1262 // We have just finished downloading a Release file (it is not
1265 string FileName
= LookupTag(Message
,"Filename");
1266 if (FileName
.empty() == true)
1269 ErrorText
= "Method gave a blank filename";
1273 if (FileName
!= DestFile
)
1276 Desc
.URI
= "copy:" + FileName
;
1281 // make sure to verify against the right file on I-M-S hit
1282 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1285 string FinalFile
= _config
->FindDir("Dir::State::lists");
1286 FinalFile
+= URItoFileName(RealURI
);
1287 if (SigFile
== DestFile
)
1288 SigFile
= FinalFile
;
1289 DestFile
= FinalFile
;
1294 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1296 // At this point, the gpgv method has succeeded, so there is a
1297 // valid signature from a key in the trusted keyring. We
1298 // perform additional verification of its contents, and use them
1299 // to verify the indexes we are about to download
1301 if (!MetaIndexParser
->Load(DestFile
))
1303 Status
= StatAuthError
;
1304 ErrorText
= MetaIndexParser
->ErrorText
;
1308 if (!VerifyVendor(Message
))
1313 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1314 std::cerr
<< "Signature verification succeeded: "
1315 << DestFile
<< std::endl
;
1317 // Download further indexes with verification
1320 // is it a clearsigned MetaIndex file?
1321 if (DestFile
== SigFile
)
1324 // Done, move signature file into position
1325 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1326 URItoFileName(RealURI
) + ".gpg";
1327 Rename(SigFile
,VerifiedSigFile
);
1328 chmod(VerifiedSigFile
.c_str(),0644);
1331 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1333 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1334 Target
!= IndexTargets
->end();
1337 HashString ExpectedIndexHash
;
1340 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1343 if ((*Target
)->IsOptional() == false)
1345 Status
= StatAuthError
;
1346 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1352 ExpectedIndexHash
= Record
->Hash
;
1353 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1355 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1356 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1358 if (ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1360 Status
= StatAuthError
;
1361 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1367 if ((*Target
)->IsOptional() == true)
1369 if ((*Target
)->IsSubIndex() == true)
1370 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1371 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1373 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1377 /* Queue Packages file (either diff or full packages files, depending
1378 on the users option) - we also check if the PDiff Index file is listed
1379 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1380 instead, but passing the required info to it is to much hassle */
1381 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1382 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1383 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1384 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1386 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1390 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1392 string::size_type pos
;
1394 // check for missing sigs (that where not fatal because otherwise we had
1397 string msg
= _("There is no public key available for the "
1398 "following key IDs:\n");
1399 pos
= Message
.find("NO_PUBKEY ");
1400 if (pos
!= std::string::npos
)
1402 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1403 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1404 missingkeys
+= (Fingerprint
);
1406 if(!missingkeys
.empty())
1407 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1409 string Transformed
= MetaIndexParser
->GetExpectedDist();
1411 if (Transformed
== "../project/experimental")
1413 Transformed
= "experimental";
1416 pos
= Transformed
.rfind('/');
1417 if (pos
!= string::npos
)
1419 Transformed
= Transformed
.substr(0, pos
);
1422 if (Transformed
== ".")
1427 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1428 MetaIndexParser
->GetValidUntil() > 0) {
1429 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1430 if (invalid_since
> 0)
1431 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1432 // the time since then the file is invalid - formated in the same way as in
1433 // the download progress display (e.g. 7d 3h 42min 1s)
1434 return _error
->Error(_("Release file expired, ignoring %s (invalid since %s)"),
1435 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1438 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1440 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1441 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1442 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1445 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1447 // This might become fatal one day
1448 // Status = StatAuthError;
1449 // ErrorText = "Conflicting distribution; expected "
1450 // + MetaIndexParser->GetExpectedDist() + " but got "
1451 // + MetaIndexParser->GetDist();
1453 if (!Transformed
.empty())
1455 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1456 Desc
.Description
.c_str(),
1457 Transformed
.c_str(),
1458 MetaIndexParser
->GetDist().c_str());
1465 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1466 // ---------------------------------------------------------------------
1468 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1470 if (AuthPass
== true)
1472 // gpgv method failed, if we have a good signature
1473 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists");
1474 if (DestFile
== SigFile
)
1475 LastGoodSigFile
.append(URItoFileName(RealURI
));
1477 LastGoodSigFile
.append("partial/").append(URItoFileName(RealURI
)).append(".gpg.reverify");
1479 if(FileExists(LastGoodSigFile
))
1481 if (DestFile
!= SigFile
)
1483 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1484 URItoFileName(RealURI
) + ".gpg";
1485 Rename(LastGoodSigFile
,VerifiedSigFile
);
1487 Status
= StatTransientNetworkError
;
1488 _error
->Warning(_("A error occurred during the signature "
1489 "verification. The repository is not updated "
1490 "and the previous index files will be used. "
1491 "GPG error: %s: %s\n"),
1492 Desc
.Description
.c_str(),
1493 LookupTag(Message
,"Message").c_str());
1494 RunScripts("APT::Update::Auth-Failure");
1497 _error
->Warning(_("GPG error: %s: %s"),
1498 Desc
.Description
.c_str(),
1499 LookupTag(Message
,"Message").c_str());
1501 // gpgv method failed
1502 ReportMirrorFailure("GPGFailure");
1505 /* Always move the meta index, even if gpgv failed. This ensures
1506 * that PackageFile objects are correctly filled in */
1508 string FinalFile
= _config
->FindDir("Dir::State::lists");
1509 FinalFile
+= URItoFileName(RealURI
);
1510 /* InRelease files become Release files, otherwise
1511 * they would be considered as trusted later on */
1512 if (SigFile
== DestFile
) {
1513 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1515 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1517 SigFile
= FinalFile
;
1519 Rename(DestFile
,FinalFile
);
1520 chmod(FinalFile
.c_str(),0644);
1522 DestFile
= FinalFile
;
1525 // No Release file was present, or verification failed, so fall
1526 // back to queueing Packages files without verification
1527 QueueIndexes(false);
1530 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1531 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1532 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1533 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1534 const vector
<struct IndexTarget
*>* IndexTargets
,
1535 indexRecords
* MetaIndexParser
) :
1536 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1537 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1538 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1543 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1544 // ---------------------------------------------------------------------
1545 // FIXME: this can go away once the InRelease file is used widely
1546 string
pkgAcqMetaClearSig::Custom600Headers()
1548 string Final
= _config
->FindDir("Dir::State::lists");
1549 Final
+= URItoFileName(RealURI
);
1552 if (stat(Final
.c_str(),&Buf
) != 0)
1553 return "\nIndex-File: true\nFail-Ignore: true\n";
1555 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1558 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1560 if (AuthPass
== false)
1562 new pkgAcqMetaSig(Owner
,
1563 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1564 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1565 IndexTargets
, MetaIndexParser
);
1566 if (Cnf
->LocalOnly
== true ||
1567 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1571 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1574 // AcqArchive::AcqArchive - Constructor /*{{{*/
1575 // ---------------------------------------------------------------------
1576 /* This just sets up the initial fetch environment and queues the first
1578 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1579 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1580 string
&StoreFilename
) :
1581 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1582 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1585 Retries
= _config
->FindI("Acquire::Retries",0);
1587 if (Version
.Arch() == 0)
1589 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1590 "This might mean you need to manually fix this package. "
1591 "(due to missing arch)"),
1592 Version
.ParentPkg().Name());
1596 /* We need to find a filename to determine the extension. We make the
1597 assumption here that all the available sources for this version share
1598 the same extension.. */
1599 // Skip not source sources, they do not have file fields.
1600 for (; Vf
.end() == false; Vf
++)
1602 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1607 // Does not really matter here.. we are going to fail out below
1608 if (Vf
.end() != true)
1610 // If this fails to get a file name we will bomb out below.
1611 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1612 if (_error
->PendingError() == true)
1615 // Generate the final file name as: package_version_arch.foo
1616 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1617 QuoteString(Version
.VerStr(),"_:") + '_' +
1618 QuoteString(Version
.Arch(),"_:.") +
1619 "." + flExtension(Parse
.FileName());
1622 // check if we have one trusted source for the package. if so, switch
1623 // to "TrustedOnly" mode
1624 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; i
++)
1626 pkgIndexFile
*Index
;
1627 if (Sources
->FindIndex(i
.File(),Index
) == false)
1629 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1631 std::cerr
<< "Checking index: " << Index
->Describe()
1632 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1634 if (Index
->IsTrusted()) {
1640 // "allow-unauthenticated" restores apts old fetching behaviour
1641 // that means that e.g. unauthenticated file:// uris are higher
1642 // priority than authenticated http:// uris
1643 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1647 if (QueueNext() == false && _error
->PendingError() == false)
1648 _error
->Error(_("I wasn't able to locate file for the %s package. "
1649 "This might mean you need to manually fix this package."),
1650 Version
.ParentPkg().Name());
1653 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1654 // ---------------------------------------------------------------------
1655 /* This queues the next available file version for download. It checks if
1656 the archive is already available in the cache and stashs the MD5 for
1658 bool pkgAcqArchive::QueueNext()
1660 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1661 for (; Vf
.end() == false; Vf
++)
1663 // Ignore not source sources
1664 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1667 // Try to cross match against the source list
1668 pkgIndexFile
*Index
;
1669 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1672 // only try to get a trusted package from another source if that source
1674 if(Trusted
&& !Index
->IsTrusted())
1677 // Grab the text package record
1678 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1679 if (_error
->PendingError() == true)
1682 string PkgFile
= Parse
.FileName();
1683 if (ForceHash
.empty() == false)
1685 if(stringcasecmp(ForceHash
, "sha256") == 0)
1686 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1687 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1688 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1690 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1695 if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1696 ExpectedHash
= HashString("SHA256", Hash
);
1697 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1698 ExpectedHash
= HashString("SHA1", Hash
);
1700 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1702 if (PkgFile
.empty() == true)
1703 return _error
->Error(_("The package index files are corrupted. No Filename: "
1704 "field for package %s."),
1705 Version
.ParentPkg().Name());
1707 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1708 Desc
.Description
= Index
->ArchiveInfo(Version
);
1710 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1712 // See if we already have the file. (Legacy filenames)
1713 FileSize
= Version
->Size
;
1714 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1716 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1718 // Make sure the size matches
1719 if ((unsigned)Buf
.st_size
== Version
->Size
)
1724 StoreFilename
= DestFile
= FinalFile
;
1728 /* Hmm, we have a file and its size does not match, this means it is
1729 an old style mismatched arch */
1730 unlink(FinalFile
.c_str());
1733 // Check it again using the new style output filenames
1734 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1735 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1737 // Make sure the size matches
1738 if ((unsigned)Buf
.st_size
== Version
->Size
)
1743 StoreFilename
= DestFile
= FinalFile
;
1747 /* Hmm, we have a file and its size does not match, this shouldnt
1749 unlink(FinalFile
.c_str());
1752 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1754 // Check the destination file
1755 if (stat(DestFile
.c_str(),&Buf
) == 0)
1757 // Hmm, the partial file is too big, erase it
1758 if ((unsigned)Buf
.st_size
> Version
->Size
)
1759 unlink(DestFile
.c_str());
1761 PartialSize
= Buf
.st_size
;
1766 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1767 Desc
.Description
= Index
->ArchiveInfo(Version
);
1769 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1778 // AcqArchive::Done - Finished fetching /*{{{*/
1779 // ---------------------------------------------------------------------
1781 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string CalcHash
,
1782 pkgAcquire::MethodConfig
*Cfg
)
1784 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1787 if (Size
!= Version
->Size
)
1790 ErrorText
= _("Size mismatch");
1795 if(ExpectedHash
.toStr() != CalcHash
)
1798 ErrorText
= _("Hash Sum mismatch");
1799 if(FileExists(DestFile
))
1800 Rename(DestFile
,DestFile
+ ".FAILED");
1804 // Grab the output filename
1805 string FileName
= LookupTag(Message
,"Filename");
1806 if (FileName
.empty() == true)
1809 ErrorText
= "Method gave a blank filename";
1815 // Reference filename
1816 if (FileName
!= DestFile
)
1818 StoreFilename
= DestFile
= FileName
;
1823 // Done, move it into position
1824 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1825 FinalFile
+= flNotDir(StoreFilename
);
1826 Rename(DestFile
,FinalFile
);
1828 StoreFilename
= DestFile
= FinalFile
;
1832 // AcqArchive::Failed - Failure handler /*{{{*/
1833 // ---------------------------------------------------------------------
1834 /* Here we try other sources */
1835 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1837 ErrorText
= LookupTag(Message
,"Message");
1839 /* We don't really want to retry on failed media swaps, this prevents
1840 that. An interesting observation is that permanent failures are not
1842 if (Cnf
->Removable
== true &&
1843 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1845 // Vf = Version.FileList();
1846 while (Vf
.end() == false) Vf
++;
1847 StoreFilename
= string();
1848 Item::Failed(Message
,Cnf
);
1852 if (QueueNext() == false)
1854 // This is the retry counter
1856 Cnf
->LocalOnly
== false &&
1857 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1860 Vf
= Version
.FileList();
1861 if (QueueNext() == true)
1865 StoreFilename
= string();
1866 Item::Failed(Message
,Cnf
);
1870 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1871 // ---------------------------------------------------------------------
1872 bool pkgAcqArchive::IsTrusted()
1877 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1878 // ---------------------------------------------------------------------
1880 void pkgAcqArchive::Finished()
1882 if (Status
== pkgAcquire::Item::StatDone
&&
1885 StoreFilename
= string();
1888 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1889 // ---------------------------------------------------------------------
1890 /* The file is added to the queue */
1891 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1892 unsigned long Size
,string Dsc
,string ShortDesc
,
1893 const string
&DestDir
, const string
&DestFilename
,
1895 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
1897 Retries
= _config
->FindI("Acquire::Retries",0);
1899 if(!DestFilename
.empty())
1900 DestFile
= DestFilename
;
1901 else if(!DestDir
.empty())
1902 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1904 DestFile
= flNotDir(URI
);
1908 Desc
.Description
= Dsc
;
1911 // Set the short description to the archive component
1912 Desc
.ShortDesc
= ShortDesc
;
1914 // Get the transfer sizes
1917 if (stat(DestFile
.c_str(),&Buf
) == 0)
1919 // Hmm, the partial file is too big, erase it
1920 if ((unsigned)Buf
.st_size
> Size
)
1921 unlink(DestFile
.c_str());
1923 PartialSize
= Buf
.st_size
;
1929 // AcqFile::Done - Item downloaded OK /*{{{*/
1930 // ---------------------------------------------------------------------
1932 void pkgAcqFile::Done(string Message
,unsigned long Size
,string CalcHash
,
1933 pkgAcquire::MethodConfig
*Cnf
)
1935 Item::Done(Message
,Size
,CalcHash
,Cnf
);
1938 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
1941 ErrorText
= _("Hash Sum mismatch");
1942 Rename(DestFile
,DestFile
+ ".FAILED");
1946 string FileName
= LookupTag(Message
,"Filename");
1947 if (FileName
.empty() == true)
1950 ErrorText
= "Method gave a blank filename";
1956 // The files timestamp matches
1957 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1960 // We have to copy it into place
1961 if (FileName
!= DestFile
)
1964 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
1965 Cnf
->Removable
== true)
1967 Desc
.URI
= "copy:" + FileName
;
1972 // Erase the file if it is a symlink so we can overwrite it
1974 if (lstat(DestFile
.c_str(),&St
) == 0)
1976 if (S_ISLNK(St
.st_mode
) != 0)
1977 unlink(DestFile
.c_str());
1981 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
1983 ErrorText
= "Link to " + DestFile
+ " failure ";
1990 // AcqFile::Failed - Failure handler /*{{{*/
1991 // ---------------------------------------------------------------------
1992 /* Here we try other sources */
1993 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1995 ErrorText
= LookupTag(Message
,"Message");
1997 // This is the retry counter
1999 Cnf
->LocalOnly
== false &&
2000 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2007 Item::Failed(Message
,Cnf
);
2010 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2011 // ---------------------------------------------------------------------
2012 /* The only header we use is the last-modified header. */
2013 string
pkgAcqFile::Custom600Headers()
2016 return "\nIndex-File: true";
2020 bool IndexTarget::IsOptional() const {
2021 if (strncmp(ShortDesc
.c_str(), "Translation", 11) != 0)
2025 bool IndexTarget::IsSubIndex() const {
2026 if (ShortDesc
!= "TranslationIndex")