1 // -*- mode: cpp; mode: fold -*-
3 // $Id: acquire-item.cc,v 1.46.2.9 2004/01/16 18:51:11 mdz Exp $
4 /* ######################################################################
6 Acquire Item - Item to acquire
8 Each item can download to exactly one file at a time. This means you
9 cannot create an item that fetches two uri's to two files at the same
10 time. The pkgAcqIndex class creates a second class upon instantiation
11 to fetch the other index files because of this.
13 ##################################################################### */
15 // Include Files /*{{{*/
18 #include <apt-pkg/acquire-item.h>
19 #include <apt-pkg/configuration.h>
20 #include <apt-pkg/aptconfiguration.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/error.h>
23 #include <apt-pkg/strutl.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/sha1.h>
26 #include <apt-pkg/tagfile.h>
27 #include <apt-pkg/indexrecords.h>
28 #include <apt-pkg/acquire.h>
29 #include <apt-pkg/hashes.h>
30 #include <apt-pkg/indexfile.h>
31 #include <apt-pkg/pkgcache.h>
32 #include <apt-pkg/cacheiterators.h>
33 #include <apt-pkg/pkgrecords.h>
53 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
55 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
57 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
58 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
59 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
60 std::cerr
<< " Actual Hash: " << std::endl
;
61 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
62 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
66 // Acquire::Item::Item - Constructor /*{{{*/
68 #pragma GCC diagnostic push
69 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
71 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
72 HashStringList
const &ExpectedHashes
,
73 pkgAcqMetaBase
*TransactionManager
)
74 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
75 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
76 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
80 if(TransactionManager
!= NULL
)
81 TransactionManager
->Add(this);
84 #pragma GCC diagnostic pop
87 // Acquire::Item::~Item - Destructor /*{{{*/
88 // ---------------------------------------------------------------------
90 pkgAcquire::Item::~Item()
95 // Acquire::Item::Failed - Item failed to download /*{{{*/
96 // ---------------------------------------------------------------------
97 /* We return to an idle state if there are still other queues that could
99 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
103 ErrorText
= LookupTag(Message
,"Message");
104 UsedMirror
= LookupTag(Message
,"UsedMirror");
105 if (QueueCounter
<= 1)
107 /* This indicates that the file is not available right now but might
108 be sometime later. If we do a retry cycle then this should be
110 if (Cnf
->LocalOnly
== true &&
111 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
122 // report mirror failure back to LP if we actually use a mirror
123 string FailReason
= LookupTag(Message
, "FailReason");
124 if(FailReason
.size() != 0)
125 ReportMirrorFailure(FailReason
);
127 ReportMirrorFailure(ErrorText
);
130 // Acquire::Item::Start - Item has begun to download /*{{{*/
131 // ---------------------------------------------------------------------
132 /* Stash status and the file size. Note that setting Complete means
133 sub-phases of the acquire process such as decompresion are operating */
134 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
136 Status
= StatFetching
;
137 if (FileSize
== 0 && Complete
== false)
141 // Acquire::Item::Done - Item downloaded OK /*{{{*/
142 // ---------------------------------------------------------------------
144 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
145 pkgAcquire::MethodConfig
* /*Cnf*/)
147 // We just downloaded something..
148 string FileName
= LookupTag(Message
,"Filename");
149 UsedMirror
= LookupTag(Message
,"UsedMirror");
150 if (Complete
== false && !Local
&& FileName
== DestFile
)
153 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
159 ErrorText
= string();
160 Owner
->Dequeue(this);
163 // Acquire::Item::Rename - Rename a file /*{{{*/
164 // ---------------------------------------------------------------------
165 /* This helper function is used by a lot of item methods as their final
167 bool pkgAcquire::Item::Rename(string From
,string To
)
169 if (rename(From
.c_str(),To
.c_str()) != 0)
172 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
173 From
.c_str(),To
.c_str());
181 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
183 if(FileExists(DestFile
))
184 Rename(DestFile
, DestFile
+ ".FAILED");
188 case HashSumMismatch
:
189 ErrorText
= _("Hash Sum mismatch");
190 Status
= StatAuthError
;
191 ReportMirrorFailure("HashChecksumFailure");
194 ErrorText
= _("Size mismatch");
195 Status
= StatAuthError
;
196 ReportMirrorFailure("SizeFailure");
199 ErrorText
= _("Invalid file format");
201 // do not report as usually its not the mirrors fault, but Portal/Proxy
204 ErrorText
= _("Signature error");
208 ErrorText
= _("Does not start with a cleartext signature");
215 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
217 ActiveSubprocess
= subprocess
;
219 #pragma GCC diagnostic push
220 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
222 Mode
= ActiveSubprocess
.c_str();
224 #pragma GCC diagnostic pop
228 // Acquire::Item::ReportMirrorFailure /*{{{*/
229 // ---------------------------------------------------------------------
230 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
232 // we only act if a mirror was used at all
233 if(UsedMirror
.empty())
236 std::cerr
<< "\nReportMirrorFailure: "
238 << " Uri: " << DescURI()
240 << FailCode
<< std::endl
;
242 const char *Args
[40];
244 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
245 "/usr/lib/apt/apt-report-mirror-failure");
246 if(!FileExists(report
))
248 Args
[i
++] = report
.c_str();
249 Args
[i
++] = UsedMirror
.c_str();
250 Args
[i
++] = DescURI().c_str();
251 Args
[i
++] = FailCode
.c_str();
253 pid_t pid
= ExecFork();
256 _error
->Error("ReportMirrorFailure Fork failed");
261 execvp(Args
[0], (char**)Args
);
262 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
265 if(!ExecWait(pid
, "report-mirror-failure"))
267 _error
->Warning("Couldn't report problem to '%s'",
268 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
272 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
273 // ---------------------------------------------------------------------
274 /* Get the DiffIndex file first and see if there are patches available
275 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
276 * patches. If anything goes wrong in that process, it will fall back to
277 * the original packages file
279 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
280 pkgAcqMetaBase
*TransactionManager
,
281 IndexTarget
const * const Target
,
282 HashStringList
const &ExpectedHashes
,
283 indexRecords
*MetaIndexParser
)
284 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
285 MetaIndexParser
), PackagesFileReadyInPartial(false)
288 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
290 RealURI
= Target
->URI
;
292 Desc
.Description
= Target
->Description
+ "/DiffIndex";
293 Desc
.ShortDesc
= Target
->ShortDesc
;
294 Desc
.URI
= Target
->URI
+ ".diff/Index";
296 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
297 DestFile
+= URItoFileName(Desc
.URI
);
300 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
302 // look for the current package file
303 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
304 CurrentPackagesFile
+= URItoFileName(RealURI
);
306 // FIXME: this file:/ check is a hack to prevent fetching
307 // from local sources. this is really silly, and
308 // should be fixed cleanly as soon as possible
309 if(!FileExists(CurrentPackagesFile
) ||
310 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
312 // we don't have a pkg file or we don't want to queue
314 std::clog
<< "No index file, local or canceld by user" << std::endl
;
320 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
321 << CurrentPackagesFile
<< std::endl
;
327 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
328 // ---------------------------------------------------------------------
329 /* The only header we use is the last-modified header. */
330 string
pkgAcqDiffIndex::Custom600Headers() const
332 string Final
= _config
->FindDir("Dir::State::lists");
333 Final
+= URItoFileName(Desc
.URI
);
336 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
339 if (stat(Final
.c_str(),&Buf
) != 0)
340 return "\nIndex-File: true";
342 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
345 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
348 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
353 vector
<DiffInfo
> available_patches
;
355 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
357 if (_error
->PendingError() == true)
360 if(TF
.Step(Tags
) == true)
366 string
const tmp
= Tags
.FindS("SHA1-Current");
367 std::stringstream
ss(tmp
);
368 ss
>> ServerSha1
>> size
;
369 unsigned long const ServerSize
= atol(size
.c_str());
371 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
374 string
const local_sha1
= SHA1
.Result();
376 if(local_sha1
== ServerSha1
)
378 // we have the same sha1 as the server so we are done here
380 std::clog
<< "Package file is up-to-date" << std::endl
;
381 // ensure we have no leftovers from previous runs
382 std::string Partial
= _config
->FindDir("Dir::State::lists");
383 Partial
+= "partial/" + URItoFileName(RealURI
);
384 unlink(Partial
.c_str());
385 // list cleanup needs to know that this file as well as the already
386 // present index is ours, so we create an empty diff to save it for us
387 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
388 ExpectedHashes
, MetaIndexParser
,
389 ServerSha1
, available_patches
);
395 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
397 // check the historie and see what patches we need
398 string
const history
= Tags
.FindS("SHA1-History");
399 std::stringstream
hist(history
);
400 while(hist
>> d
.sha1
>> size
>> d
.file
)
402 // read until the first match is found
403 // from that point on, we probably need all diffs
404 if(d
.sha1
== local_sha1
)
406 else if (found
== false)
410 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
411 available_patches
.push_back(d
);
414 if (available_patches
.empty() == false)
416 // patching with too many files is rather slow compared to a fast download
417 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
418 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
421 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
422 << ") so fallback to complete download" << std::endl
;
426 // see if the patches are too big
427 found
= false; // it was true and it will be true again at the end
428 d
= *available_patches
.begin();
429 string
const firstPatch
= d
.file
;
430 unsigned long patchesSize
= 0;
431 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
432 while(patches
>> d
.sha1
>> size
>> d
.file
)
434 if (firstPatch
== d
.file
)
436 else if (found
== false)
439 patchesSize
+= atol(size
.c_str());
441 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
442 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
445 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
446 << ") so fallback to complete download" << std::endl
;
452 // we have something, queue the next diff
455 // FIXME: make this use the method
456 PackagesFileReadyInPartial
= true;
457 std::string Partial
= _config
->FindDir("Dir::State::lists");
458 Partial
+= "partial/" + URItoFileName(RealURI
);
460 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
461 FileFd
To(Partial
, FileFd::WriteEmpty
);
462 if(CopyFile(From
, To
) == false)
463 return _error
->Errno("CopyFile", "failed to copy");
466 std::cerr
<< "Done copying " << CurrentPackagesFile
471 string::size_type
const last_space
= Description
.rfind(" ");
472 if(last_space
!= string::npos
)
473 Description
.erase(last_space
, Description
.size()-last_space
);
475 /* decide if we should download patches one by one or in one go:
476 The first is good if the server merges patches, but many don't so client
477 based merging can be attempt in which case the second is better.
478 "bad things" will happen if patches are merged on the server,
479 but client side merging is attempt as well */
480 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
481 if (pdiff_merge
== true)
483 // reprepro adds this flag if it has merged patches on the server
484 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
485 pdiff_merge
= (precedence
!= "merged");
488 if (pdiff_merge
== false)
490 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
492 ServerSha1
, available_patches
);
496 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
497 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
498 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
,
503 available_patches
[i
],
514 // Nothing found, report and return false
515 // Failing here is ok, if we return false later, the full
516 // IndexFile is queued
518 std::clog
<< "Can't find a patch in the index file" << std::endl
;
522 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
525 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
526 << "Falling back to normal index file acquire" << std::endl
;
528 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
535 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
536 pkgAcquire::MethodConfig
*Cnf
)
539 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
541 Item::Done(Message
, Size
, Hashes
, Cnf
);
543 // verify the index target
544 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
546 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
547 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
548 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
550 RenameOnError(HashSumMismatch
);
551 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
552 Failed(Message
, Cnf
);
558 if(!ParseDiffIndex(DestFile
))
559 return Failed("", NULL
);
561 // queue for final move
563 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
564 FinalFile
+= string(".IndexDiff");
565 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
573 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
574 // ---------------------------------------------------------------------
575 /* The package diff is added to the queue. one object is constructed
576 * for each diff and the index
578 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
579 pkgAcqMetaBase
*TransactionManager
,
580 struct IndexTarget
const * const Target
,
581 HashStringList
const &ExpectedHashes
,
582 indexRecords
*MetaIndexParser
,
584 vector
<DiffInfo
> diffs
)
585 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
586 available_patches(diffs
), ServerSha1(ServerSha1
)
589 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
590 DestFile
+= URItoFileName(Target
->URI
);
592 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
594 RealURI
= Target
->URI
;
596 Description
= Target
->Description
;
597 Desc
.ShortDesc
= Target
->ShortDesc
;
599 if(available_patches
.empty() == true)
601 // we are done (yeah!), check hashes against the final file
602 DestFile
= _config
->FindDir("Dir::State::lists");
603 DestFile
+= URItoFileName(Target
->URI
);
609 State
= StateFetchDiff
;
614 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
617 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
618 << "Falling back to normal index file acquire" << std::endl
;
619 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
623 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
624 void pkgAcqIndexDiffs::Finish(bool allDone
)
627 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
629 << Desc
.URI
<< std::endl
;
631 // we restore the original name, this is required, otherwise
632 // the file will be cleaned
635 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
637 RenameOnError(HashSumMismatch
);
643 PartialFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
645 DestFile
= _config
->FindDir("Dir::State::lists");
646 DestFile
+= URItoFileName(RealURI
);
648 // this happens if we have a up-to-date indexfile
649 if(!FileExists(PartialFile
))
650 PartialFile
= DestFile
;
652 TransactionManager
->TransactionStageCopy(this, PartialFile
, DestFile
);
654 // this is for the "real" finish
659 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
664 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
671 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
673 // calc sha1 of the just patched file
674 string FinalFile
= _config
->FindDir("Dir::State::lists");
675 FinalFile
+= "partial/" + URItoFileName(RealURI
);
677 if(!FileExists(FinalFile
))
679 Failed("No FinalFile " + FinalFile
+ " available", NULL
);
683 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
686 string local_sha1
= string(SHA1
.Result());
688 std::clog
<< "QueueNextDiff: "
689 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
692 // final file reached before all patches are applied
693 if(local_sha1
== ServerSha1
)
699 // remove all patches until the next matching patch is found
700 // this requires the Index file to be ordered
701 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
702 available_patches
.empty() == false &&
703 I
!= available_patches
.end() &&
704 I
->sha1
!= local_sha1
;
707 available_patches
.erase(I
);
710 // error checking and falling back if no patch was found
711 if(available_patches
.empty() == true)
713 Failed("No patches available", NULL
);
717 // queue the right diff
718 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
719 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
720 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
721 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
724 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
731 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
732 pkgAcquire::MethodConfig
*Cnf
)
735 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
737 Item::Done(Message
, Size
, Hashes
, Cnf
);
739 // FIXME: verify this download too before feeding it to rred
742 FinalFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
744 // success in downloading a diff, enter ApplyDiff state
745 if(State
== StateFetchDiff
)
748 // rred excepts the patch as $FinalFile.ed
749 Rename(DestFile
,FinalFile
+".ed");
752 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
754 State
= StateApplyDiff
;
756 Desc
.URI
= "rred:" + FinalFile
;
758 SetActiveSubprocess("rred");
763 // success in download/apply a diff, queue next (if needed)
764 if(State
== StateApplyDiff
)
766 // remove the just applied patch
767 available_patches
.erase(available_patches
.begin());
768 unlink((FinalFile
+ ".ed").c_str());
773 std::clog
<< "Moving patched file in place: " << std::endl
774 << DestFile
<< " -> " << FinalFile
<< std::endl
;
776 Rename(DestFile
,FinalFile
);
777 chmod(FinalFile
.c_str(),0644);
779 // see if there is more to download
780 if(available_patches
.empty() == false) {
781 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
782 ExpectedHashes
, MetaIndexParser
,
783 ServerSha1
, available_patches
);
787 DestFile
= FinalFile
;
792 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
793 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
794 pkgAcqMetaBase
*TransactionManager
,
795 struct IndexTarget
const * const Target
,
796 HashStringList
const &ExpectedHashes
,
797 indexRecords
*MetaIndexParser
,
798 DiffInfo
const &patch
,
799 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
800 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
801 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
804 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
805 DestFile
+= URItoFileName(Target
->URI
);
807 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
809 RealURI
= Target
->URI
;
811 Description
= Target
->Description
;
812 Desc
.ShortDesc
= Target
->ShortDesc
;
814 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
815 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
816 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
817 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
820 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
825 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
828 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
833 // check if we are the first to fail, otherwise we are done here
834 State
= StateDoneDiff
;
835 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
836 I
!= allPatches
->end(); ++I
)
837 if ((*I
)->State
== StateErrorDiff
)
840 // first failure means we should fallback
841 State
= StateErrorDiff
;
842 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
843 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
846 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
847 pkgAcquire::MethodConfig
*Cnf
)
850 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
852 Item::Done(Message
,Size
,Hashes
,Cnf
);
854 // FIXME: verify download before feeding it to rred
856 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + "partial/" + URItoFileName(RealURI
);
858 if (State
== StateFetchDiff
)
860 // rred expects the patch as $FinalFile.ed.$patchname.gz
861 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
863 // check if this is the last completed diff
864 State
= StateDoneDiff
;
865 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
866 I
!= allPatches
->end(); ++I
)
867 if ((*I
)->State
!= StateDoneDiff
)
870 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
874 // this is the last completed diff, so we are ready to apply now
875 State
= StateApplyDiff
;
878 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
881 Desc
.URI
= "rred:" + FinalFile
;
883 SetActiveSubprocess("rred");
886 // success in download/apply all diffs, clean up
887 else if (State
== StateApplyDiff
)
889 // see if we really got the expected file
890 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
892 RenameOnError(HashSumMismatch
);
897 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
898 FinalFile
+= URItoFileName(RealURI
);
900 // move the result into place
902 std::clog
<< "Queue patched file in place: " << std::endl
903 << DestFile
<< " -> " << FinalFile
<< std::endl
;
905 // queue for copy by the transaction manager
906 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
908 // ensure the ed's are gone regardless of list-cleanup
909 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
910 I
!= allPatches
->end(); ++I
)
912 std::string PartialFile
= _config
->FindDir("Dir::State::lists");
913 PartialFile
+= "partial/" + URItoFileName(RealURI
);
914 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
915 std::cerr
<< patch
<< std::endl
;
916 unlink(patch
.c_str());
922 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
926 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
927 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
929 if(MetaKey
!= "" && Hashes
.usable())
931 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
932 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
934 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
941 // AcqIndex::AcqIndex - Constructor /*{{{*/
942 // ---------------------------------------------------------------------
943 /* The package file is added to the queue and a second class is
944 instantiated to fetch the revision file */
945 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
946 string URI
,string URIDesc
,string ShortDesc
,
947 HashStringList
const &ExpectedHash
)
948 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
952 AutoSelectCompression();
953 Init(URI
, URIDesc
, ShortDesc
);
955 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
956 std::clog
<< "New pkgIndex with TransactionManager "
957 << TransactionManager
<< std::endl
;
960 // AcqIndex::AcqIndex - Constructor /*{{{*/
961 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
962 pkgAcqMetaBase
*TransactionManager
,
963 IndexTarget
const *Target
,
964 HashStringList
const &ExpectedHash
,
965 indexRecords
*MetaIndexParser
)
966 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
969 RealURI
= Target
->URI
;
971 // autoselect the compression method
972 AutoSelectCompression();
973 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
975 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
976 std::clog
<< "New pkgIndex with TransactionManager "
977 << TransactionManager
<< std::endl
;
980 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
981 void pkgAcqIndex::AutoSelectCompression()
983 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
984 CompressionExtensions
= "";
985 if (ExpectedHashes
.usable())
987 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
988 t
!= types
.end(); ++t
)
990 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
991 if (*t
== "uncompressed" ||
992 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
993 CompressionExtensions
.append(*t
).append(" ");
998 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
999 CompressionExtensions
.append(*t
).append(" ");
1001 if (CompressionExtensions
.empty() == false)
1002 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1005 // AcqIndex::Init - defered Constructor /*{{{*/
1006 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1007 string
const &ShortDesc
)
1009 Stage
= STAGE_DOWNLOAD
;
1011 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1012 DestFile
+= URItoFileName(URI
);
1014 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1015 if (CurrentCompressionExtension
== "uncompressed")
1019 MetaKey
= string(Target
->MetaKey
);
1023 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1024 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1026 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1029 // load the filesize
1032 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1034 FileSize
= Record
->Size
;
1036 InitByHashIfNeeded(MetaKey
);
1039 Desc
.Description
= URIDesc
;
1041 Desc
.ShortDesc
= ShortDesc
;
1046 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1047 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1050 // - (maybe?) add support for by-hash into the sources.list as flag
1051 // - make apt-ftparchive generate the hashes (and expire?)
1052 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1053 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1054 _config
->FindB(HostKnob
, false) == true ||
1055 MetaIndexParser
->GetSupportsAcquireByHash())
1057 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1060 // FIXME: should we really use the best hash here? or a fixed one?
1061 const HashString
*TargetHash
= Record
->Hashes
.find("");
1062 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1063 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1064 Desc
.URI
= Desc
.URI
.replace(
1066 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1070 "Fetching ByHash requested but can not find record for %s",
1076 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1077 // ---------------------------------------------------------------------
1078 /* The only header we use is the last-modified header. */
1079 string
pkgAcqIndex::Custom600Headers() const
1081 string Final
= GetFinalFilename();
1083 string msg
= "\nIndex-File: true";
1085 if (stat(Final
.c_str(),&Buf
) == 0)
1086 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1091 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1092 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1094 size_t const nextExt
= CompressionExtensions
.find(' ');
1095 if (nextExt
!= std::string::npos
)
1097 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1098 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1102 // on decompression failure, remove bad versions in partial/
1103 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1105 unlink(EraseFileName
.c_str());
1108 Item::Failed(Message
,Cnf
);
1110 /// cancel the entire transaction
1111 TransactionManager
->AbortTransaction();
1114 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1115 std::string
pkgAcqIndex::GetFinalFilename() const
1117 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1118 FinalFile
+= URItoFileName(RealURI
);
1119 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1120 FinalFile
+= '.' + CurrentCompressionExtension
;
1124 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1125 void pkgAcqIndex::ReverifyAfterIMS()
1127 // update destfile to *not* include the compression extension when doing
1128 // a reverify (as its uncompressed on disk already)
1129 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1130 DestFile
+= URItoFileName(RealURI
);
1132 // adjust DestFile if its compressed on disk
1133 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1134 DestFile
+= '.' + CurrentCompressionExtension
;
1136 // copy FinalFile into partial/ so that we check the hash again
1137 string FinalFile
= GetFinalFilename();
1138 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1139 Desc
.URI
= "copy:" + FinalFile
;
1143 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1144 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1146 // FIXME: this can go away once we only ever download stuff that
1147 // has a valid hash and we never do GET based probing
1148 // FIXME2: this also leaks debian-isms into the code and should go therefore
1150 /* Always validate the index file for correctness (all indexes must
1151 * have a Package field) (LP: #346386) (Closes: #627642)
1153 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1154 // Only test for correctness if the content of the file is not empty
1159 pkgTagFile
tag(&fd
);
1161 // all our current indexes have a field 'Package' in each section
1162 if (_error
->PendingError() == true ||
1163 tag
.Step(sec
) == false ||
1164 sec
.Exists("Package") == false)
1170 // AcqIndex::Done - Finished a fetch /*{{{*/
1171 // ---------------------------------------------------------------------
1172 /* This goes through a number of states.. On the initial fetch the
1173 method could possibly return an alternate filename which points
1174 to the uncompressed version of the file. If this is so the file
1175 is copied into the partial directory. In all other cases the file
1176 is decompressed with a compressed uri. */
1177 void pkgAcqIndex::Done(string Message
,
1178 unsigned long long Size
,
1179 HashStringList
const &Hashes
,
1180 pkgAcquire::MethodConfig
*Cfg
)
1182 Item::Done(Message
,Size
,Hashes
,Cfg
);
1186 case STAGE_DOWNLOAD
:
1187 StageDownloadDone(Message
, Hashes
, Cfg
);
1189 case STAGE_DECOMPRESS_AND_VERIFY
:
1190 StageDecompressDone(Message
, Hashes
, Cfg
);
1195 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1196 void pkgAcqIndex::StageDownloadDone(string Message
,
1197 HashStringList
const &Hashes
,
1198 pkgAcquire::MethodConfig
*Cfg
)
1200 // First check if the calculcated Hash of the (compressed) downloaded
1201 // file matches the hash we have in the MetaIndexRecords for this file
1202 if(VerifyHashByMetaKey(Hashes
) == false)
1204 RenameOnError(HashSumMismatch
);
1205 Failed(Message
, Cfg
);
1211 // Handle the unzipd case
1212 string FileName
= LookupTag(Message
,"Alt-Filename");
1213 if (FileName
.empty() == false)
1215 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1217 DestFile
+= ".decomp";
1218 Desc
.URI
= "copy:" + FileName
;
1220 SetActiveSubprocess("copy");
1224 FileName
= LookupTag(Message
,"Filename");
1225 if (FileName
.empty() == true)
1228 ErrorText
= "Method gave a blank filename";
1231 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1232 // not the "DestFile" we set, in this case we uncompress from the local file
1233 if (FileName
!= DestFile
)
1236 EraseFileName
= FileName
;
1238 // we need to verify the file against the current Release file again
1239 // on if-modfied-since hit to avoid a stale attack against us
1240 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1242 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1243 // file when its doing the indexcopy
1244 if (RealURI
.substr(0,6) == "cdrom:")
1247 // The files timestamp matches, reverify by copy into partial/
1253 // If we have compressed indexes enabled, queue for hash verification
1254 if (_config
->FindB("Acquire::GzipIndexes",false))
1256 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1257 DestFile
+= URItoFileName(RealURI
) + '.' + CurrentCompressionExtension
;
1259 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1260 Desc
.URI
= "copy:" + FileName
;
1266 // get the binary name for your used compression type
1268 if(CurrentCompressionExtension
== "uncompressed")
1269 decompProg
= "copy";
1271 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1272 if(decompProg
.empty() == true)
1274 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1278 // queue uri for the next stage
1279 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1280 DestFile
+= ".decomp";
1281 Desc
.URI
= decompProg
+ ":" + FileName
;
1284 SetActiveSubprocess(decompProg
);
1287 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1288 void pkgAcqIndex::StageDecompressDone(string Message
,
1289 HashStringList
const &Hashes
,
1290 pkgAcquire::MethodConfig
*Cfg
)
1292 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1295 RenameOnError(HashSumMismatch
);
1296 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1297 Failed(Message
, Cfg
);
1301 if(!ValidateFile(DestFile
))
1303 RenameOnError(InvalidFormat
);
1304 Failed(Message
, Cfg
);
1308 // remove the compressed version of the file
1309 unlink(EraseFileName
.c_str());
1311 // Done, queue for rename on transaction finished
1312 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1317 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1318 // ---------------------------------------------------------------------
1319 /* The Translation file is added to the queue */
1320 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1321 string URI
,string URIDesc
,string ShortDesc
)
1322 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1325 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1326 pkgAcqMetaBase
*TransactionManager
,
1327 IndexTarget
const * const Target
,
1328 HashStringList
const &ExpectedHashes
,
1329 indexRecords
*MetaIndexParser
)
1330 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1332 // load the filesize
1333 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1335 FileSize
= Record
->Size
;
1338 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1339 string
pkgAcqIndexTrans::Custom600Headers() const
1341 string Final
= GetFinalFilename();
1344 if (stat(Final
.c_str(),&Buf
) != 0)
1345 return "\nFail-Ignore: true\nIndex-File: true";
1346 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1349 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1350 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1352 size_t const nextExt
= CompressionExtensions
.find(' ');
1353 if (nextExt
!= std::string::npos
)
1355 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1356 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1361 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1362 if (Cnf
->LocalOnly
== true ||
1363 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1372 Item::Failed(Message
,Cnf
);
1375 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1376 void pkgAcqMetaBase::Add(Item
*I
)
1378 Transaction
.push_back(I
);
1381 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1382 void pkgAcqMetaBase::AbortTransaction()
1384 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1385 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1387 // ensure the toplevel is in error state too
1388 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1389 I
!= Transaction
.end(); ++I
)
1391 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1392 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1393 // the transaction will abort, so stop anything that is idle
1394 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1395 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1397 // kill files in partial
1398 string PartialFile
= _config
->FindDir("Dir::State::lists");
1399 PartialFile
+= "partial/";
1400 PartialFile
+= flNotDir((*I
)->DestFile
);
1401 if(FileExists(PartialFile
))
1402 Rename(PartialFile
, PartialFile
+ ".FAILED");
1406 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1407 bool pkgAcqMetaBase::TransactionHasError()
1409 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1410 I
!= Transaction
.end(); ++I
)
1411 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1412 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1418 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1419 void pkgAcqMetaBase::CommitTransaction()
1421 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1422 std::clog
<< "CommitTransaction: " << this << std::endl
;
1424 // move new files into place *and* remove files that are not
1425 // part of the transaction but are still on disk
1426 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1427 I
!= Transaction
.end(); ++I
)
1429 if((*I
)->PartialFile
!= "")
1431 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1433 << (*I
)->PartialFile
<< " -> "
1434 << (*I
)->DestFile
<< " "
1437 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1438 chmod((*I
)->DestFile
.c_str(),0644);
1440 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1446 unlink((*I
)->DestFile
.c_str());
1448 // mark that this transaction is finished
1449 (*I
)->TransactionManager
= 0;
1453 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1454 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1455 const std::string
&From
,
1456 const std::string
&To
)
1458 I
->PartialFile
= From
;
1462 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1463 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1464 const std::string
&FinalFile
)
1466 I
->PartialFile
= "";
1467 I
->DestFile
= FinalFile
;
1470 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1471 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&RealURI
,
1472 const std::string
&Message
)
1474 // FIXME: this entire function can do now that we disallow going to
1475 // a unauthenticated state and can cleanly rollback
1477 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1479 if(FileExists(Final
))
1481 Status
= StatTransientNetworkError
;
1482 _error
->Warning(_("An error occurred during the signature "
1483 "verification. The repository is not updated "
1484 "and the previous index files will be used. "
1485 "GPG error: %s: %s\n"),
1486 Desc
.Description
.c_str(),
1487 LookupTag(Message
,"Message").c_str());
1488 RunScripts("APT::Update::Auth-Failure");
1490 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1491 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1492 _error
->Error(_("GPG error: %s: %s"),
1493 Desc
.Description
.c_str(),
1494 LookupTag(Message
,"Message").c_str());
1498 _error
->Warning(_("GPG error: %s: %s"),
1499 Desc
.Description
.c_str(),
1500 LookupTag(Message
,"Message").c_str());
1502 // gpgv method failed
1503 ReportMirrorFailure("GPGFailure");
1507 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1508 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1509 pkgAcqMetaBase
*TransactionManager
,
1510 string URI
,string URIDesc
,string ShortDesc
,
1511 string MetaIndexFile
,
1512 const vector
<IndexTarget
*>* IndexTargets
,
1513 indexRecords
* MetaIndexParser
) :
1514 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1515 HashStringList(), TransactionManager
),
1516 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1517 ShortDesc(ShortDesc
)
1519 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1520 DestFile
+= URItoFileName(RealURI
);
1522 // remove any partial downloaded sig-file in partial/.
1523 // it may confuse proxies and is too small to warrant a
1524 // partial download anyway
1525 unlink(DestFile
.c_str());
1527 // set the TransactionManager
1528 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1529 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1530 << TransactionManager
<< std::endl
;
1533 Desc
.Description
= URIDesc
;
1535 Desc
.ShortDesc
= ShortDesc
;
1541 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1545 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1546 // ---------------------------------------------------------------------
1547 string
pkgAcqMetaSig::Custom600Headers() const
1549 string FinalFile
= _config
->FindDir("Dir::State::lists");
1550 FinalFile
+= URItoFileName(RealURI
);
1553 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1554 return "\nIndex-File: true";
1556 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1559 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1560 // ---------------------------------------------------------------------
1561 /* The only header we use is the last-modified header. */
1562 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1563 HashStringList
const &Hashes
,
1564 pkgAcquire::MethodConfig
*Cfg
)
1566 Item::Done(Message
, Size
, Hashes
, Cfg
);
1568 if(AuthPass
== false)
1570 if(CheckDownloadDone(Message
, RealURI
) == true)
1572 // destfile will be modified to point to MetaIndexFile for the
1573 // gpgv method, so we need to save it here
1574 MetaIndexFileSignature
= DestFile
;
1575 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1581 if(CheckAuthDone(Message
, RealURI
) == true)
1583 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1584 FinalFile
+= URItoFileName(RealURI
);
1585 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1590 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1592 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1594 // check if we need to fail at this point
1595 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1598 // FIXME: meh, this is not really elegant
1599 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1601 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1603 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1605 std::string downgrade_msg
;
1606 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1608 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1610 // meh, the users wants to take risks (we still mark the packages
1611 // from this repository as unauthenticated)
1612 _error
->Warning("%s", downgrade_msg
.c_str());
1613 _error
->Warning(_("This is normally not allowed, but the option "
1614 "Acquire::AllowDowngradeToInsecureRepositories was "
1615 "given to override it."));
1618 _error
->Error("%s", downgrade_msg
.c_str());
1619 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1620 Status
= pkgAcquire::Item::StatError
;
1621 TransactionManager
->AbortTransaction();
1626 // this ensures that any file in the lists/ dir is removed by the
1628 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1629 DestFile
+= URItoFileName(RealURI
);
1630 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1632 // only allow going further if the users explicitely wants it
1633 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
1635 // we parse the indexes here because at this point the user wanted
1636 // a repository that may potentially harm him
1637 MetaIndexParser
->Load(MetaIndexFile
);
1642 _error
->Warning("Use --allow-insecure-repositories to force the update");
1645 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1646 if (Cnf
->LocalOnly
== true ||
1647 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1655 Item::Failed(Message
,Cnf
);
1658 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1659 pkgAcqMetaBase
*TransactionManager
,
1660 string URI
,string URIDesc
,string ShortDesc
,
1661 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1662 const vector
<IndexTarget
*>* IndexTargets
,
1663 indexRecords
* MetaIndexParser
) :
1664 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1665 TransactionManager
),
1666 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1667 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1668 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1670 if(TransactionManager
== NULL
)
1672 this->TransactionManager
= this;
1673 this->TransactionManager
->Add(this);
1676 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1677 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1678 << this->TransactionManager
<< std::endl
;
1681 Init(URIDesc
, ShortDesc
);
1684 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1685 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1687 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1688 DestFile
+= URItoFileName(RealURI
);
1691 Desc
.Description
= URIDesc
;
1693 Desc
.ShortDesc
= ShortDesc
;
1696 // we expect more item
1697 ExpectedAdditionalItems
= IndexTargets
->size();
1701 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1702 // ---------------------------------------------------------------------
1703 string
pkgAcqMetaIndex::Custom600Headers() const
1705 string Final
= _config
->FindDir("Dir::State::lists");
1706 Final
+= URItoFileName(RealURI
);
1709 if (stat(Final
.c_str(),&Buf
) != 0)
1710 return "\nIndex-File: true";
1712 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1715 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1716 HashStringList
const &Hashes
,
1717 pkgAcquire::MethodConfig
*Cfg
)
1719 Item::Done(Message
,Size
,Hashes
,Cfg
);
1721 if(CheckDownloadDone(Message
, RealURI
))
1723 // we have a Release file, now download the Signature, all further
1724 // verify/queue for additional downloads will be done in the
1725 // pkgAcqMetaSig::Done() code
1726 std::string MetaIndexFile
= DestFile
;
1727 new pkgAcqMetaSig(Owner
, TransactionManager
,
1728 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1729 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1732 string FinalFile
= _config
->FindDir("Dir::State::lists");
1733 FinalFile
+= URItoFileName(RealURI
);
1734 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1738 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1740 // At this point, the gpgv method has succeeded, so there is a
1741 // valid signature from a key in the trusted keyring. We
1742 // perform additional verification of its contents, and use them
1743 // to verify the indexes we are about to download
1745 if (!MetaIndexParser
->Load(DestFile
))
1747 Status
= StatAuthError
;
1748 ErrorText
= MetaIndexParser
->ErrorText
;
1752 if (!VerifyVendor(Message
, RealURI
))
1757 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1758 std::cerr
<< "Signature verification succeeded: "
1759 << DestFile
<< std::endl
;
1761 // Download further indexes with verification
1763 // it would be really nice if we could simply do
1764 // if (IMSHit == false) QueueIndexes(true)
1765 // and skip the download if the Release file has not changed
1766 // - but right now the list cleaner will needs to be tricked
1767 // to not delete all our packages/source indexes in this case
1774 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1775 const std::string
&MetaIndexFileSignature
)
1778 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1779 DestFile
= MetaIndexFile
;
1781 SetActiveSubprocess("gpgv");
1785 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1786 const std::string
&RealURI
)
1788 // We have just finished downloading a Release file (it is not
1791 string FileName
= LookupTag(Message
,"Filename");
1792 if (FileName
.empty() == true)
1795 ErrorText
= "Method gave a blank filename";
1799 if (FileName
!= DestFile
)
1802 Desc
.URI
= "copy:" + FileName
;
1807 // make sure to verify against the right file on I-M-S hit
1808 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1811 string FinalFile
= _config
->FindDir("Dir::State::lists");
1812 FinalFile
+= URItoFileName(RealURI
);
1813 DestFile
= FinalFile
;
1816 // set Item to complete as the remaining work is all local (verify etc)
1822 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1824 bool transInRelease
= false;
1826 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1827 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1828 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1829 if (k
->find("Translation-") != std::string::npos
)
1831 transInRelease
= true;
1836 // at this point the real Items are loaded in the fetcher
1837 ExpectedAdditionalItems
= 0;
1838 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1839 Target
!= IndexTargets
->end();
1842 HashStringList ExpectedIndexHashes
;
1843 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1844 bool compressedAvailable
= false;
1847 if ((*Target
)->IsOptional() == true)
1849 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1850 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1851 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1853 compressedAvailable
= true;
1857 else if (verify
== true)
1859 Status
= StatAuthError
;
1860 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1866 ExpectedIndexHashes
= Record
->Hashes
;
1867 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1869 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1870 << "Expected Hash:" << std::endl
;
1871 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1872 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1873 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1875 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1877 Status
= StatAuthError
;
1878 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1883 if ((*Target
)->IsOptional() == true)
1885 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1887 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1888 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1889 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1891 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1896 /* Queue Packages file (either diff or full packages files, depending
1897 on the users option) - we also check if the PDiff Index file is listed
1898 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1899 instead, but passing the required info to it is to much hassle */
1900 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1901 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1902 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1904 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1908 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
1910 string::size_type pos
;
1912 // check for missing sigs (that where not fatal because otherwise we had
1915 string msg
= _("There is no public key available for the "
1916 "following key IDs:\n");
1917 pos
= Message
.find("NO_PUBKEY ");
1918 if (pos
!= std::string::npos
)
1920 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1921 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1922 missingkeys
+= (Fingerprint
);
1924 if(!missingkeys
.empty())
1925 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1927 string Transformed
= MetaIndexParser
->GetExpectedDist();
1929 if (Transformed
== "../project/experimental")
1931 Transformed
= "experimental";
1934 pos
= Transformed
.rfind('/');
1935 if (pos
!= string::npos
)
1937 Transformed
= Transformed
.substr(0, pos
);
1940 if (Transformed
== ".")
1945 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1946 MetaIndexParser
->GetValidUntil() > 0) {
1947 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1948 if (invalid_since
> 0)
1949 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1950 // the time since then the file is invalid - formated in the same way as in
1951 // the download progress display (e.g. 7d 3h 42min 1s)
1952 return _error
->Error(
1953 _("Release file for %s is expired (invalid since %s). "
1954 "Updates for this repository will not be applied."),
1955 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1958 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1960 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1961 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1962 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1965 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1967 // This might become fatal one day
1968 // Status = StatAuthError;
1969 // ErrorText = "Conflicting distribution; expected "
1970 // + MetaIndexParser->GetExpectedDist() + " but got "
1971 // + MetaIndexParser->GetDist();
1973 if (!Transformed
.empty())
1975 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1976 Desc
.Description
.c_str(),
1977 Transformed
.c_str(),
1978 MetaIndexParser
->GetDist().c_str());
1985 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
1986 void pkgAcqMetaIndex::Failed(string
/*Message*/,
1987 pkgAcquire::MethodConfig
* /*Cnf*/)
1989 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1991 _error
->Warning(_("The repository '%s' does not have a Release file. "
1992 "This is deprecated, please contact the owner of the "
1993 "repository."), URIDesc
.c_str());
1995 // No Release file was present so fall
1996 // back to queueing Packages files without verification
1997 // only allow going further if the users explicitely wants it
1998 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2000 // Done, queue for rename on transaction finished
2001 if (FileExists(DestFile
))
2002 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2004 // queue without any kind of hashsum support
2005 QueueIndexes(false);
2007 // warn if the repository is unsinged
2008 _error
->Warning("Use --allow-insecure-repositories to force the update");
2009 TransactionManager
->AbortTransaction();
2015 void pkgAcqMetaIndex::Finished() /*{{{*/
2017 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2018 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2019 if(TransactionManager
!= NULL
&&
2020 TransactionManager
->TransactionHasError() == false)
2021 TransactionManager
->CommitTransaction();
2024 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2025 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2026 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2027 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2028 const vector
<IndexTarget
*>* IndexTargets
,
2029 indexRecords
* MetaIndexParser
) :
2030 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2031 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2032 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2034 // index targets + (worst case:) Release/Release.gpg
2035 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2039 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2043 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2044 // ---------------------------------------------------------------------
2045 string
pkgAcqMetaClearSig::Custom600Headers() const
2047 string Final
= _config
->FindDir("Dir::State::lists");
2048 Final
+= URItoFileName(RealURI
);
2051 if (stat(Final
.c_str(),&Buf
) != 0)
2053 if (stat(Final
.c_str(),&Buf
) != 0)
2054 return "\nIndex-File: true\nFail-Ignore: true\n";
2057 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2060 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2061 // ---------------------------------------------------------------------
2062 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long /*Size*/,
2063 HashStringList
const &/*Hashes*/,
2064 pkgAcquire::MethodConfig
*Cnf
)
2066 // if we expect a ClearTextSignature (InRelase), ensure that
2067 // this is what we get and if not fail to queue a
2068 // Release/Release.gpg, see #346386
2069 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2071 pkgAcquire::Item::Failed(Message
, Cnf
);
2072 RenameOnError(NotClearsigned
);
2073 TransactionManager
->AbortTransaction();
2077 if(AuthPass
== false)
2079 if(CheckDownloadDone(Message
, RealURI
) == true)
2080 QueueForSignatureVerify(DestFile
, DestFile
);
2085 if(CheckAuthDone(Message
, RealURI
) == true)
2087 string FinalFile
= _config
->FindDir("Dir::State::lists");
2088 FinalFile
+= URItoFileName(RealURI
);
2090 // queue for copy in place
2091 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2096 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2098 // we failed, we will not get additional items from this method
2099 ExpectedAdditionalItems
= 0;
2101 if (AuthPass
== false)
2103 // Queue the 'old' InRelease file for removal if we try Release.gpg
2104 // as otherwise the file will stay around and gives a false-auth
2105 // impression (CVE-2012-0214)
2106 string FinalFile
= _config
->FindDir("Dir::State::lists");
2107 FinalFile
.append(URItoFileName(RealURI
));
2108 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2110 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2111 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2112 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2113 IndexTargets
, MetaIndexParser
);
2114 if (Cnf
->LocalOnly
== true ||
2115 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2120 if(CheckStopAuthentication(RealURI
, Message
))
2123 _error
->Warning(_("The data from '%s' is not signed. Packages "
2124 "from that repository can not be authenticated."),
2127 // No Release file was present, or verification failed, so fall
2128 // back to queueing Packages files without verification
2129 // only allow going further if the users explicitely wants it
2130 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2132 /* Always move the meta index, even if gpgv failed. This ensures
2133 * that PackageFile objects are correctly filled in */
2134 if (FileExists(DestFile
))
2136 string FinalFile
= _config
->FindDir("Dir::State::lists");
2137 FinalFile
+= URItoFileName(RealURI
);
2138 /* InRelease files become Release files, otherwise
2139 * they would be considered as trusted later on */
2140 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2142 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2146 // Done, queue for rename on transaction finished
2147 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2149 QueueIndexes(false);
2151 // warn if the repository is unsinged
2152 _error
->Warning("Use --allow-insecure-repositories to force the update");
2153 TransactionManager
->AbortTransaction();
2160 // AcqArchive::AcqArchive - Constructor /*{{{*/
2161 // ---------------------------------------------------------------------
2162 /* This just sets up the initial fetch environment and queues the first
2164 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2165 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2166 string
&StoreFilename
) :
2167 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2168 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2171 Retries
= _config
->FindI("Acquire::Retries",0);
2173 if (Version
.Arch() == 0)
2175 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2176 "This might mean you need to manually fix this package. "
2177 "(due to missing arch)"),
2178 Version
.ParentPkg().FullName().c_str());
2182 /* We need to find a filename to determine the extension. We make the
2183 assumption here that all the available sources for this version share
2184 the same extension.. */
2185 // Skip not source sources, they do not have file fields.
2186 for (; Vf
.end() == false; ++Vf
)
2188 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2193 // Does not really matter here.. we are going to fail out below
2194 if (Vf
.end() != true)
2196 // If this fails to get a file name we will bomb out below.
2197 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2198 if (_error
->PendingError() == true)
2201 // Generate the final file name as: package_version_arch.foo
2202 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2203 QuoteString(Version
.VerStr(),"_:") + '_' +
2204 QuoteString(Version
.Arch(),"_:.") +
2205 "." + flExtension(Parse
.FileName());
2208 // check if we have one trusted source for the package. if so, switch
2209 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2210 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2211 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2212 bool seenUntrusted
= false;
2213 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2215 pkgIndexFile
*Index
;
2216 if (Sources
->FindIndex(i
.File(),Index
) == false)
2219 if (debugAuth
== true)
2220 std::cerr
<< "Checking index: " << Index
->Describe()
2221 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2223 if (Index
->IsTrusted() == true)
2226 if (allowUnauth
== false)
2230 seenUntrusted
= true;
2233 // "allow-unauthenticated" restores apts old fetching behaviour
2234 // that means that e.g. unauthenticated file:// uris are higher
2235 // priority than authenticated http:// uris
2236 if (allowUnauth
== true && seenUntrusted
== true)
2240 if (QueueNext() == false && _error
->PendingError() == false)
2241 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2242 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2245 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2246 // ---------------------------------------------------------------------
2247 /* This queues the next available file version for download. It checks if
2248 the archive is already available in the cache and stashs the MD5 for
2250 bool pkgAcqArchive::QueueNext()
2252 for (; Vf
.end() == false; ++Vf
)
2254 // Ignore not source sources
2255 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2258 // Try to cross match against the source list
2259 pkgIndexFile
*Index
;
2260 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2263 // only try to get a trusted package from another source if that source
2265 if(Trusted
&& !Index
->IsTrusted())
2268 // Grab the text package record
2269 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2270 if (_error
->PendingError() == true)
2273 string PkgFile
= Parse
.FileName();
2274 ExpectedHashes
= Parse
.Hashes();
2276 if (PkgFile
.empty() == true)
2277 return _error
->Error(_("The package index files are corrupted. No Filename: "
2278 "field for package %s."),
2279 Version
.ParentPkg().Name());
2281 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2282 Desc
.Description
= Index
->ArchiveInfo(Version
);
2284 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2286 // See if we already have the file. (Legacy filenames)
2287 FileSize
= Version
->Size
;
2288 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2290 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2292 // Make sure the size matches
2293 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2298 StoreFilename
= DestFile
= FinalFile
;
2302 /* Hmm, we have a file and its size does not match, this means it is
2303 an old style mismatched arch */
2304 unlink(FinalFile
.c_str());
2307 // Check it again using the new style output filenames
2308 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2309 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2311 // Make sure the size matches
2312 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2317 StoreFilename
= DestFile
= FinalFile
;
2321 /* Hmm, we have a file and its size does not match, this shouldn't
2323 unlink(FinalFile
.c_str());
2326 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2328 // Check the destination file
2329 if (stat(DestFile
.c_str(),&Buf
) == 0)
2331 // Hmm, the partial file is too big, erase it
2332 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2333 unlink(DestFile
.c_str());
2335 PartialSize
= Buf
.st_size
;
2338 // Disables download of archives - useful if no real installation follows,
2339 // e.g. if we are just interested in proposed installation order
2340 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2345 StoreFilename
= DestFile
= FinalFile
;
2359 // AcqArchive::Done - Finished fetching /*{{{*/
2360 // ---------------------------------------------------------------------
2362 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2363 pkgAcquire::MethodConfig
*Cfg
)
2365 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2368 if (Size
!= Version
->Size
)
2370 RenameOnError(SizeMismatch
);
2374 // FIXME: could this empty() check impose *any* sort of security issue?
2375 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2377 RenameOnError(HashSumMismatch
);
2378 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2382 // Grab the output filename
2383 string FileName
= LookupTag(Message
,"Filename");
2384 if (FileName
.empty() == true)
2387 ErrorText
= "Method gave a blank filename";
2393 // Reference filename
2394 if (FileName
!= DestFile
)
2396 StoreFilename
= DestFile
= FileName
;
2401 // Done, move it into position
2402 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2403 FinalFile
+= flNotDir(StoreFilename
);
2404 Rename(DestFile
,FinalFile
);
2406 StoreFilename
= DestFile
= FinalFile
;
2410 // AcqArchive::Failed - Failure handler /*{{{*/
2411 // ---------------------------------------------------------------------
2412 /* Here we try other sources */
2413 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2415 ErrorText
= LookupTag(Message
,"Message");
2417 /* We don't really want to retry on failed media swaps, this prevents
2418 that. An interesting observation is that permanent failures are not
2420 if (Cnf
->Removable
== true &&
2421 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2423 // Vf = Version.FileList();
2424 while (Vf
.end() == false) ++Vf
;
2425 StoreFilename
= string();
2426 Item::Failed(Message
,Cnf
);
2430 if (QueueNext() == false)
2432 // This is the retry counter
2434 Cnf
->LocalOnly
== false &&
2435 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2438 Vf
= Version
.FileList();
2439 if (QueueNext() == true)
2443 StoreFilename
= string();
2444 Item::Failed(Message
,Cnf
);
2448 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2449 // ---------------------------------------------------------------------
2450 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2455 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2456 // ---------------------------------------------------------------------
2458 void pkgAcqArchive::Finished()
2460 if (Status
== pkgAcquire::Item::StatDone
&&
2463 StoreFilename
= string();
2466 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2467 // ---------------------------------------------------------------------
2468 /* The file is added to the queue */
2469 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2470 unsigned long long Size
,string Dsc
,string ShortDesc
,
2471 const string
&DestDir
, const string
&DestFilename
,
2473 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2475 Retries
= _config
->FindI("Acquire::Retries",0);
2477 if(!DestFilename
.empty())
2478 DestFile
= DestFilename
;
2479 else if(!DestDir
.empty())
2480 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2482 DestFile
= flNotDir(URI
);
2486 Desc
.Description
= Dsc
;
2489 // Set the short description to the archive component
2490 Desc
.ShortDesc
= ShortDesc
;
2492 // Get the transfer sizes
2495 if (stat(DestFile
.c_str(),&Buf
) == 0)
2497 // Hmm, the partial file is too big, erase it
2498 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2499 unlink(DestFile
.c_str());
2501 PartialSize
= Buf
.st_size
;
2507 // AcqFile::Done - Item downloaded OK /*{{{*/
2508 // ---------------------------------------------------------------------
2510 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2511 pkgAcquire::MethodConfig
*Cnf
)
2513 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2516 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2518 RenameOnError(HashSumMismatch
);
2519 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2523 string FileName
= LookupTag(Message
,"Filename");
2524 if (FileName
.empty() == true)
2527 ErrorText
= "Method gave a blank filename";
2533 // The files timestamp matches
2534 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2537 // We have to copy it into place
2538 if (FileName
!= DestFile
)
2541 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2542 Cnf
->Removable
== true)
2544 Desc
.URI
= "copy:" + FileName
;
2549 // Erase the file if it is a symlink so we can overwrite it
2551 if (lstat(DestFile
.c_str(),&St
) == 0)
2553 if (S_ISLNK(St
.st_mode
) != 0)
2554 unlink(DestFile
.c_str());
2558 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2560 ErrorText
= "Link to " + DestFile
+ " failure ";
2567 // AcqFile::Failed - Failure handler /*{{{*/
2568 // ---------------------------------------------------------------------
2569 /* Here we try other sources */
2570 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2572 ErrorText
= LookupTag(Message
,"Message");
2574 // This is the retry counter
2576 Cnf
->LocalOnly
== false &&
2577 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2584 Item::Failed(Message
,Cnf
);
2587 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2588 // ---------------------------------------------------------------------
2589 /* The only header we use is the last-modified header. */
2590 string
pkgAcqFile::Custom600Headers() const
2593 return "\nIndex-File: true";