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
);
559 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
561 // success in downloading the index
563 FinalFile
+= string(".IndexDiff");
565 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
567 Rename(DestFile
,FinalFile
);
568 chmod(FinalFile
.c_str(),0644);
569 DestFile
= FinalFile
;
571 if(!ParseDiffIndex(DestFile
))
572 return Failed("", NULL
);
580 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
581 // ---------------------------------------------------------------------
582 /* The package diff is added to the queue. one object is constructed
583 * for each diff and the index
585 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
586 pkgAcqMetaBase
*TransactionManager
,
587 struct IndexTarget
const * const Target
,
588 HashStringList
const &ExpectedHashes
,
589 indexRecords
*MetaIndexParser
,
591 vector
<DiffInfo
> diffs
)
592 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
593 available_patches(diffs
), ServerSha1(ServerSha1
)
596 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
597 DestFile
+= URItoFileName(Target
->URI
);
599 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
601 RealURI
= Target
->URI
;
603 Description
= Target
->Description
;
604 Desc
.ShortDesc
= Target
->ShortDesc
;
606 if(available_patches
.empty() == true)
608 // we are done (yeah!), check hashes against the final file
609 DestFile
= _config
->FindDir("Dir::State::lists");
610 DestFile
+= URItoFileName(Target
->URI
);
616 State
= StateFetchDiff
;
621 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
624 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
625 << "Falling back to normal index file acquire" << std::endl
;
626 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
630 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
631 void pkgAcqIndexDiffs::Finish(bool allDone
)
634 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
636 << Desc
.URI
<< std::endl
;
638 // we restore the original name, this is required, otherwise
639 // the file will be cleaned
642 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
644 RenameOnError(HashSumMismatch
);
650 PartialFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
652 DestFile
= _config
->FindDir("Dir::State::lists");
653 DestFile
+= URItoFileName(RealURI
);
655 // this happens if we have a up-to-date indexfile
656 if(!FileExists(PartialFile
))
657 PartialFile
= DestFile
;
659 TransactionManager
->TransactionStageCopy(this, PartialFile
, DestFile
);
661 // this is for the "real" finish
666 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
671 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
678 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
680 // calc sha1 of the just patched file
681 string FinalFile
= _config
->FindDir("Dir::State::lists");
682 FinalFile
+= "partial/" + URItoFileName(RealURI
);
684 if(!FileExists(FinalFile
))
686 Failed("No FinalFile " + FinalFile
+ " available", NULL
);
690 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
693 string local_sha1
= string(SHA1
.Result());
695 std::clog
<< "QueueNextDiff: "
696 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
699 // final file reached before all patches are applied
700 if(local_sha1
== ServerSha1
)
706 // remove all patches until the next matching patch is found
707 // this requires the Index file to be ordered
708 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
709 available_patches
.empty() == false &&
710 I
!= available_patches
.end() &&
711 I
->sha1
!= local_sha1
;
714 available_patches
.erase(I
);
717 // error checking and falling back if no patch was found
718 if(available_patches
.empty() == true)
720 Failed("No patches available", NULL
);
724 // queue the right diff
725 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
726 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
727 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
728 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
731 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
738 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
739 pkgAcquire::MethodConfig
*Cnf
)
742 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
744 Item::Done(Message
, Size
, Hashes
, Cnf
);
746 // FIXME: verify this download too before feeding it to rred
749 FinalFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
751 // success in downloading a diff, enter ApplyDiff state
752 if(State
== StateFetchDiff
)
755 // rred excepts the patch as $FinalFile.ed
756 Rename(DestFile
,FinalFile
+".ed");
759 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
761 State
= StateApplyDiff
;
763 Desc
.URI
= "rred:" + FinalFile
;
765 SetActiveSubprocess("rred");
770 // success in download/apply a diff, queue next (if needed)
771 if(State
== StateApplyDiff
)
773 // remove the just applied patch
774 available_patches
.erase(available_patches
.begin());
775 unlink((FinalFile
+ ".ed").c_str());
780 std::clog
<< "Moving patched file in place: " << std::endl
781 << DestFile
<< " -> " << FinalFile
<< std::endl
;
783 Rename(DestFile
,FinalFile
);
784 chmod(FinalFile
.c_str(),0644);
786 // see if there is more to download
787 if(available_patches
.empty() == false) {
788 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
789 ExpectedHashes
, MetaIndexParser
,
790 ServerSha1
, available_patches
);
794 DestFile
= FinalFile
;
799 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
800 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
801 pkgAcqMetaBase
*TransactionManager
,
802 struct IndexTarget
const * const Target
,
803 HashStringList
const &ExpectedHashes
,
804 indexRecords
*MetaIndexParser
,
805 DiffInfo
const &patch
,
806 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
807 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
808 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
811 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
812 DestFile
+= URItoFileName(Target
->URI
);
814 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
816 RealURI
= Target
->URI
;
818 Description
= Target
->Description
;
819 Desc
.ShortDesc
= Target
->ShortDesc
;
821 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
822 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
823 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
824 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
827 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
832 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
835 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
840 // check if we are the first to fail, otherwise we are done here
841 State
= StateDoneDiff
;
842 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
843 I
!= allPatches
->end(); ++I
)
844 if ((*I
)->State
== StateErrorDiff
)
847 // first failure means we should fallback
848 State
= StateErrorDiff
;
849 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
850 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
853 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
854 pkgAcquire::MethodConfig
*Cnf
)
857 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
859 Item::Done(Message
,Size
,Hashes
,Cnf
);
861 // FIXME: verify download before feeding it to rred
863 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + "partial/" + URItoFileName(RealURI
);
865 if (State
== StateFetchDiff
)
867 // rred expects the patch as $FinalFile.ed.$patchname.gz
868 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
870 // check if this is the last completed diff
871 State
= StateDoneDiff
;
872 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
873 I
!= allPatches
->end(); ++I
)
874 if ((*I
)->State
!= StateDoneDiff
)
877 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
881 // this is the last completed diff, so we are ready to apply now
882 State
= StateApplyDiff
;
885 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
888 Desc
.URI
= "rred:" + FinalFile
;
890 SetActiveSubprocess("rred");
893 // success in download/apply all diffs, clean up
894 else if (State
== StateApplyDiff
)
896 // see if we really got the expected file
897 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
899 RenameOnError(HashSumMismatch
);
904 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
905 FinalFile
+= URItoFileName(RealURI
);
907 // move the result into place
909 std::clog
<< "Queue patched file in place: " << std::endl
910 << DestFile
<< " -> " << FinalFile
<< std::endl
;
912 // queue for copy by the transaction manager
913 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
915 // ensure the ed's are gone regardless of list-cleanup
916 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
917 I
!= allPatches
->end(); ++I
)
919 std::string PartialFile
= _config
->FindDir("Dir::State::lists");
920 PartialFile
+= "partial/" + URItoFileName(RealURI
);
921 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
922 std::cerr
<< patch
<< std::endl
;
923 unlink(patch
.c_str());
929 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
934 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
935 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
937 if(MetaKey
!= "" && Hashes
.usable())
939 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
940 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
942 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
950 // AcqIndex::AcqIndex - Constructor /*{{{*/
951 // ---------------------------------------------------------------------
952 /* The package file is added to the queue and a second class is
953 instantiated to fetch the revision file */
954 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
955 string URI
,string URIDesc
,string ShortDesc
,
956 HashStringList
const &ExpectedHash
)
957 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
961 AutoSelectCompression();
962 Init(URI
, URIDesc
, ShortDesc
);
964 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
965 std::clog
<< "New pkgIndex with TransactionManager "
966 << TransactionManager
<< std::endl
;
969 // AcqIndex::AcqIndex - Constructor /*{{{*/
970 // ---------------------------------------------------------------------
971 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
972 pkgAcqMetaBase
*TransactionManager
,
973 IndexTarget
const *Target
,
974 HashStringList
const &ExpectedHash
,
975 indexRecords
*MetaIndexParser
)
976 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
979 RealURI
= Target
->URI
;
981 // autoselect the compression method
982 AutoSelectCompression();
983 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
985 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
986 std::clog
<< "New pkgIndex with TransactionManager "
987 << TransactionManager
<< std::endl
;
990 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
991 // ---------------------------------------------------------------------
992 void pkgAcqIndex::AutoSelectCompression()
994 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
995 CompressionExtensions
= "";
996 if (ExpectedHashes
.usable())
998 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
999 t
!= types
.end(); ++t
)
1001 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1002 if (*t
== "uncompressed" ||
1003 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1004 CompressionExtensions
.append(*t
).append(" ");
1009 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1010 CompressionExtensions
.append(*t
).append(" ");
1012 if (CompressionExtensions
.empty() == false)
1013 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1015 // AcqIndex::Init - defered Constructor /*{{{*/
1016 // ---------------------------------------------------------------------
1017 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1018 string
const &ShortDesc
)
1020 Stage
= STAGE_DOWNLOAD
;
1022 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1023 DestFile
+= URItoFileName(URI
);
1025 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1026 if (CurrentCompressionExtension
== "uncompressed")
1030 MetaKey
= string(Target
->MetaKey
);
1034 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1035 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1037 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1040 // load the filesize
1043 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1045 FileSize
= Record
->Size
;
1047 InitByHashIfNeeded(MetaKey
);
1050 Desc
.Description
= URIDesc
;
1052 Desc
.ShortDesc
= ShortDesc
;
1057 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1058 // ---------------------------------------------------------------------
1060 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1063 // - (maybe?) add support for by-hash into the sources.list as flag
1064 // - make apt-ftparchive generate the hashes (and expire?)
1065 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1066 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1067 _config
->FindB(HostKnob
, false) == true ||
1068 MetaIndexParser
->GetSupportsAcquireByHash())
1070 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1073 // FIXME: should we really use the best hash here? or a fixed one?
1074 const HashString
*TargetHash
= Record
->Hashes
.find("");
1075 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1076 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1077 Desc
.URI
= Desc
.URI
.replace(
1079 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1083 "Fetching ByHash requested but can not find record for %s",
1089 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1090 // ---------------------------------------------------------------------
1091 /* The only header we use is the last-modified header. */
1092 string
pkgAcqIndex::Custom600Headers() const
1094 string Final
= GetFinalFilename();
1096 string msg
= "\nIndex-File: true";
1098 if (stat(Final
.c_str(),&Buf
) == 0)
1099 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1104 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1105 // ---------------------------------------------------------------------
1107 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1109 size_t const nextExt
= CompressionExtensions
.find(' ');
1110 if (nextExt
!= std::string::npos
)
1112 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1113 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1117 // on decompression failure, remove bad versions in partial/
1118 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1120 unlink(EraseFileName
.c_str());
1123 Item::Failed(Message
,Cnf
);
1125 /// cancel the entire transaction
1126 TransactionManager
->AbortTransaction();
1129 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1130 // ---------------------------------------------------------------------
1132 std::string
pkgAcqIndex::GetFinalFilename() const
1134 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1135 FinalFile
+= URItoFileName(RealURI
);
1136 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1137 FinalFile
+= '.' + CurrentCompressionExtension
;
1141 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1142 // ---------------------------------------------------------------------
1144 void pkgAcqIndex::ReverifyAfterIMS()
1146 // update destfile to *not* include the compression extension when doing
1147 // a reverify (as its uncompressed on disk already)
1148 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1149 DestFile
+= URItoFileName(RealURI
);
1151 // adjust DestFile if its compressed on disk
1152 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1153 DestFile
+= '.' + CurrentCompressionExtension
;
1155 // copy FinalFile into partial/ so that we check the hash again
1156 string FinalFile
= GetFinalFilename();
1157 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1158 Desc
.URI
= "copy:" + FinalFile
;
1163 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1164 // --------------------------------------------------------------------------
1165 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1167 // FIXME: this can go away once we only ever download stuff that
1168 // has a valid hash and we never do GET based probing
1169 // FIXME2: this also leaks debian-isms into the code and should go therefore
1171 /* Always validate the index file for correctness (all indexes must
1172 * have a Package field) (LP: #346386) (Closes: #627642)
1174 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1175 // Only test for correctness if the content of the file is not empty
1180 pkgTagFile
tag(&fd
);
1182 // all our current indexes have a field 'Package' in each section
1183 if (_error
->PendingError() == true ||
1184 tag
.Step(sec
) == false ||
1185 sec
.Exists("Package") == false)
1191 // AcqIndex::Done - Finished a fetch /*{{{*/
1192 // ---------------------------------------------------------------------
1193 /* This goes through a number of states.. On the initial fetch the
1194 method could possibly return an alternate filename which points
1195 to the uncompressed version of the file. If this is so the file
1196 is copied into the partial directory. In all other cases the file
1197 is decompressed with a compressed uri. */
1198 void pkgAcqIndex::Done(string Message
,
1199 unsigned long long Size
,
1200 HashStringList
const &Hashes
,
1201 pkgAcquire::MethodConfig
*Cfg
)
1203 Item::Done(Message
,Size
,Hashes
,Cfg
);
1207 case STAGE_DOWNLOAD
:
1208 StageDownloadDone(Message
, Hashes
, Cfg
);
1210 case STAGE_DECOMPRESS_AND_VERIFY
:
1211 StageDecompressDone(Message
, Hashes
, Cfg
);
1216 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1217 void pkgAcqIndex::StageDownloadDone(string Message
,
1218 HashStringList
const &Hashes
,
1219 pkgAcquire::MethodConfig
*Cfg
)
1221 // First check if the calculcated Hash of the (compressed) downloaded
1222 // file matches the hash we have in the MetaIndexRecords for this file
1223 if(VerifyHashByMetaKey(Hashes
) == false)
1225 RenameOnError(HashSumMismatch
);
1226 Failed(Message
, Cfg
);
1232 // Handle the unzipd case
1233 string FileName
= LookupTag(Message
,"Alt-Filename");
1234 if (FileName
.empty() == false)
1236 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1238 DestFile
+= ".decomp";
1239 Desc
.URI
= "copy:" + FileName
;
1241 SetActiveSubprocess("copy");
1245 FileName
= LookupTag(Message
,"Filename");
1246 if (FileName
.empty() == true)
1249 ErrorText
= "Method gave a blank filename";
1252 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1253 // not the "DestFile" we set, in this case we uncompress from the local file
1254 if (FileName
!= DestFile
)
1257 EraseFileName
= FileName
;
1259 // we need to verify the file against the current Release file again
1260 // on if-modfied-since hit to avoid a stale attack against us
1261 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1263 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1264 // file when its doing the indexcopy
1265 if (RealURI
.substr(0,6) == "cdrom:")
1268 // The files timestamp matches, reverify by copy into partial/
1274 // If we have compressed indexes enabled, queue for hash verification
1275 if (_config
->FindB("Acquire::GzipIndexes",false))
1277 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1278 DestFile
+= URItoFileName(RealURI
) + '.' + CurrentCompressionExtension
;
1280 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1281 Desc
.URI
= "copy:" + FileName
;
1287 // get the binary name for your used compression type
1289 if(CurrentCompressionExtension
== "uncompressed")
1290 decompProg
= "copy";
1292 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1293 if(decompProg
.empty() == true)
1295 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1299 // queue uri for the next stage
1300 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1301 DestFile
+= ".decomp";
1302 Desc
.URI
= decompProg
+ ":" + FileName
;
1305 SetActiveSubprocess(decompProg
);
1308 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1309 void pkgAcqIndex::StageDecompressDone(string Message
,
1310 HashStringList
const &Hashes
,
1311 pkgAcquire::MethodConfig
*Cfg
)
1313 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1316 RenameOnError(HashSumMismatch
);
1317 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1318 Failed(Message
, Cfg
);
1322 if(!ValidateFile(DestFile
))
1324 RenameOnError(InvalidFormat
);
1325 Failed(Message
, Cfg
);
1329 // remove the compressed version of the file
1330 unlink(EraseFileName
.c_str());
1332 // Done, queue for rename on transaction finished
1333 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1339 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1340 // ---------------------------------------------------------------------
1341 /* The Translation file is added to the queue */
1342 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1343 string URI
,string URIDesc
,string ShortDesc
)
1344 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1348 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1349 pkgAcqMetaBase
*TransactionManager
,
1350 IndexTarget
const * const Target
,
1351 HashStringList
const &ExpectedHashes
,
1352 indexRecords
*MetaIndexParser
)
1353 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1355 // load the filesize
1356 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1358 FileSize
= Record
->Size
;
1361 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1362 // ---------------------------------------------------------------------
1363 string
pkgAcqIndexTrans::Custom600Headers() const
1365 string Final
= GetFinalFilename();
1368 if (stat(Final
.c_str(),&Buf
) != 0)
1369 return "\nFail-Ignore: true\nIndex-File: true";
1370 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1373 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1374 // ---------------------------------------------------------------------
1376 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1378 size_t const nextExt
= CompressionExtensions
.find(' ');
1379 if (nextExt
!= std::string::npos
)
1381 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1382 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1387 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1388 if (Cnf
->LocalOnly
== true ||
1389 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1398 Item::Failed(Message
,Cnf
);
1401 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1402 // ---------------------------------------------------------------------
1404 void pkgAcqMetaBase::Add(Item
*I
)
1406 Transaction
.push_back(I
);
1409 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1410 // ---------------------------------------------------------------------
1412 void pkgAcqMetaBase::AbortTransaction()
1414 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1415 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1417 // ensure the toplevel is in error state too
1418 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1419 I
!= Transaction
.end(); ++I
)
1421 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1422 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1423 // the transaction will abort, so stop anything that is idle
1424 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1425 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1427 // kill files in partial
1428 string PartialFile
= _config
->FindDir("Dir::State::lists");
1429 PartialFile
+= "partial/";
1430 PartialFile
+= flNotDir((*I
)->DestFile
);
1431 if(FileExists(PartialFile
))
1432 Rename(PartialFile
, PartialFile
+ ".FAILED");
1436 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1437 // ---------------------------------------------------------------------
1439 bool pkgAcqMetaBase::TransactionHasError()
1441 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1442 I
!= Transaction
.end(); ++I
)
1443 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1444 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1450 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1451 // ---------------------------------------------------------------------
1453 void pkgAcqMetaBase::CommitTransaction()
1455 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1456 std::clog
<< "CommitTransaction: " << this << std::endl
;
1458 // move new files into place *and* remove files that are not
1459 // part of the transaction but are still on disk
1460 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1461 I
!= Transaction
.end(); ++I
)
1463 if((*I
)->PartialFile
!= "")
1465 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1467 << (*I
)->PartialFile
<< " -> "
1468 << (*I
)->DestFile
<< " "
1471 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1472 chmod((*I
)->DestFile
.c_str(),0644);
1474 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1480 unlink((*I
)->DestFile
.c_str());
1482 // mark that this transaction is finished
1483 (*I
)->TransactionManager
= 0;
1487 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1488 // ---------------------------------------------------------------------
1490 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1491 const std::string
&From
,
1492 const std::string
&To
)
1494 I
->PartialFile
= From
;
1498 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1499 // ---------------------------------------------------------------------
1501 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1502 const std::string
&FinalFile
)
1504 I
->PartialFile
= "";
1505 I
->DestFile
= FinalFile
;
1509 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1510 // ---------------------------------------------------------------------
1512 bool pkgAcqMetaBase::GenerateAuthWarning(const std::string
&RealURI
,
1513 const std::string
&Message
)
1515 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1517 if(FileExists(Final
))
1519 Status
= StatTransientNetworkError
;
1520 _error
->Warning(_("An error occurred during the signature "
1521 "verification. The repository is not updated "
1522 "and the previous index files will be used. "
1523 "GPG error: %s: %s\n"),
1524 Desc
.Description
.c_str(),
1525 LookupTag(Message
,"Message").c_str());
1526 RunScripts("APT::Update::Auth-Failure");
1528 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1529 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1530 _error
->Error(_("GPG error: %s: %s"),
1531 Desc
.Description
.c_str(),
1532 LookupTag(Message
,"Message").c_str());
1536 _error
->Warning(_("GPG error: %s: %s"),
1537 Desc
.Description
.c_str(),
1538 LookupTag(Message
,"Message").c_str());
1540 // gpgv method failed
1541 ReportMirrorFailure("GPGFailure");
1545 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1546 // ---------------------------------------------------------------------
1548 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1549 pkgAcqMetaBase
*TransactionManager
,
1550 string URI
,string URIDesc
,string ShortDesc
,
1551 string MetaIndexFile
,
1552 const vector
<IndexTarget
*>* IndexTargets
,
1553 indexRecords
* MetaIndexParser
) :
1554 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1555 HashStringList(), TransactionManager
),
1556 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1557 ShortDesc(ShortDesc
)
1559 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1560 DestFile
+= URItoFileName(RealURI
);
1562 // remove any partial downloaded sig-file in partial/.
1563 // it may confuse proxies and is too small to warrant a
1564 // partial download anyway
1565 unlink(DestFile
.c_str());
1567 // set the TransactionManager
1568 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1569 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1570 << TransactionManager
<< std::endl
;
1573 Desc
.Description
= URIDesc
;
1575 Desc
.ShortDesc
= ShortDesc
;
1581 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1585 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1586 // ---------------------------------------------------------------------
1587 /* The only header we use is the last-modified header. */
1588 string
pkgAcqMetaSig::Custom600Headers() const
1590 string FinalFile
= _config
->FindDir("Dir::State::lists");
1591 FinalFile
+= URItoFileName(RealURI
);
1594 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1595 return "\nIndex-File: true";
1597 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1600 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1601 // ---------------------------------------------------------------------
1602 /* The only header we use is the last-modified header. */
1603 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1604 HashStringList
const &Hashes
,
1605 pkgAcquire::MethodConfig
*Cfg
)
1607 Item::Done(Message
, Size
, Hashes
, Cfg
);
1609 if(AuthPass
== false)
1611 if(CheckDownloadDone(Message
, RealURI
) == true)
1613 // destfile will be modified to point to MetaIndexFile for the
1614 // gpgv method, so we need to save it here
1615 MetaIndexFileSignature
= DestFile
;
1616 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1622 if(AuthDone(Message
, RealURI
) == true)
1624 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1625 FinalFile
+= URItoFileName(RealURI
);
1627 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1632 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1634 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1636 // FIXME: duplicated code from pkgAcqMetaIndex
1637 if (AuthPass
== true)
1639 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
1644 // FIXME: meh, this is not really elegant
1645 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1647 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1649 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1651 std::string downgrade_msg
;
1652 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1654 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1656 // meh, the users wants to take risks (we still mark the packages
1657 // from this repository as unauthenticated)
1658 _error
->Warning("%s", downgrade_msg
.c_str());
1659 _error
->Warning(_("This is normally not allowed, but the option "
1660 "Acquire::AllowDowngradeToInsecureRepositories was "
1661 "given to override it."));
1664 _error
->Error("%s", downgrade_msg
.c_str());
1665 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1666 Status
= pkgAcquire::Item::StatError
;
1667 TransactionManager
->AbortTransaction();
1672 // this ensures that any file in the lists/ dir is removed by the
1674 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1675 DestFile
+= URItoFileName(RealURI
);
1676 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1678 // only allow going further if the users explicitely wants it
1679 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
1681 // we parse the indexes here because at this point the user wanted
1682 // a repository that may potentially harm him
1683 MetaIndexParser
->Load(MetaIndexFile
);
1688 _error
->Warning("Use --allow-insecure-repositories to force the update");
1691 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1692 if (Cnf
->LocalOnly
== true ||
1693 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1701 Item::Failed(Message
,Cnf
);
1704 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1705 pkgAcqMetaBase
*TransactionManager
,
1706 string URI
,string URIDesc
,string ShortDesc
,
1707 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1708 const vector
<IndexTarget
*>* IndexTargets
,
1709 indexRecords
* MetaIndexParser
) :
1710 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1711 TransactionManager
),
1712 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1713 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1714 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1716 if(TransactionManager
== NULL
)
1718 this->TransactionManager
= this;
1719 this->TransactionManager
->Add(this);
1722 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1723 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1724 << this->TransactionManager
<< std::endl
;
1727 Init(URIDesc
, ShortDesc
);
1730 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1731 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1733 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1734 DestFile
+= URItoFileName(RealURI
);
1737 Desc
.Description
= URIDesc
;
1739 Desc
.ShortDesc
= ShortDesc
;
1742 // we expect more item
1743 ExpectedAdditionalItems
= IndexTargets
->size();
1746 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1747 // ---------------------------------------------------------------------
1748 /* The only header we use is the last-modified header. */
1749 string
pkgAcqMetaIndex::Custom600Headers() const
1751 string Final
= _config
->FindDir("Dir::State::lists");
1752 Final
+= URItoFileName(RealURI
);
1755 if (stat(Final
.c_str(),&Buf
) != 0)
1756 return "\nIndex-File: true";
1758 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1761 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1762 HashStringList
const &Hashes
,
1763 pkgAcquire::MethodConfig
*Cfg
)
1765 Item::Done(Message
,Size
,Hashes
,Cfg
);
1767 if(CheckDownloadDone(Message
, RealURI
))
1769 // we have a Release file, now download the Signature, all further
1770 // verify/queue for additional downloads will be done in the
1771 // pkgAcqMetaSig::Done() code
1772 std::string MetaIndexFile
= DestFile
;
1773 new pkgAcqMetaSig(Owner
, TransactionManager
,
1774 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1775 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1778 string FinalFile
= _config
->FindDir("Dir::State::lists");
1779 FinalFile
+= URItoFileName(RealURI
);
1780 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1784 bool pkgAcqMetaBase::AuthDone(string Message
, const string
&RealURI
) /*{{{*/
1786 // At this point, the gpgv method has succeeded, so there is a
1787 // valid signature from a key in the trusted keyring. We
1788 // perform additional verification of its contents, and use them
1789 // to verify the indexes we are about to download
1791 if (!MetaIndexParser
->Load(DestFile
))
1793 Status
= StatAuthError
;
1794 ErrorText
= MetaIndexParser
->ErrorText
;
1798 if (!VerifyVendor(Message
, RealURI
))
1803 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1804 std::cerr
<< "Signature verification succeeded: "
1805 << DestFile
<< std::endl
;
1807 // Download further indexes with verification
1809 // it would be really nice if we could simply do
1810 // if (IMSHit == false) QueueIndexes(true)
1811 // and skip the download if the Release file has not changed
1812 // - but right now the list cleaner will needs to be tricked
1813 // to not delete all our packages/source indexes in this case
1820 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1821 const std::string
&MetaIndexFileSignature
)
1824 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1825 DestFile
= MetaIndexFile
;
1827 SetActiveSubprocess("gpgv");
1831 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1832 const std::string
&RealURI
)
1834 // We have just finished downloading a Release file (it is not
1837 string FileName
= LookupTag(Message
,"Filename");
1838 if (FileName
.empty() == true)
1841 ErrorText
= "Method gave a blank filename";
1845 if (FileName
!= DestFile
)
1848 Desc
.URI
= "copy:" + FileName
;
1853 // make sure to verify against the right file on I-M-S hit
1854 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1857 string FinalFile
= _config
->FindDir("Dir::State::lists");
1858 FinalFile
+= URItoFileName(RealURI
);
1859 DestFile
= FinalFile
;
1862 // set Item to complete as the remaining work is all local (verify etc)
1868 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1870 bool transInRelease
= false;
1872 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1873 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1874 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1875 if (k
->find("Translation-") != std::string::npos
)
1877 transInRelease
= true;
1882 // at this point the real Items are loaded in the fetcher
1883 ExpectedAdditionalItems
= 0;
1884 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1885 Target
!= IndexTargets
->end();
1888 HashStringList ExpectedIndexHashes
;
1889 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1890 bool compressedAvailable
= false;
1893 if ((*Target
)->IsOptional() == true)
1895 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1896 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1897 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1899 compressedAvailable
= true;
1903 else if (verify
== true)
1905 Status
= StatAuthError
;
1906 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1912 ExpectedIndexHashes
= Record
->Hashes
;
1913 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1915 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1916 << "Expected Hash:" << std::endl
;
1917 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1918 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1919 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1921 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1923 Status
= StatAuthError
;
1924 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1929 if ((*Target
)->IsOptional() == true)
1931 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1933 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1934 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1935 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1937 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1942 /* Queue Packages file (either diff or full packages files, depending
1943 on the users option) - we also check if the PDiff Index file is listed
1944 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1945 instead, but passing the required info to it is to much hassle */
1946 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1947 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1948 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1950 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1954 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
1956 string::size_type pos
;
1958 // check for missing sigs (that where not fatal because otherwise we had
1961 string msg
= _("There is no public key available for the "
1962 "following key IDs:\n");
1963 pos
= Message
.find("NO_PUBKEY ");
1964 if (pos
!= std::string::npos
)
1966 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1967 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1968 missingkeys
+= (Fingerprint
);
1970 if(!missingkeys
.empty())
1971 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1973 string Transformed
= MetaIndexParser
->GetExpectedDist();
1975 if (Transformed
== "../project/experimental")
1977 Transformed
= "experimental";
1980 pos
= Transformed
.rfind('/');
1981 if (pos
!= string::npos
)
1983 Transformed
= Transformed
.substr(0, pos
);
1986 if (Transformed
== ".")
1991 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1992 MetaIndexParser
->GetValidUntil() > 0) {
1993 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1994 if (invalid_since
> 0)
1995 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1996 // the time since then the file is invalid - formated in the same way as in
1997 // the download progress display (e.g. 7d 3h 42min 1s)
1998 return _error
->Error(
1999 _("Release file for %s is expired (invalid since %s). "
2000 "Updates for this repository will not be applied."),
2001 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2004 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2006 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2007 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2008 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2011 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2013 // This might become fatal one day
2014 // Status = StatAuthError;
2015 // ErrorText = "Conflicting distribution; expected "
2016 // + MetaIndexParser->GetExpectedDist() + " but got "
2017 // + MetaIndexParser->GetDist();
2019 if (!Transformed
.empty())
2021 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2022 Desc
.Description
.c_str(),
2023 Transformed
.c_str(),
2024 MetaIndexParser
->GetDist().c_str());
2031 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
2032 // ---------------------------------------------------------------------
2034 void pkgAcqMetaIndex::Failed(string Message
,
2035 pkgAcquire::MethodConfig
* /*Cnf*/)
2037 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2039 if (AuthPass
== true)
2041 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
2046 _error
->Warning(_("The data from '%s' is not signed. Packages "
2047 "from that repository can not be authenticated."),
2050 // No Release file was present, or verification failed, so fall
2051 // back to queueing Packages files without verification
2052 // only allow going further if the users explicitely wants it
2053 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2055 /* Always move the meta index, even if gpgv failed. This ensures
2056 * that PackageFile objects are correctly filled in */
2057 if (FileExists(DestFile
))
2059 string FinalFile
= _config
->FindDir("Dir::State::lists");
2060 FinalFile
+= URItoFileName(RealURI
);
2061 /* InRelease files become Release files, otherwise
2062 * they would be considered as trusted later on */
2063 if (SigFile
== DestFile
) {
2064 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2066 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2068 SigFile
= FinalFile
;
2071 // Done, queue for rename on transaction finished
2072 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2075 QueueIndexes(false);
2077 // warn if the repository is unsinged
2078 _error
->Warning("Use --allow-insecure-repositories to force the update");
2079 TransactionManager
->AbortTransaction();
2087 void pkgAcqMetaIndex::Finished()
2089 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2090 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2091 if(TransactionManager
!= NULL
&&
2092 TransactionManager
->TransactionHasError() == false)
2093 TransactionManager
->CommitTransaction();
2097 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2098 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2099 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2100 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2101 const vector
<IndexTarget
*>* IndexTargets
,
2102 indexRecords
* MetaIndexParser
) :
2103 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2104 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2105 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2109 // index targets + (worst case:) Release/Release.gpg
2110 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2113 // keep the old InRelease around in case of transistent network errors
2114 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2115 if (RealFileExists(Final
) == true)
2117 string
const LastGoodSig
= DestFile
+ ".reverify";
2118 Rename(Final
,LastGoodSig
);
2123 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2126 // if the file was never queued undo file-changes done in the constructor
2127 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
2129 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2130 string
const LastGoodSig
= DestFile
+ ".reverify";
2131 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
2132 Rename(LastGoodSig
, Final
);
2137 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2138 // ---------------------------------------------------------------------
2139 // FIXME: this can go away once the InRelease file is used widely
2140 string
pkgAcqMetaClearSig::Custom600Headers() const
2142 string Final
= _config
->FindDir("Dir::State::lists");
2143 Final
+= URItoFileName(RealURI
);
2146 if (stat(Final
.c_str(),&Buf
) != 0)
2148 if (stat(Final
.c_str(),&Buf
) != 0)
2149 return "\nIndex-File: true\nFail-Ignore: true\n";
2152 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2155 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2156 // ---------------------------------------------------------------------
2157 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2158 HashStringList
const &Hashes
,
2159 pkgAcquire::MethodConfig
*Cnf
)
2161 // if we expect a ClearTextSignature (InRelase), ensure that
2162 // this is what we get and if not fail to queue a
2163 // Release/Release.gpg, see #346386
2164 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2166 pkgAcquire::Item::Failed(Message
, Cnf
);
2167 RenameOnError(NotClearsigned
);
2168 TransactionManager
->AbortTransaction();
2172 if(AuthPass
== false)
2174 if(CheckDownloadDone(Message
, RealURI
) == true)
2175 QueueForSignatureVerify(DestFile
, DestFile
);
2180 if(AuthDone(Message
, RealURI
) == true)
2182 string FinalFile
= _config
->FindDir("Dir::State::lists");
2183 FinalFile
+= URItoFileName(RealURI
);
2185 // queue for copy in place
2186 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2191 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2193 // we failed, we will not get additional items from this method
2194 ExpectedAdditionalItems
= 0;
2196 if (AuthPass
== false)
2198 // Queue the 'old' InRelease file for removal if we try Release.gpg
2199 // as otherwise the file will stay around and gives a false-auth
2200 // impression (CVE-2012-0214)
2201 string FinalFile
= _config
->FindDir("Dir::State::lists");
2202 FinalFile
.append(URItoFileName(RealURI
));
2203 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2205 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2206 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2207 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2208 IndexTargets
, MetaIndexParser
);
2209 if (Cnf
->LocalOnly
== true ||
2210 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2214 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2217 // AcqArchive::AcqArchive - Constructor /*{{{*/
2218 // ---------------------------------------------------------------------
2219 /* This just sets up the initial fetch environment and queues the first
2221 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2222 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2223 string
&StoreFilename
) :
2224 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2225 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2228 Retries
= _config
->FindI("Acquire::Retries",0);
2230 if (Version
.Arch() == 0)
2232 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2233 "This might mean you need to manually fix this package. "
2234 "(due to missing arch)"),
2235 Version
.ParentPkg().FullName().c_str());
2239 /* We need to find a filename to determine the extension. We make the
2240 assumption here that all the available sources for this version share
2241 the same extension.. */
2242 // Skip not source sources, they do not have file fields.
2243 for (; Vf
.end() == false; ++Vf
)
2245 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2250 // Does not really matter here.. we are going to fail out below
2251 if (Vf
.end() != true)
2253 // If this fails to get a file name we will bomb out below.
2254 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2255 if (_error
->PendingError() == true)
2258 // Generate the final file name as: package_version_arch.foo
2259 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2260 QuoteString(Version
.VerStr(),"_:") + '_' +
2261 QuoteString(Version
.Arch(),"_:.") +
2262 "." + flExtension(Parse
.FileName());
2265 // check if we have one trusted source for the package. if so, switch
2266 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2267 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2268 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2269 bool seenUntrusted
= false;
2270 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2272 pkgIndexFile
*Index
;
2273 if (Sources
->FindIndex(i
.File(),Index
) == false)
2276 if (debugAuth
== true)
2277 std::cerr
<< "Checking index: " << Index
->Describe()
2278 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2280 if (Index
->IsTrusted() == true)
2283 if (allowUnauth
== false)
2287 seenUntrusted
= true;
2290 // "allow-unauthenticated" restores apts old fetching behaviour
2291 // that means that e.g. unauthenticated file:// uris are higher
2292 // priority than authenticated http:// uris
2293 if (allowUnauth
== true && seenUntrusted
== true)
2297 if (QueueNext() == false && _error
->PendingError() == false)
2298 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2299 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2302 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2303 // ---------------------------------------------------------------------
2304 /* This queues the next available file version for download. It checks if
2305 the archive is already available in the cache and stashs the MD5 for
2307 bool pkgAcqArchive::QueueNext()
2309 for (; Vf
.end() == false; ++Vf
)
2311 // Ignore not source sources
2312 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2315 // Try to cross match against the source list
2316 pkgIndexFile
*Index
;
2317 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2320 // only try to get a trusted package from another source if that source
2322 if(Trusted
&& !Index
->IsTrusted())
2325 // Grab the text package record
2326 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2327 if (_error
->PendingError() == true)
2330 string PkgFile
= Parse
.FileName();
2331 ExpectedHashes
= Parse
.Hashes();
2333 if (PkgFile
.empty() == true)
2334 return _error
->Error(_("The package index files are corrupted. No Filename: "
2335 "field for package %s."),
2336 Version
.ParentPkg().Name());
2338 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2339 Desc
.Description
= Index
->ArchiveInfo(Version
);
2341 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2343 // See if we already have the file. (Legacy filenames)
2344 FileSize
= Version
->Size
;
2345 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2347 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2349 // Make sure the size matches
2350 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2355 StoreFilename
= DestFile
= FinalFile
;
2359 /* Hmm, we have a file and its size does not match, this means it is
2360 an old style mismatched arch */
2361 unlink(FinalFile
.c_str());
2364 // Check it again using the new style output filenames
2365 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2366 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2368 // Make sure the size matches
2369 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2374 StoreFilename
= DestFile
= FinalFile
;
2378 /* Hmm, we have a file and its size does not match, this shouldn't
2380 unlink(FinalFile
.c_str());
2383 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2385 // Check the destination file
2386 if (stat(DestFile
.c_str(),&Buf
) == 0)
2388 // Hmm, the partial file is too big, erase it
2389 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2390 unlink(DestFile
.c_str());
2392 PartialSize
= Buf
.st_size
;
2395 // Disables download of archives - useful if no real installation follows,
2396 // e.g. if we are just interested in proposed installation order
2397 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2402 StoreFilename
= DestFile
= FinalFile
;
2416 // AcqArchive::Done - Finished fetching /*{{{*/
2417 // ---------------------------------------------------------------------
2419 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2420 pkgAcquire::MethodConfig
*Cfg
)
2422 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2425 if (Size
!= Version
->Size
)
2427 RenameOnError(SizeMismatch
);
2431 // FIXME: could this empty() check impose *any* sort of security issue?
2432 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2434 RenameOnError(HashSumMismatch
);
2435 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2439 // Grab the output filename
2440 string FileName
= LookupTag(Message
,"Filename");
2441 if (FileName
.empty() == true)
2444 ErrorText
= "Method gave a blank filename";
2450 // Reference filename
2451 if (FileName
!= DestFile
)
2453 StoreFilename
= DestFile
= FileName
;
2458 // Done, move it into position
2459 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2460 FinalFile
+= flNotDir(StoreFilename
);
2461 Rename(DestFile
,FinalFile
);
2463 StoreFilename
= DestFile
= FinalFile
;
2467 // AcqArchive::Failed - Failure handler /*{{{*/
2468 // ---------------------------------------------------------------------
2469 /* Here we try other sources */
2470 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2472 ErrorText
= LookupTag(Message
,"Message");
2474 /* We don't really want to retry on failed media swaps, this prevents
2475 that. An interesting observation is that permanent failures are not
2477 if (Cnf
->Removable
== true &&
2478 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2480 // Vf = Version.FileList();
2481 while (Vf
.end() == false) ++Vf
;
2482 StoreFilename
= string();
2483 Item::Failed(Message
,Cnf
);
2487 if (QueueNext() == false)
2489 // This is the retry counter
2491 Cnf
->LocalOnly
== false &&
2492 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2495 Vf
= Version
.FileList();
2496 if (QueueNext() == true)
2500 StoreFilename
= string();
2501 Item::Failed(Message
,Cnf
);
2505 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2506 // ---------------------------------------------------------------------
2507 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2512 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2513 // ---------------------------------------------------------------------
2515 void pkgAcqArchive::Finished()
2517 if (Status
== pkgAcquire::Item::StatDone
&&
2520 StoreFilename
= string();
2523 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2524 // ---------------------------------------------------------------------
2525 /* The file is added to the queue */
2526 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2527 unsigned long long Size
,string Dsc
,string ShortDesc
,
2528 const string
&DestDir
, const string
&DestFilename
,
2530 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2532 Retries
= _config
->FindI("Acquire::Retries",0);
2534 if(!DestFilename
.empty())
2535 DestFile
= DestFilename
;
2536 else if(!DestDir
.empty())
2537 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2539 DestFile
= flNotDir(URI
);
2543 Desc
.Description
= Dsc
;
2546 // Set the short description to the archive component
2547 Desc
.ShortDesc
= ShortDesc
;
2549 // Get the transfer sizes
2552 if (stat(DestFile
.c_str(),&Buf
) == 0)
2554 // Hmm, the partial file is too big, erase it
2555 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2556 unlink(DestFile
.c_str());
2558 PartialSize
= Buf
.st_size
;
2564 // AcqFile::Done - Item downloaded OK /*{{{*/
2565 // ---------------------------------------------------------------------
2567 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2568 pkgAcquire::MethodConfig
*Cnf
)
2570 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2573 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2575 RenameOnError(HashSumMismatch
);
2576 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2580 string FileName
= LookupTag(Message
,"Filename");
2581 if (FileName
.empty() == true)
2584 ErrorText
= "Method gave a blank filename";
2590 // The files timestamp matches
2591 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2594 // We have to copy it into place
2595 if (FileName
!= DestFile
)
2598 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2599 Cnf
->Removable
== true)
2601 Desc
.URI
= "copy:" + FileName
;
2606 // Erase the file if it is a symlink so we can overwrite it
2608 if (lstat(DestFile
.c_str(),&St
) == 0)
2610 if (S_ISLNK(St
.st_mode
) != 0)
2611 unlink(DestFile
.c_str());
2615 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2617 ErrorText
= "Link to " + DestFile
+ " failure ";
2624 // AcqFile::Failed - Failure handler /*{{{*/
2625 // ---------------------------------------------------------------------
2626 /* Here we try other sources */
2627 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2629 ErrorText
= LookupTag(Message
,"Message");
2631 // This is the retry counter
2633 Cnf
->LocalOnly
== false &&
2634 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2641 Item::Failed(Message
,Cnf
);
2644 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2645 // ---------------------------------------------------------------------
2646 /* The only header we use is the last-modified header. */
2647 string
pkgAcqFile::Custom600Headers() const
2650 return "\nIndex-File: true";