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 /* Downloaded invalid transindex => Error (LP: #346386) (Closes: #627642) */
275 indexRecords SubIndexParser
;
276 if (FileExists(DestFile
) == true && !SubIndexParser
.Load(DestFile
)) {
278 ErrorText
= SubIndexParser
.ErrorText
;
282 // sucess in downloading the index
285 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
<< std::endl
;
286 Rename(DestFile
,FinalFile
);
287 chmod(FinalFile
.c_str(),0644);
288 DestFile
= FinalFile
;
290 if(ParseIndex(DestFile
) == false)
291 return Failed("", NULL
);
299 bool pkgAcqSubIndex::ParseIndex(string
const &IndexFile
) /*{{{*/
301 indexRecords SubIndexParser
;
302 if (FileExists(IndexFile
) == false || SubIndexParser
.Load(IndexFile
) == false)
305 std::vector
<std::string
> lang
= APT::Configuration::getLanguages(true);
306 for (std::vector
<std::string
>::const_iterator l
= lang
.begin();
307 l
!= lang
.end(); ++l
)
312 string file
= "Translation-" + *l
;
313 indexRecords::checkSum
const *Record
= SubIndexParser
.Lookup(file
);
317 // FIXME: the Index file provided by debian currently only includes bz2 records
318 Record
= SubIndexParser
.Lookup(file
+ ".bz2");
324 expected
= Record
->Hash
;
325 if (expected
.empty() == true)
330 target
.Description
= Desc
.Description
.erase(Desc
.Description
.rfind(' ')+1).append(file
);
331 target
.MetaKey
= file
;
332 target
.ShortDesc
= file
;
333 target
.URI
= Desc
.URI
.substr(0, Desc
.URI
.rfind('/')+1).append(file
);
334 new pkgAcqIndexTrans(Owner
, &target
, expected
, &SubIndexParser
);
339 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
340 // ---------------------------------------------------------------------
341 /* Get the DiffIndex file first and see if there are patches availabe
342 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
343 * patches. If anything goes wrong in that process, it will fall back to
344 * the original packages file
346 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
347 string URI
,string URIDesc
,string ShortDesc
,
348 HashString ExpectedHash
)
349 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
353 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
355 Desc
.Description
= URIDesc
+ "/DiffIndex";
357 Desc
.ShortDesc
= ShortDesc
;
358 Desc
.URI
= URI
+ ".diff/Index";
360 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
361 DestFile
+= URItoFileName(URI
) + string(".DiffIndex");
364 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
366 // look for the current package file
367 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
368 CurrentPackagesFile
+= URItoFileName(RealURI
);
370 // FIXME: this file:/ check is a hack to prevent fetching
371 // from local sources. this is really silly, and
372 // should be fixed cleanly as soon as possible
373 if(!FileExists(CurrentPackagesFile
) ||
374 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
376 // we don't have a pkg file or we don't want to queue
378 std::clog
<< "No index file, local or canceld by user" << std::endl
;
384 std::clog
<< "pkgAcqIndexDiffs::pkgAcqIndexDiffs(): "
385 << CurrentPackagesFile
<< std::endl
;
391 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
392 // ---------------------------------------------------------------------
393 /* The only header we use is the last-modified header. */
394 string
pkgAcqDiffIndex::Custom600Headers()
396 string Final
= _config
->FindDir("Dir::State::lists");
397 Final
+= URItoFileName(RealURI
) + string(".IndexDiff");
400 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
403 if (stat(Final
.c_str(),&Buf
) != 0)
404 return "\nIndex-File: true";
406 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
409 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
412 std::clog
<< "pkgAcqIndexDiffs::ParseIndexDiff() " << IndexDiffFile
417 vector
<DiffInfo
> available_patches
;
419 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
421 if (_error
->PendingError() == true)
424 if(TF
.Step(Tags
) == true)
430 string
const tmp
= Tags
.FindS("SHA1-Current");
431 std::stringstream
ss(tmp
);
432 ss
>> ServerSha1
>> size
;
433 unsigned long const ServerSize
= atol(size
.c_str());
435 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
437 SHA1
.AddFD(fd
.Fd(), fd
.Size());
438 string
const local_sha1
= SHA1
.Result();
440 if(local_sha1
== ServerSha1
)
442 // we have the same sha1 as the server
444 std::clog
<< "Package file is up-to-date" << std::endl
;
445 // set found to true, this will queue a pkgAcqIndexDiffs with
446 // a empty availabe_patches
452 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
454 // check the historie and see what patches we need
455 string
const history
= Tags
.FindS("SHA1-History");
456 std::stringstream
hist(history
);
457 while(hist
>> d
.sha1
>> size
>> d
.file
)
459 // read until the first match is found
460 // from that point on, we probably need all diffs
461 if(d
.sha1
== local_sha1
)
463 else if (found
== false)
467 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
468 available_patches
.push_back(d
);
471 if (available_patches
.empty() == false)
473 // patching with too many files is rather slow compared to a fast download
474 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
475 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
478 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
479 << ") so fallback to complete download" << std::endl
;
483 // see if the patches are too big
484 found
= false; // it was true and it will be true again at the end
485 d
= *available_patches
.begin();
486 string
const firstPatch
= d
.file
;
487 unsigned long patchesSize
= 0;
488 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
489 while(patches
>> d
.sha1
>> size
>> d
.file
)
491 if (firstPatch
== d
.file
)
493 else if (found
== false)
496 patchesSize
+= atol(size
.c_str());
498 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
499 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
502 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
503 << ") so fallback to complete download" << std::endl
;
509 // we have something, queue the next diff
513 string::size_type
const last_space
= Description
.rfind(" ");
514 if(last_space
!= string::npos
)
515 Description
.erase(last_space
, Description
.size()-last_space
);
516 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
517 ExpectedHash
, ServerSha1
, available_patches
);
525 // Nothing found, report and return false
526 // Failing here is ok, if we return false later, the full
527 // IndexFile is queued
529 std::clog
<< "Can't find a patch in the index file" << std::endl
;
533 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
536 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< std::endl
537 << "Falling back to normal index file aquire" << std::endl
;
539 new pkgAcqIndex(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
547 void pkgAcqDiffIndex::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
548 pkgAcquire::MethodConfig
*Cnf
)
551 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
553 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
556 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
558 // sucess in downloading the index
560 FinalFile
+= string(".IndexDiff");
562 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
564 Rename(DestFile
,FinalFile
);
565 chmod(FinalFile
.c_str(),0644);
566 DestFile
= FinalFile
;
568 if(!ParseDiffIndex(DestFile
))
569 return Failed("", NULL
);
577 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
578 // ---------------------------------------------------------------------
579 /* The package diff is added to the queue. one object is constructed
580 * for each diff and the index
582 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
583 string URI
,string URIDesc
,string ShortDesc
,
584 HashString ExpectedHash
,
586 vector
<DiffInfo
> diffs
)
587 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
),
588 available_patches(diffs
), ServerSha1(ServerSha1
)
591 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
592 DestFile
+= URItoFileName(URI
);
594 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
596 Description
= URIDesc
;
598 Desc
.ShortDesc
= ShortDesc
;
600 if(available_patches
.size() == 0)
602 // we are done (yeah!)
608 State
= StateFetchDiff
;
613 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
616 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< std::endl
617 << "Falling back to normal index file aquire" << std::endl
;
618 new pkgAcqIndex(Owner
, RealURI
, Description
,Desc
.ShortDesc
,
623 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
624 void pkgAcqIndexDiffs::Finish(bool allDone
)
626 // we restore the original name, this is required, otherwise
627 // the file will be cleaned
630 DestFile
= _config
->FindDir("Dir::State::lists");
631 DestFile
+= URItoFileName(RealURI
);
633 if(!ExpectedHash
.empty() && !ExpectedHash
.VerifyFile(DestFile
))
635 Status
= StatAuthError
;
636 ErrorText
= _("MD5Sum mismatch");
637 Rename(DestFile
,DestFile
+ ".FAILED");
642 // this is for the "real" finish
647 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
652 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
659 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
662 // calc sha1 of the just patched file
663 string FinalFile
= _config
->FindDir("Dir::State::lists");
664 FinalFile
+= URItoFileName(RealURI
);
666 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
668 SHA1
.AddFD(fd
.Fd(), fd
.Size());
669 string local_sha1
= string(SHA1
.Result());
671 std::clog
<< "QueueNextDiff: "
672 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
674 // final file reached before all patches are applied
675 if(local_sha1
== ServerSha1
)
681 // remove all patches until the next matching patch is found
682 // this requires the Index file to be ordered
683 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
684 available_patches
.empty() == false &&
685 I
!= available_patches
.end() &&
686 I
->sha1
!= local_sha1
;
689 available_patches
.erase(I
);
692 // error checking and falling back if no patch was found
693 if(available_patches
.empty() == true)
699 // queue the right diff
700 Desc
.URI
= string(RealURI
) + ".diff/" + available_patches
[0].file
+ ".gz";
701 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
702 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
703 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
706 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
713 void pkgAcqIndexDiffs::Done(string Message
,unsigned long Size
,string Md5Hash
, /*{{{*/
714 pkgAcquire::MethodConfig
*Cnf
)
717 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
719 Item::Done(Message
,Size
,Md5Hash
,Cnf
);
722 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
724 // sucess in downloading a diff, enter ApplyDiff state
725 if(State
== StateFetchDiff
)
728 // rred excepts the patch as $FinalFile.ed
729 Rename(DestFile
,FinalFile
+".ed");
732 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
734 State
= StateApplyDiff
;
736 Desc
.URI
= "rred:" + FinalFile
;
743 // success in download/apply a diff, queue next (if needed)
744 if(State
== StateApplyDiff
)
746 // remove the just applied patch
747 available_patches
.erase(available_patches
.begin());
752 std::clog
<< "Moving patched file in place: " << std::endl
753 << DestFile
<< " -> " << FinalFile
<< std::endl
;
755 Rename(DestFile
,FinalFile
);
756 chmod(FinalFile
.c_str(),0644);
758 // see if there is more to download
759 if(available_patches
.empty() == false) {
760 new pkgAcqIndexDiffs(Owner
, RealURI
, Description
, Desc
.ShortDesc
,
761 ExpectedHash
, ServerSha1
, available_patches
);
768 // AcqIndex::AcqIndex - Constructor /*{{{*/
769 // ---------------------------------------------------------------------
770 /* The package file is added to the queue and a second class is
771 instantiated to fetch the revision file */
772 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
773 string URI
,string URIDesc
,string ShortDesc
,
774 HashString ExpectedHash
, string comprExt
)
775 : Item(Owner
), RealURI(URI
), ExpectedHash(ExpectedHash
)
777 if(comprExt
.empty() == true)
779 // autoselect the compression method
780 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
781 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
782 comprExt
.append(*t
).append(" ");
783 if (comprExt
.empty() == false)
784 comprExt
.erase(comprExt
.end()-1);
786 CompressionExtension
= comprExt
;
788 Init(URI
, URIDesc
, ShortDesc
);
790 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
, IndexTarget
const *Target
,
791 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
792 : Item(Owner
), RealURI(Target
->URI
), ExpectedHash(ExpectedHash
)
794 // autoselect the compression method
795 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
796 CompressionExtension
= "";
797 if (ExpectedHash
.empty() == false)
799 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
800 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
801 CompressionExtension
.append(*t
).append(" ");
805 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
806 CompressionExtension
.append(*t
).append(" ");
808 if (CompressionExtension
.empty() == false)
809 CompressionExtension
.erase(CompressionExtension
.end()-1);
811 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
814 // AcqIndex::Init - defered Constructor /*{{{*/
815 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
816 Decompression
= false;
819 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
820 DestFile
+= URItoFileName(URI
);
822 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
823 if (comprExt
== "uncompressed")
826 Desc
.URI
= URI
+ '.' + comprExt
;
828 Desc
.Description
= URIDesc
;
830 Desc
.ShortDesc
= ShortDesc
;
835 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
836 // ---------------------------------------------------------------------
837 /* The only header we use is the last-modified header. */
838 string
pkgAcqIndex::Custom600Headers()
840 string Final
= _config
->FindDir("Dir::State::lists");
841 Final
+= URItoFileName(RealURI
);
842 if (_config
->FindB("Acquire::GzipIndexes",false))
845 string msg
= "\nIndex-File: true";
846 // FIXME: this really should use "IndexTarget::IsOptional()" but that
847 // seems to be difficult without breaking ABI
848 if (ShortDesc().find("Translation") != 0)
849 msg
+= "\nFail-Ignore: true";
851 if (stat(Final
.c_str(),&Buf
) == 0)
852 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
857 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
859 size_t const nextExt
= CompressionExtension
.find(' ');
860 if (nextExt
!= std::string::npos
)
862 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
863 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
867 // on decompression failure, remove bad versions in partial/
868 if (Decompression
&& Erase
) {
869 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
870 s
.append(URItoFileName(RealURI
));
874 Item::Failed(Message
,Cnf
);
877 // AcqIndex::Done - Finished a fetch /*{{{*/
878 // ---------------------------------------------------------------------
879 /* This goes through a number of states.. On the initial fetch the
880 method could possibly return an alternate filename which points
881 to the uncompressed version of the file. If this is so the file
882 is copied into the partial directory. In all other cases the file
883 is decompressed with a gzip uri. */
884 void pkgAcqIndex::Done(string Message
,unsigned long Size
,string Hash
,
885 pkgAcquire::MethodConfig
*Cfg
)
887 Item::Done(Message
,Size
,Hash
,Cfg
);
889 if (Decompression
== true)
891 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
893 std::cerr
<< std::endl
<< RealURI
<< ": Computed Hash: " << Hash
;
894 std::cerr
<< " Expected Hash: " << ExpectedHash
.toStr() << std::endl
;
897 if (!ExpectedHash
.empty() && ExpectedHash
.toStr() != Hash
)
899 Status
= StatAuthError
;
900 ErrorText
= _("Hash Sum mismatch");
901 Rename(DestFile
,DestFile
+ ".FAILED");
902 ReportMirrorFailure("HashChecksumFailure");
906 /* Verify the index file for correctness (all indexes must
907 * have a Package field) (LP: #346386) (Closes: #627642) */
909 FileFd
fd(DestFile
, FileFd::ReadOnly
);
913 // Only test for correctness if the file is not empty (empty is ok)
915 if (_error
->PendingError() || !tag
.Step(sec
)) {
917 _error
->DumpErrors();
918 Rename(DestFile
,DestFile
+ ".FAILED");
920 } else if (!sec
.Exists("Package")) {
922 ErrorText
= ("Encountered a section with no Package: header");
923 Rename(DestFile
,DestFile
+ ".FAILED");
929 // Done, move it into position
930 string FinalFile
= _config
->FindDir("Dir::State::lists");
931 FinalFile
+= URItoFileName(RealURI
);
932 Rename(DestFile
,FinalFile
);
933 chmod(FinalFile
.c_str(),0644);
935 /* We restore the original name to DestFile so that the clean operation
937 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
938 DestFile
+= URItoFileName(RealURI
);
940 // Remove the compressed version.
942 unlink(DestFile
.c_str());
949 // Handle the unzipd case
950 string FileName
= LookupTag(Message
,"Alt-Filename");
951 if (FileName
.empty() == false)
953 // The files timestamp matches
954 if (StringToBool(LookupTag(Message
,"Alt-IMS-Hit"),false) == true)
956 Decompression
= true;
958 DestFile
+= ".decomp";
959 Desc
.URI
= "copy:" + FileName
;
965 FileName
= LookupTag(Message
,"Filename");
966 if (FileName
.empty() == true)
969 ErrorText
= "Method gave a blank filename";
972 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
974 // The files timestamp matches
975 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true) {
976 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
977 // Update DestFile for .gz suffix so that the clean operation keeps it
982 if (FileName
== DestFile
)
989 // If we enable compressed indexes and already have gzip, keep it
990 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
) {
991 string FinalFile
= _config
->FindDir("Dir::State::lists");
992 FinalFile
+= URItoFileName(RealURI
) + ".gz";
993 Rename(DestFile
,FinalFile
);
994 chmod(FinalFile
.c_str(),0644);
996 // Update DestFile for .gz suffix so that the clean operation keeps it
997 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
998 DestFile
+= URItoFileName(RealURI
) + ".gz";
1002 // get the binary name for your used compression type
1003 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1004 if(decompProg
.empty() == false);
1005 else if(compExt
== "uncompressed")
1006 decompProg
= "copy";
1008 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1012 Decompression
= true;
1013 DestFile
+= ".decomp";
1014 Desc
.URI
= decompProg
+ ":" + FileName
;
1016 Mode
= decompProg
.c_str();
1019 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1020 // ---------------------------------------------------------------------
1021 /* The Translation file is added to the queue */
1022 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1023 string URI
,string URIDesc
,string ShortDesc
)
1024 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashString(), "")
1027 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
, IndexTarget
const *Target
,
1028 HashString
const &ExpectedHash
, indexRecords
const *MetaIndexParser
)
1029 : pkgAcqIndex(Owner
, Target
, ExpectedHash
, MetaIndexParser
)
1033 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1034 // ---------------------------------------------------------------------
1035 string
pkgAcqIndexTrans::Custom600Headers()
1037 string Final
= _config
->FindDir("Dir::State::lists");
1038 Final
+= URItoFileName(RealURI
);
1041 if (stat(Final
.c_str(),&Buf
) != 0)
1042 return "\nFail-Ignore: true\nIndex-File: true";
1043 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1046 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1047 // ---------------------------------------------------------------------
1049 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1051 size_t const nextExt
= CompressionExtension
.find(' ');
1052 if (nextExt
!= std::string::npos
)
1054 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1055 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1060 if (Cnf
->LocalOnly
== true ||
1061 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1070 Item::Failed(Message
,Cnf
);
1073 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1074 string URI
,string URIDesc
,string ShortDesc
,
1075 string MetaIndexURI
, string MetaIndexURIDesc
,
1076 string MetaIndexShortDesc
,
1077 const vector
<IndexTarget
*>* IndexTargets
,
1078 indexRecords
* MetaIndexParser
) :
1079 Item(Owner
), RealURI(URI
), MetaIndexURI(MetaIndexURI
),
1080 MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1081 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
)
1083 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1084 DestFile
+= URItoFileName(URI
);
1086 // remove any partial downloaded sig-file in partial/.
1087 // it may confuse proxies and is too small to warrant a
1088 // partial download anyway
1089 unlink(DestFile
.c_str());
1092 Desc
.Description
= URIDesc
;
1094 Desc
.ShortDesc
= ShortDesc
;
1097 string Final
= _config
->FindDir("Dir::State::lists");
1098 Final
+= URItoFileName(RealURI
);
1100 if (stat(Final
.c_str(),&Buf
) == 0)
1102 // File was already in place. It needs to be re-downloaded/verified
1103 // because Release might have changed, we do give it a differnt
1104 // name than DestFile because otherwise the http method will
1105 // send If-Range requests and there are too many broken servers
1106 // out there that do not understand them
1107 LastGoodSig
= DestFile
+".reverify";
1108 Rename(Final
,LastGoodSig
);
1114 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1115 // ---------------------------------------------------------------------
1116 /* The only header we use is the last-modified header. */
1117 string
pkgAcqMetaSig::Custom600Headers()
1120 if (stat(LastGoodSig
.c_str(),&Buf
) != 0)
1121 return "\nIndex-File: true";
1123 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1126 void pkgAcqMetaSig::Done(string Message
,unsigned long Size
,string MD5
,
1127 pkgAcquire::MethodConfig
*Cfg
)
1129 Item::Done(Message
,Size
,MD5
,Cfg
);
1131 string FileName
= LookupTag(Message
,"Filename");
1132 if (FileName
.empty() == true)
1135 ErrorText
= "Method gave a blank filename";
1139 if (FileName
!= DestFile
)
1141 // We have to copy it into place
1143 Desc
.URI
= "copy:" + FileName
;
1150 // put the last known good file back on i-m-s hit (it will
1151 // be re-verified again)
1152 // Else do nothing, we have the new file in DestFile then
1153 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1154 Rename(LastGoodSig
, DestFile
);
1156 // queue a pkgAcqMetaIndex to be verified against the sig we just retrieved
1157 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
,
1158 MetaIndexShortDesc
, DestFile
, IndexTargets
,
1163 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1165 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1167 // if we get a network error we fail gracefully
1168 if(Status
== StatTransientNetworkError
)
1170 Item::Failed(Message
,Cnf
);
1171 // move the sigfile back on transient network failures
1172 if(FileExists(LastGoodSig
))
1173 Rename(LastGoodSig
,Final
);
1175 // set the status back to , Item::Failed likes to reset it
1176 Status
= pkgAcquire::Item::StatTransientNetworkError
;
1180 // Delete any existing sigfile when the acquire failed
1181 unlink(Final
.c_str());
1183 // queue a pkgAcqMetaIndex with no sigfile
1184 new pkgAcqMetaIndex(Owner
, MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1185 "", IndexTargets
, MetaIndexParser
);
1187 if (Cnf
->LocalOnly
== true ||
1188 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1197 Item::Failed(Message
,Cnf
);
1200 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1201 string URI
,string URIDesc
,string ShortDesc
,
1203 const vector
<struct IndexTarget
*>* IndexTargets
,
1204 indexRecords
* MetaIndexParser
) :
1205 Item(Owner
), RealURI(URI
), SigFile(SigFile
), IndexTargets(IndexTargets
),
1206 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false)
1208 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1209 DestFile
+= URItoFileName(URI
);
1212 Desc
.Description
= URIDesc
;
1214 Desc
.ShortDesc
= ShortDesc
;
1220 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1221 // ---------------------------------------------------------------------
1222 /* The only header we use is the last-modified header. */
1223 string
pkgAcqMetaIndex::Custom600Headers()
1225 string Final
= _config
->FindDir("Dir::State::lists");
1226 Final
+= URItoFileName(RealURI
);
1229 if (stat(Final
.c_str(),&Buf
) != 0)
1230 return "\nIndex-File: true";
1232 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1235 void pkgAcqMetaIndex::Done(string Message
,unsigned long Size
,string Hash
, /*{{{*/
1236 pkgAcquire::MethodConfig
*Cfg
)
1238 Item::Done(Message
,Size
,Hash
,Cfg
);
1240 // MetaIndexes are done in two passes: one to download the
1241 // metaindex with an appropriate method, and a second to verify it
1242 // with the gpgv method
1244 if (AuthPass
== true)
1248 // all cool, move Release file into place
1253 RetrievalDone(Message
);
1255 // Still more retrieving to do
1260 // There was no signature file, so we are finished. Download
1261 // the indexes and do only hashsum verification
1262 MetaIndexParser
->Load(DestFile
);
1267 // There was a signature file, so pass it to gpgv for
1270 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1271 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1272 << SigFile
<< "," << DestFile
<< ")\n";
1274 Desc
.URI
= "gpgv:" + SigFile
;
1281 if (Complete
== true)
1283 string FinalFile
= _config
->FindDir("Dir::State::lists");
1284 FinalFile
+= URItoFileName(RealURI
);
1285 if (SigFile
== DestFile
)
1286 SigFile
= FinalFile
;
1287 Rename(DestFile
,FinalFile
);
1288 chmod(FinalFile
.c_str(),0644);
1289 DestFile
= FinalFile
;
1293 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1295 // We have just finished downloading a Release file (it is not
1298 string FileName
= LookupTag(Message
,"Filename");
1299 if (FileName
.empty() == true)
1302 ErrorText
= "Method gave a blank filename";
1306 if (FileName
!= DestFile
)
1309 Desc
.URI
= "copy:" + FileName
;
1314 // make sure to verify against the right file on I-M-S hit
1315 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1318 string FinalFile
= _config
->FindDir("Dir::State::lists");
1319 FinalFile
+= URItoFileName(RealURI
);
1320 if (SigFile
== DestFile
)
1321 SigFile
= FinalFile
;
1322 DestFile
= FinalFile
;
1327 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1329 // At this point, the gpgv method has succeeded, so there is a
1330 // valid signature from a key in the trusted keyring. We
1331 // perform additional verification of its contents, and use them
1332 // to verify the indexes we are about to download
1334 if (!MetaIndexParser
->Load(DestFile
))
1336 Status
= StatAuthError
;
1337 ErrorText
= MetaIndexParser
->ErrorText
;
1341 if (!VerifyVendor(Message
))
1346 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1347 std::cerr
<< "Signature verification succeeded: "
1348 << DestFile
<< std::endl
;
1350 // Download further indexes with verification
1353 // is it a clearsigned MetaIndex file?
1354 if (DestFile
== SigFile
)
1357 // Done, move signature file into position
1358 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1359 URItoFileName(RealURI
) + ".gpg";
1360 Rename(SigFile
,VerifiedSigFile
);
1361 chmod(VerifiedSigFile
.c_str(),0644);
1364 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1367 /* Reject invalid, existing Release files (LP: #346386) (Closes: #627642)
1368 * FIXME: Disabled; it breaks unsigned repositories without hashes */
1369 if (!verify
&& FileExists(DestFile
) && !MetaIndexParser
->Load(DestFile
))
1372 ErrorText
= MetaIndexParser
->ErrorText
;
1376 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1377 Target
!= IndexTargets
->end();
1380 HashString ExpectedIndexHash
;
1383 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1386 if ((*Target
)->IsOptional() == false)
1388 Status
= StatAuthError
;
1389 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1395 ExpectedIndexHash
= Record
->Hash
;
1396 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1398 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
;
1399 std::cerr
<< "Expected Hash: " << ExpectedIndexHash
.toStr() << std::endl
;
1400 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1402 if (ExpectedIndexHash
.empty() == true && (*Target
)->IsOptional() == false)
1404 Status
= StatAuthError
;
1405 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1411 if ((*Target
)->IsOptional() == true)
1413 if ((*Target
)->IsSubIndex() == true)
1414 new pkgAcqSubIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1415 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1417 new pkgAcqIndexTrans(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1421 /* Queue Packages file (either diff or full packages files, depending
1422 on the users option) - we also check if the PDiff Index file is listed
1423 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1424 instead, but passing the required info to it is to much hassle */
1425 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1426 MetaIndexParser
->Exists(string((*Target
)->MetaKey
).append(".diff/Index")) == true))
1427 new pkgAcqDiffIndex(Owner
, (*Target
)->URI
, (*Target
)->Description
,
1428 (*Target
)->ShortDesc
, ExpectedIndexHash
);
1430 new pkgAcqIndex(Owner
, *Target
, ExpectedIndexHash
, MetaIndexParser
);
1434 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1436 string::size_type pos
;
1438 // check for missing sigs (that where not fatal because otherwise we had
1441 string msg
= _("There is no public key available for the "
1442 "following key IDs:\n");
1443 pos
= Message
.find("NO_PUBKEY ");
1444 if (pos
!= std::string::npos
)
1446 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1447 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1448 missingkeys
+= (Fingerprint
);
1450 if(!missingkeys
.empty())
1451 _error
->Warning("%s", string(msg
+missingkeys
).c_str());
1453 string Transformed
= MetaIndexParser
->GetExpectedDist();
1455 if (Transformed
== "../project/experimental")
1457 Transformed
= "experimental";
1460 pos
= Transformed
.rfind('/');
1461 if (pos
!= string::npos
)
1463 Transformed
= Transformed
.substr(0, pos
);
1466 if (Transformed
== ".")
1471 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1472 MetaIndexParser
->GetValidUntil() > 0) {
1473 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1474 if (invalid_since
> 0)
1475 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1476 // the time since then the file is invalid - formated in the same way as in
1477 // the download progress display (e.g. 7d 3h 42min 1s)
1478 return _error
->Error(
1479 _("Release file for %s is expired (invalid since %s). "
1480 "Updates for this repository will not be applied."),
1481 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1484 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1486 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1487 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1488 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1491 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1493 // This might become fatal one day
1494 // Status = StatAuthError;
1495 // ErrorText = "Conflicting distribution; expected "
1496 // + MetaIndexParser->GetExpectedDist() + " but got "
1497 // + MetaIndexParser->GetDist();
1499 if (!Transformed
.empty())
1501 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1502 Desc
.Description
.c_str(),
1503 Transformed
.c_str(),
1504 MetaIndexParser
->GetDist().c_str());
1511 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1512 // ---------------------------------------------------------------------
1514 void pkgAcqMetaIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1516 if (AuthPass
== true)
1518 // gpgv method failed, if we have a good signature
1519 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists");
1520 if (DestFile
== SigFile
)
1521 LastGoodSigFile
.append(URItoFileName(RealURI
));
1523 LastGoodSigFile
.append("partial/").append(URItoFileName(RealURI
)).append(".gpg.reverify");
1525 if(FileExists(LastGoodSigFile
))
1527 if (DestFile
!= SigFile
)
1529 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1530 URItoFileName(RealURI
) + ".gpg";
1531 Rename(LastGoodSigFile
,VerifiedSigFile
);
1533 Status
= StatTransientNetworkError
;
1534 _error
->Warning(_("A error occurred during the signature "
1535 "verification. The repository is not updated "
1536 "and the previous index files will be used. "
1537 "GPG error: %s: %s\n"),
1538 Desc
.Description
.c_str(),
1539 LookupTag(Message
,"Message").c_str());
1540 RunScripts("APT::Update::Auth-Failure");
1542 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1543 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1544 _error
->Error(_("GPG error: %s: %s"),
1545 Desc
.Description
.c_str(),
1546 LookupTag(Message
,"Message").c_str());
1549 _error
->Warning(_("GPG error: %s: %s"),
1550 Desc
.Description
.c_str(),
1551 LookupTag(Message
,"Message").c_str());
1553 // gpgv method failed
1554 ReportMirrorFailure("GPGFailure");
1557 /* Always move the meta index, even if gpgv failed. This ensures
1558 * that PackageFile objects are correctly filled in */
1559 if (FileExists(DestFile
)) {
1560 string FinalFile
= _config
->FindDir("Dir::State::lists");
1561 FinalFile
+= URItoFileName(RealURI
);
1562 /* InRelease files become Release files, otherwise
1563 * they would be considered as trusted later on */
1564 if (SigFile
== DestFile
) {
1565 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1567 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1569 SigFile
= FinalFile
;
1571 Rename(DestFile
,FinalFile
);
1572 chmod(FinalFile
.c_str(),0644);
1574 DestFile
= FinalFile
;
1577 // No Release file was present, or verification failed, so fall
1578 // back to queueing Packages files without verification
1579 QueueIndexes(false);
1582 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1583 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1584 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1585 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1586 const vector
<struct IndexTarget
*>* IndexTargets
,
1587 indexRecords
* MetaIndexParser
) :
1588 pkgAcqMetaIndex(Owner
, URI
, URIDesc
, ShortDesc
, "", IndexTargets
, MetaIndexParser
),
1589 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1590 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1595 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1596 // ---------------------------------------------------------------------
1597 // FIXME: this can go away once the InRelease file is used widely
1598 string
pkgAcqMetaClearSig::Custom600Headers()
1600 string Final
= _config
->FindDir("Dir::State::lists");
1601 Final
+= URItoFileName(RealURI
);
1604 if (stat(Final
.c_str(),&Buf
) != 0)
1605 return "\nIndex-File: true\nFail-Ignore: true\n";
1607 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1610 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1612 if (AuthPass
== false)
1614 new pkgAcqMetaSig(Owner
,
1615 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
1616 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
1617 IndexTargets
, MetaIndexParser
);
1618 if (Cnf
->LocalOnly
== true ||
1619 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
1623 pkgAcqMetaIndex::Failed(Message
, Cnf
);
1626 // AcqArchive::AcqArchive - Constructor /*{{{*/
1627 // ---------------------------------------------------------------------
1628 /* This just sets up the initial fetch environment and queues the first
1630 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
1631 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
1632 string
&StoreFilename
) :
1633 Item(Owner
), Version(Version
), Sources(Sources
), Recs(Recs
),
1634 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
1637 Retries
= _config
->FindI("Acquire::Retries",0);
1639 if (Version
.Arch() == 0)
1641 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1642 "This might mean you need to manually fix this package. "
1643 "(due to missing arch)"),
1644 Version
.ParentPkg().Name());
1648 /* We need to find a filename to determine the extension. We make the
1649 assumption here that all the available sources for this version share
1650 the same extension.. */
1651 // Skip not source sources, they do not have file fields.
1652 for (; Vf
.end() == false; Vf
++)
1654 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1659 // Does not really matter here.. we are going to fail out below
1660 if (Vf
.end() != true)
1662 // If this fails to get a file name we will bomb out below.
1663 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1664 if (_error
->PendingError() == true)
1667 // Generate the final file name as: package_version_arch.foo
1668 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
1669 QuoteString(Version
.VerStr(),"_:") + '_' +
1670 QuoteString(Version
.Arch(),"_:.") +
1671 "." + flExtension(Parse
.FileName());
1674 // check if we have one trusted source for the package. if so, switch
1675 // to "TrustedOnly" mode
1676 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
1678 pkgIndexFile
*Index
;
1679 if (Sources
->FindIndex(i
.File(),Index
) == false)
1681 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1683 std::cerr
<< "Checking index: " << Index
->Describe()
1684 << "(Trusted=" << Index
->IsTrusted() << ")\n";
1686 if (Index
->IsTrusted()) {
1692 // "allow-unauthenticated" restores apts old fetching behaviour
1693 // that means that e.g. unauthenticated file:// uris are higher
1694 // priority than authenticated http:// uris
1695 if (_config
->FindB("APT::Get::AllowUnauthenticated",false) == true)
1699 if (QueueNext() == false && _error
->PendingError() == false)
1700 _error
->Error(_("I wasn't able to locate a file for the %s package. "
1701 "This might mean you need to manually fix this package."),
1702 Version
.ParentPkg().Name());
1705 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
1706 // ---------------------------------------------------------------------
1707 /* This queues the next available file version for download. It checks if
1708 the archive is already available in the cache and stashs the MD5 for
1710 bool pkgAcqArchive::QueueNext()
1712 string
const ForceHash
= _config
->Find("Acquire::ForceHash");
1713 for (; Vf
.end() == false; ++Vf
)
1715 // Ignore not source sources
1716 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
1719 // Try to cross match against the source list
1720 pkgIndexFile
*Index
;
1721 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
1724 // only try to get a trusted package from another source if that source
1726 if(Trusted
&& !Index
->IsTrusted())
1729 // Grab the text package record
1730 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
1731 if (_error
->PendingError() == true)
1734 string PkgFile
= Parse
.FileName();
1735 if (ForceHash
.empty() == false)
1737 if(stringcasecmp(ForceHash
, "sha256") == 0)
1738 ExpectedHash
= HashString("SHA256", Parse
.SHA256Hash());
1739 else if (stringcasecmp(ForceHash
, "sha1") == 0)
1740 ExpectedHash
= HashString("SHA1", Parse
.SHA1Hash());
1742 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1747 if ((Hash
= Parse
.SHA256Hash()).empty() == false)
1748 ExpectedHash
= HashString("SHA256", Hash
);
1749 else if ((Hash
= Parse
.SHA1Hash()).empty() == false)
1750 ExpectedHash
= HashString("SHA1", Hash
);
1752 ExpectedHash
= HashString("MD5Sum", Parse
.MD5Hash());
1754 if (PkgFile
.empty() == true)
1755 return _error
->Error(_("The package index files are corrupted. No Filename: "
1756 "field for package %s."),
1757 Version
.ParentPkg().Name());
1759 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1760 Desc
.Description
= Index
->ArchiveInfo(Version
);
1762 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1764 // See if we already have the file. (Legacy filenames)
1765 FileSize
= Version
->Size
;
1766 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
1768 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1770 // Make sure the size matches
1771 if ((unsigned)Buf
.st_size
== Version
->Size
)
1776 StoreFilename
= DestFile
= FinalFile
;
1780 /* Hmm, we have a file and its size does not match, this means it is
1781 an old style mismatched arch */
1782 unlink(FinalFile
.c_str());
1785 // Check it again using the new style output filenames
1786 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
1787 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1789 // Make sure the size matches
1790 if ((unsigned)Buf
.st_size
== Version
->Size
)
1795 StoreFilename
= DestFile
= FinalFile
;
1799 /* Hmm, we have a file and its size does not match, this shouldnt
1801 unlink(FinalFile
.c_str());
1804 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
1806 // Check the destination file
1807 if (stat(DestFile
.c_str(),&Buf
) == 0)
1809 // Hmm, the partial file is too big, erase it
1810 if ((unsigned)Buf
.st_size
> Version
->Size
)
1811 unlink(DestFile
.c_str());
1813 PartialSize
= Buf
.st_size
;
1818 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
1819 Desc
.Description
= Index
->ArchiveInfo(Version
);
1821 Desc
.ShortDesc
= Version
.ParentPkg().Name();
1830 // AcqArchive::Done - Finished fetching /*{{{*/
1831 // ---------------------------------------------------------------------
1833 void pkgAcqArchive::Done(string Message
,unsigned long Size
,string CalcHash
,
1834 pkgAcquire::MethodConfig
*Cfg
)
1836 Item::Done(Message
,Size
,CalcHash
,Cfg
);
1839 if (Size
!= Version
->Size
)
1842 ErrorText
= _("Size mismatch");
1847 if(ExpectedHash
.toStr() != CalcHash
)
1850 ErrorText
= _("Hash Sum mismatch");
1851 if(FileExists(DestFile
))
1852 Rename(DestFile
,DestFile
+ ".FAILED");
1856 // Grab the output filename
1857 string FileName
= LookupTag(Message
,"Filename");
1858 if (FileName
.empty() == true)
1861 ErrorText
= "Method gave a blank filename";
1867 // Reference filename
1868 if (FileName
!= DestFile
)
1870 StoreFilename
= DestFile
= FileName
;
1875 // Done, move it into position
1876 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
1877 FinalFile
+= flNotDir(StoreFilename
);
1878 Rename(DestFile
,FinalFile
);
1880 StoreFilename
= DestFile
= FinalFile
;
1884 // AcqArchive::Failed - Failure handler /*{{{*/
1885 // ---------------------------------------------------------------------
1886 /* Here we try other sources */
1887 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1889 ErrorText
= LookupTag(Message
,"Message");
1891 /* We don't really want to retry on failed media swaps, this prevents
1892 that. An interesting observation is that permanent failures are not
1894 if (Cnf
->Removable
== true &&
1895 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1897 // Vf = Version.FileList();
1898 while (Vf
.end() == false) ++Vf
;
1899 StoreFilename
= string();
1900 Item::Failed(Message
,Cnf
);
1904 if (QueueNext() == false)
1906 // This is the retry counter
1908 Cnf
->LocalOnly
== false &&
1909 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
1912 Vf
= Version
.FileList();
1913 if (QueueNext() == true)
1917 StoreFilename
= string();
1918 Item::Failed(Message
,Cnf
);
1922 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
1923 // ---------------------------------------------------------------------
1924 bool pkgAcqArchive::IsTrusted()
1929 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
1930 // ---------------------------------------------------------------------
1932 void pkgAcqArchive::Finished()
1934 if (Status
== pkgAcquire::Item::StatDone
&&
1937 StoreFilename
= string();
1940 // AcqFile::pkgAcqFile - Constructor /*{{{*/
1941 // ---------------------------------------------------------------------
1942 /* The file is added to the queue */
1943 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
,string Hash
,
1944 unsigned long Size
,string Dsc
,string ShortDesc
,
1945 const string
&DestDir
, const string
&DestFilename
,
1947 Item(Owner
), ExpectedHash(Hash
), IsIndexFile(IsIndexFile
)
1949 Retries
= _config
->FindI("Acquire::Retries",0);
1951 if(!DestFilename
.empty())
1952 DestFile
= DestFilename
;
1953 else if(!DestDir
.empty())
1954 DestFile
= DestDir
+ "/" + flNotDir(URI
);
1956 DestFile
= flNotDir(URI
);
1960 Desc
.Description
= Dsc
;
1963 // Set the short description to the archive component
1964 Desc
.ShortDesc
= ShortDesc
;
1966 // Get the transfer sizes
1969 if (stat(DestFile
.c_str(),&Buf
) == 0)
1971 // Hmm, the partial file is too big, erase it
1972 if ((unsigned)Buf
.st_size
> Size
)
1973 unlink(DestFile
.c_str());
1975 PartialSize
= Buf
.st_size
;
1981 // AcqFile::Done - Item downloaded OK /*{{{*/
1982 // ---------------------------------------------------------------------
1984 void pkgAcqFile::Done(string Message
,unsigned long Size
,string CalcHash
,
1985 pkgAcquire::MethodConfig
*Cnf
)
1987 Item::Done(Message
,Size
,CalcHash
,Cnf
);
1990 if(!ExpectedHash
.empty() && ExpectedHash
.toStr() != CalcHash
)
1993 ErrorText
= _("Hash Sum mismatch");
1994 Rename(DestFile
,DestFile
+ ".FAILED");
1998 string FileName
= LookupTag(Message
,"Filename");
1999 if (FileName
.empty() == true)
2002 ErrorText
= "Method gave a blank filename";
2008 // The files timestamp matches
2009 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2012 // We have to copy it into place
2013 if (FileName
!= DestFile
)
2016 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2017 Cnf
->Removable
== true)
2019 Desc
.URI
= "copy:" + FileName
;
2024 // Erase the file if it is a symlink so we can overwrite it
2026 if (lstat(DestFile
.c_str(),&St
) == 0)
2028 if (S_ISLNK(St
.st_mode
) != 0)
2029 unlink(DestFile
.c_str());
2033 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2035 ErrorText
= "Link to " + DestFile
+ " failure ";
2042 // AcqFile::Failed - Failure handler /*{{{*/
2043 // ---------------------------------------------------------------------
2044 /* Here we try other sources */
2045 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2047 ErrorText
= LookupTag(Message
,"Message");
2049 // This is the retry counter
2051 Cnf
->LocalOnly
== false &&
2052 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2059 Item::Failed(Message
,Cnf
);
2062 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2063 // ---------------------------------------------------------------------
2064 /* The only header we use is the last-modified header. */
2065 string
pkgAcqFile::Custom600Headers()
2068 return "\nIndex-File: true";
2072 bool IndexTarget::IsOptional() const {
2073 if (strncmp(ShortDesc
.c_str(), "Translation", 11) != 0)
2077 bool IndexTarget::IsSubIndex() const {
2078 if (ShortDesc
!= "TranslationIndex")