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 // Acquire::Item::ReportMirrorFailure /*{{{*/
216 // ---------------------------------------------------------------------
217 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
219 // we only act if a mirror was used at all
220 if(UsedMirror
.empty())
223 std::cerr
<< "\nReportMirrorFailure: "
225 << " Uri: " << DescURI()
227 << FailCode
<< std::endl
;
229 const char *Args
[40];
231 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
232 "/usr/lib/apt/apt-report-mirror-failure");
233 if(!FileExists(report
))
235 Args
[i
++] = report
.c_str();
236 Args
[i
++] = UsedMirror
.c_str();
237 Args
[i
++] = DescURI().c_str();
238 Args
[i
++] = FailCode
.c_str();
240 pid_t pid
= ExecFork();
243 _error
->Error("ReportMirrorFailure Fork failed");
248 execvp(Args
[0], (char**)Args
);
249 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
252 if(!ExecWait(pid
, "report-mirror-failure"))
254 _error
->Warning("Couldn't report problem to '%s'",
255 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
259 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
260 // ---------------------------------------------------------------------
261 /* Get the DiffIndex file first and see if there are patches available
262 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
263 * patches. If anything goes wrong in that process, it will fall back to
264 * the original packages file
266 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
267 pkgAcqMetaBase
*TransactionManager
,
268 IndexTarget
const * const Target
,
269 HashStringList
const &ExpectedHashes
,
270 indexRecords
*MetaIndexParser
)
271 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
272 MetaIndexParser
), PackagesFileReadyInPartial(false)
275 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
277 RealURI
= Target
->URI
;
279 Desc
.Description
= Target
->Description
+ "/DiffIndex";
280 Desc
.ShortDesc
= Target
->ShortDesc
;
281 Desc
.URI
= Target
->URI
+ ".diff/Index";
283 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
284 DestFile
+= URItoFileName(Desc
.URI
);
287 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
289 // look for the current package file
290 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
291 CurrentPackagesFile
+= URItoFileName(RealURI
);
293 // FIXME: this file:/ check is a hack to prevent fetching
294 // from local sources. this is really silly, and
295 // should be fixed cleanly as soon as possible
296 if(!FileExists(CurrentPackagesFile
) ||
297 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
299 // we don't have a pkg file or we don't want to queue
301 std::clog
<< "No index file, local or canceld by user" << std::endl
;
307 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
308 << CurrentPackagesFile
<< std::endl
;
314 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
315 // ---------------------------------------------------------------------
316 /* The only header we use is the last-modified header. */
317 string
pkgAcqDiffIndex::Custom600Headers() const
319 string Final
= _config
->FindDir("Dir::State::lists");
320 Final
+= URItoFileName(Desc
.URI
);
323 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
326 if (stat(Final
.c_str(),&Buf
) != 0)
327 return "\nIndex-File: true";
329 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
332 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
335 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
340 vector
<DiffInfo
> available_patches
;
342 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
344 if (_error
->PendingError() == true)
347 if(TF
.Step(Tags
) == true)
353 string
const tmp
= Tags
.FindS("SHA1-Current");
354 std::stringstream
ss(tmp
);
355 ss
>> ServerSha1
>> size
;
356 unsigned long const ServerSize
= atol(size
.c_str());
358 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
361 string
const local_sha1
= SHA1
.Result();
363 if(local_sha1
== ServerSha1
)
365 // we have the same sha1 as the server so we are done here
367 std::clog
<< "Package file is up-to-date" << std::endl
;
368 // ensure we have no leftovers from previous runs
369 std::string Partial
= _config
->FindDir("Dir::State::lists");
370 Partial
+= "partial/" + URItoFileName(RealURI
);
371 unlink(Partial
.c_str());
372 // list cleanup needs to know that this file as well as the already
373 // present index is ours, so we create an empty diff to save it for us
374 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
375 ExpectedHashes
, MetaIndexParser
,
376 ServerSha1
, available_patches
);
382 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
384 // check the historie and see what patches we need
385 string
const history
= Tags
.FindS("SHA1-History");
386 std::stringstream
hist(history
);
387 while(hist
>> d
.sha1
>> size
>> d
.file
)
389 // read until the first match is found
390 // from that point on, we probably need all diffs
391 if(d
.sha1
== local_sha1
)
393 else if (found
== false)
397 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
398 available_patches
.push_back(d
);
401 if (available_patches
.empty() == false)
403 // patching with too many files is rather slow compared to a fast download
404 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
405 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
408 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
409 << ") so fallback to complete download" << std::endl
;
413 // see if the patches are too big
414 found
= false; // it was true and it will be true again at the end
415 d
= *available_patches
.begin();
416 string
const firstPatch
= d
.file
;
417 unsigned long patchesSize
= 0;
418 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
419 while(patches
>> d
.sha1
>> size
>> d
.file
)
421 if (firstPatch
== d
.file
)
423 else if (found
== false)
426 patchesSize
+= atol(size
.c_str());
428 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
429 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
432 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
433 << ") so fallback to complete download" << std::endl
;
439 // we have something, queue the next diff
442 // FIXME: make this use the method
443 PackagesFileReadyInPartial
= true;
444 std::string Partial
= _config
->FindDir("Dir::State::lists");
445 Partial
+= "partial/" + URItoFileName(RealURI
);
447 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
448 FileFd
To(Partial
, FileFd::WriteEmpty
);
449 if(CopyFile(From
, To
) == false)
450 return _error
->Errno("CopyFile", "failed to copy");
453 std::cerr
<< "Done copying " << CurrentPackagesFile
458 string::size_type
const last_space
= Description
.rfind(" ");
459 if(last_space
!= string::npos
)
460 Description
.erase(last_space
, Description
.size()-last_space
);
462 /* decide if we should download patches one by one or in one go:
463 The first is good if the server merges patches, but many don't so client
464 based merging can be attempt in which case the second is better.
465 "bad things" will happen if patches are merged on the server,
466 but client side merging is attempt as well */
467 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
468 if (pdiff_merge
== true)
470 // reprepro adds this flag if it has merged patches on the server
471 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
472 pdiff_merge
= (precedence
!= "merged");
475 if (pdiff_merge
== false)
477 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
479 ServerSha1
, available_patches
);
483 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
484 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
485 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
,
490 available_patches
[i
],
501 // Nothing found, report and return false
502 // Failing here is ok, if we return false later, the full
503 // IndexFile is queued
505 std::clog
<< "Can't find a patch in the index file" << std::endl
;
509 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
512 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
513 << "Falling back to normal index file acquire" << std::endl
;
515 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
522 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
523 pkgAcquire::MethodConfig
*Cnf
)
526 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
528 Item::Done(Message
, Size
, Hashes
, Cnf
);
531 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
533 // success in downloading the index
535 FinalFile
+= string(".IndexDiff");
537 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
539 Rename(DestFile
,FinalFile
);
540 chmod(FinalFile
.c_str(),0644);
541 DestFile
= FinalFile
;
543 if(!ParseDiffIndex(DestFile
))
544 return Failed("", NULL
);
552 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
553 // ---------------------------------------------------------------------
554 /* The package diff is added to the queue. one object is constructed
555 * for each diff and the index
557 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
558 pkgAcqMetaBase
*TransactionManager
,
559 struct IndexTarget
const * const Target
,
560 HashStringList
const &ExpectedHashes
,
561 indexRecords
*MetaIndexParser
,
563 vector
<DiffInfo
> diffs
)
564 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
565 available_patches(diffs
), ServerSha1(ServerSha1
)
568 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
569 DestFile
+= URItoFileName(Target
->URI
);
571 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
573 RealURI
= Target
->URI
;
575 Description
= Target
->Description
;
576 Desc
.ShortDesc
= Target
->ShortDesc
;
578 if(available_patches
.empty() == true)
580 // we are done (yeah!), check hashes against the final file
581 DestFile
= _config
->FindDir("Dir::State::lists");
582 DestFile
+= URItoFileName(Target
->URI
);
588 State
= StateFetchDiff
;
593 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
596 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
597 << "Falling back to normal index file acquire" << std::endl
;
598 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
602 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
603 void pkgAcqIndexDiffs::Finish(bool allDone
)
606 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
608 << Desc
.URI
<< std::endl
;
610 // we restore the original name, this is required, otherwise
611 // the file will be cleaned
614 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
616 RenameOnError(HashSumMismatch
);
622 PartialFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
624 DestFile
= _config
->FindDir("Dir::State::lists");
625 DestFile
+= URItoFileName(RealURI
);
627 // this happens if we have a up-to-date indexfile
628 if(!FileExists(PartialFile
))
629 PartialFile
= DestFile
;
631 TransactionManager
->TransactionStageCopy(this, PartialFile
, DestFile
);
633 // this is for the "real" finish
638 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
643 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
650 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
652 // calc sha1 of the just patched file
653 string FinalFile
= _config
->FindDir("Dir::State::lists");
654 FinalFile
+= "partial/" + URItoFileName(RealURI
);
656 if(!FileExists(FinalFile
))
658 Failed("No FinalFile " + FinalFile
+ " available", NULL
);
662 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
665 string local_sha1
= string(SHA1
.Result());
667 std::clog
<< "QueueNextDiff: "
668 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
671 // final file reached before all patches are applied
672 if(local_sha1
== ServerSha1
)
678 // remove all patches until the next matching patch is found
679 // this requires the Index file to be ordered
680 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
681 available_patches
.empty() == false &&
682 I
!= available_patches
.end() &&
683 I
->sha1
!= local_sha1
;
686 available_patches
.erase(I
);
689 // error checking and falling back if no patch was found
690 if(available_patches
.empty() == true)
692 Failed("No patches available", NULL
);
696 // queue the right diff
697 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
698 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
699 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
700 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
703 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
710 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
711 pkgAcquire::MethodConfig
*Cnf
)
714 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
716 Item::Done(Message
, Size
, Hashes
, Cnf
);
719 FinalFile
= _config
->FindDir("Dir::State::lists")+"partial/"+URItoFileName(RealURI
);
721 // success in downloading a diff, enter ApplyDiff state
722 if(State
== StateFetchDiff
)
725 // rred excepts the patch as $FinalFile.ed
726 Rename(DestFile
,FinalFile
+".ed");
729 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
731 State
= StateApplyDiff
;
733 Desc
.URI
= "rred:" + FinalFile
;
735 ActiveSubprocess
= "rred";
737 #pragma GCC diagnostic push
738 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
742 #pragma GCC diagnostic pop
748 // success in download/apply a diff, queue next (if needed)
749 if(State
== StateApplyDiff
)
751 // remove the just applied patch
752 available_patches
.erase(available_patches
.begin());
753 unlink((FinalFile
+ ".ed").c_str());
758 std::clog
<< "Moving patched file in place: " << std::endl
759 << DestFile
<< " -> " << FinalFile
<< std::endl
;
761 Rename(DestFile
,FinalFile
);
762 chmod(FinalFile
.c_str(),0644);
764 // see if there is more to download
765 if(available_patches
.empty() == false) {
766 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
767 ExpectedHashes
, MetaIndexParser
,
768 ServerSha1
, available_patches
);
772 DestFile
= FinalFile
;
777 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
778 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
779 pkgAcqMetaBase
*TransactionManager
,
780 struct IndexTarget
const * const Target
,
781 HashStringList
const &ExpectedHashes
,
782 indexRecords
*MetaIndexParser
,
783 DiffInfo
const &patch
,
784 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
785 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
786 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
789 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
790 DestFile
+= URItoFileName(Target
->URI
);
792 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
794 RealURI
= Target
->URI
;
796 Description
= Target
->Description
;
797 Desc
.ShortDesc
= Target
->ShortDesc
;
799 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
800 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
801 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
802 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
805 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
810 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
813 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
818 // check if we are the first to fail, otherwise we are done here
819 State
= StateDoneDiff
;
820 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
821 I
!= allPatches
->end(); ++I
)
822 if ((*I
)->State
== StateErrorDiff
)
825 // first failure means we should fallback
826 State
= StateErrorDiff
;
827 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
828 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
831 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
832 pkgAcquire::MethodConfig
*Cnf
)
835 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
837 Item::Done(Message
,Size
,Hashes
,Cnf
);
839 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + "partial/" + URItoFileName(RealURI
);
841 if (State
== StateFetchDiff
)
843 // rred expects the patch as $FinalFile.ed.$patchname.gz
844 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
846 // check if this is the last completed diff
847 State
= StateDoneDiff
;
848 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
849 I
!= allPatches
->end(); ++I
)
850 if ((*I
)->State
!= StateDoneDiff
)
853 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
857 // this is the last completed diff, so we are ready to apply now
858 State
= StateApplyDiff
;
861 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
864 Desc
.URI
= "rred:" + FinalFile
;
866 ActiveSubprocess
= "rred";
868 #pragma GCC diagnostic push
869 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
873 #pragma GCC diagnostic pop
877 // success in download/apply all diffs, clean up
878 else if (State
== StateApplyDiff
)
880 // see if we really got the expected file
881 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
883 RenameOnError(HashSumMismatch
);
888 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
889 FinalFile
+= URItoFileName(RealURI
);
891 // move the result into place
893 std::clog
<< "Queue patched file in place: " << std::endl
894 << DestFile
<< " -> " << FinalFile
<< std::endl
;
896 // queue for copy by the transaction manager
897 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
899 // ensure the ed's are gone regardless of list-cleanup
900 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
901 I
!= allPatches
->end(); ++I
)
903 std::string PartialFile
= _config
->FindDir("Dir::State::lists");
904 PartialFile
+= "partial/" + URItoFileName(RealURI
);
905 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
906 std::cerr
<< patch
<< std::endl
;
907 unlink(patch
.c_str());
913 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
917 // AcqIndex::AcqIndex - Constructor /*{{{*/
918 // ---------------------------------------------------------------------
919 /* The package file is added to the queue and a second class is
920 instantiated to fetch the revision file */
921 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
922 string URI
,string URIDesc
,string ShortDesc
,
923 HashStringList
const &ExpectedHash
)
924 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
), RealURI(URI
)
926 AutoSelectCompression();
927 Init(URI
, URIDesc
, ShortDesc
);
929 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
930 std::clog
<< "New pkgIndex with TransactionManager "
931 << TransactionManager
<< std::endl
;
934 // AcqIndex::AcqIndex - Constructor /*{{{*/
935 // ---------------------------------------------------------------------
936 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
937 pkgAcqMetaBase
*TransactionManager
,
938 IndexTarget
const *Target
,
939 HashStringList
const &ExpectedHash
,
940 indexRecords
*MetaIndexParser
)
941 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
942 MetaIndexParser
), RealURI(Target
->URI
)
944 // autoselect the compression method
945 AutoSelectCompression();
946 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
948 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
949 std::clog
<< "New pkgIndex with TransactionManager "
950 << TransactionManager
<< std::endl
;
953 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
954 // ---------------------------------------------------------------------
955 void pkgAcqIndex::AutoSelectCompression()
957 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
958 CompressionExtension
= "";
959 if (ExpectedHashes
.usable())
961 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
962 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
963 CompressionExtension
.append(*t
).append(" ");
967 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
968 CompressionExtension
.append(*t
).append(" ");
970 if (CompressionExtension
.empty() == false)
971 CompressionExtension
.erase(CompressionExtension
.end()-1);
973 // AcqIndex::Init - defered Constructor /*{{{*/
974 // ---------------------------------------------------------------------
975 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
976 string
const &ShortDesc
)
978 Decompression
= false;
981 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
982 DestFile
+= URItoFileName(URI
);
984 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
985 if (comprExt
== "uncompressed")
989 MetaKey
= string(Target
->MetaKey
);
993 Desc
.URI
= URI
+ '.' + comprExt
;
994 DestFile
= DestFile
+ '.' + comprExt
;
996 MetaKey
= string(Target
->MetaKey
) + '.' + comprExt
;
1002 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1004 FileSize
= Record
->Size
;
1006 InitByHashIfNeeded(MetaKey
);
1009 Desc
.Description
= URIDesc
;
1011 Desc
.ShortDesc
= ShortDesc
;
1016 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1017 // ---------------------------------------------------------------------
1019 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1022 // - (maybe?) add support for by-hash into the sources.list as flag
1023 // - make apt-ftparchive generate the hashes (and expire?)
1024 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1025 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1026 _config
->FindB(HostKnob
, false) == true ||
1027 MetaIndexParser
->GetSupportsAcquireByHash())
1029 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1032 // FIXME: should we really use the best hash here? or a fixed one?
1033 const HashString
*TargetHash
= Record
->Hashes
.find("");
1034 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1035 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1036 Desc
.URI
= Desc
.URI
.replace(
1038 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1042 "Fetching ByHash requested but can not find record for %s",
1048 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1049 // ---------------------------------------------------------------------
1050 /* The only header we use is the last-modified header. */
1051 string
pkgAcqIndex::Custom600Headers() const
1053 string Final
= GetFinalFilename();
1055 string msg
= "\nIndex-File: true";
1057 if (stat(Final
.c_str(),&Buf
) == 0)
1058 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1063 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1064 // ---------------------------------------------------------------------
1066 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1068 size_t const nextExt
= CompressionExtension
.find(' ');
1069 if (nextExt
!= std::string::npos
)
1071 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1072 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1076 // on decompression failure, remove bad versions in partial/
1077 if (Decompression
&& Erase
) {
1078 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1079 s
.append(URItoFileName(RealURI
));
1083 Item::Failed(Message
,Cnf
);
1085 /// cancel the entire transaction
1086 TransactionManager
->AbortTransaction();
1089 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1090 // ---------------------------------------------------------------------
1092 std::string
pkgAcqIndex::GetFinalFilename() const
1094 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1095 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1096 FinalFile
+= URItoFileName(RealURI
);
1097 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1098 FinalFile
+= '.' + compExt
;
1102 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1103 // ---------------------------------------------------------------------
1105 void pkgAcqIndex::ReverifyAfterIMS()
1107 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1109 // update destfile to *not* include the compression extension when doing
1110 // a reverify (as its uncompressed on disk already)
1111 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1112 DestFile
+= URItoFileName(RealURI
);
1114 // adjust DestFile if its compressed on disk
1115 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1116 DestFile
+= '.' + compExt
;
1118 // copy FinalFile into partial/ so that we check the hash again
1119 string FinalFile
= GetFinalFilename();
1120 Decompression
= true;
1121 Desc
.URI
= "copy:" + FinalFile
;
1125 // AcqIndex::Done - Finished a fetch /*{{{*/
1126 // ---------------------------------------------------------------------
1127 /* This goes through a number of states.. On the initial fetch the
1128 method could possibly return an alternate filename which points
1129 to the uncompressed version of the file. If this is so the file
1130 is copied into the partial directory. In all other cases the file
1131 is decompressed with a compressed uri. */
1132 void pkgAcqIndex::Done(string Message
, unsigned long long Size
,
1133 HashStringList
const &Hashes
,
1134 pkgAcquire::MethodConfig
*Cfg
)
1136 Item::Done(Message
,Size
,Hashes
,Cfg
);
1137 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1139 if (Decompression
== true)
1141 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1144 RenameOnError(HashSumMismatch
);
1145 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1146 Failed(Message
, Cfg
);
1150 // FIXME: this can go away once we only ever download stuff that
1151 // has a valid hash and we never do GET based probing
1153 /* Always verify the index file for correctness (all indexes must
1154 * have a Package field) (LP: #346386) (Closes: #627642)
1156 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Extension
);
1157 // Only test for correctness if the content of the file is not empty
1162 pkgTagFile
tag(&fd
);
1164 // all our current indexes have a field 'Package' in each section
1165 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1167 RenameOnError(InvalidFormat
);
1168 Failed(Message
, Cfg
);
1173 // FIXME: can we void the "Erase" bool here as its very non-local?
1174 std::string CompressedFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1175 CompressedFile
+= URItoFileName(RealURI
);
1177 // Remove the compressed version.
1179 unlink(CompressedFile
.c_str());
1181 // Done, queue for rename on transaction finished
1182 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1187 // FIXME: use the same method to find
1188 // check the compressed hash too
1189 if(MetaKey
!= "" && Hashes
.size() > 0)
1191 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1192 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1194 RenameOnError(HashSumMismatch
);
1195 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1196 Failed(Message
, Cfg
);
1204 // Handle the unzipd case
1205 string FileName
= LookupTag(Message
,"Alt-Filename");
1206 if (FileName
.empty() == false)
1208 Decompression
= true;
1210 DestFile
+= ".decomp";
1211 Desc
.URI
= "copy:" + FileName
;
1213 ActiveSubprocess
= "copy";
1215 #pragma GCC diagnostic push
1216 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1220 #pragma GCC diagnostic pop
1225 FileName
= LookupTag(Message
,"Filename");
1226 if (FileName
.empty() == true)
1229 ErrorText
= "Method gave a blank filename";
1232 if (FileName
== DestFile
)
1237 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1238 // file when its doing the indexcopy
1239 if (RealURI
.substr(0,6) == "cdrom:" &&
1240 StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1243 // The files timestamp matches, reverify by copy into partial/
1244 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1249 // set destfile to the final destfile
1250 if(_config
->FindB("Acquire::GzipIndexes",false) == false)
1252 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1253 DestFile
+= URItoFileName(RealURI
);
1256 ReverifyAfterIMS(FileName
);
1262 // If we enable compressed indexes, queue for hash verification
1263 if (_config
->FindB("Acquire::GzipIndexes",false))
1265 DestFile
= _config
->FindDir("Dir::State::lists");
1266 DestFile
+= URItoFileName(RealURI
) + '.' + compExt
;
1268 Decompression
= true;
1269 Desc
.URI
= "copy:" + FileName
;
1275 // get the binary name for your used compression type
1276 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1277 if(decompProg
.empty() == false);
1278 else if(compExt
== "uncompressed")
1279 decompProg
= "copy";
1281 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1285 Decompression
= true;
1286 DestFile
+= ".decomp";
1287 Desc
.URI
= decompProg
+ ":" + FileName
;
1290 ActiveSubprocess
= decompProg
;
1292 #pragma GCC diagnostic push
1293 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1295 Mode
= ActiveSubprocess
.c_str();
1297 #pragma GCC diagnostic pop
1301 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1302 // ---------------------------------------------------------------------
1303 /* The Translation file is added to the queue */
1304 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1305 string URI
,string URIDesc
,string ShortDesc
)
1306 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1310 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1311 pkgAcqMetaBase
*TransactionManager
,
1312 IndexTarget
const * const Target
,
1313 HashStringList
const &ExpectedHashes
,
1314 indexRecords
*MetaIndexParser
)
1315 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1317 // load the filesize
1318 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1320 FileSize
= Record
->Size
;
1323 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1324 // ---------------------------------------------------------------------
1325 string
pkgAcqIndexTrans::Custom600Headers() const
1327 string Final
= GetFinalFilename();
1330 if (stat(Final
.c_str(),&Buf
) != 0)
1331 return "\nFail-Ignore: true\nIndex-File: true";
1332 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1335 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1336 // ---------------------------------------------------------------------
1338 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1340 size_t const nextExt
= CompressionExtension
.find(' ');
1341 if (nextExt
!= std::string::npos
)
1343 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1344 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1349 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1350 if (Cnf
->LocalOnly
== true ||
1351 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1360 Item::Failed(Message
,Cnf
);
1364 void pkgAcqMetaBase::Add(Item
*I
)
1366 Transaction
.push_back(I
);
1369 void pkgAcqMetaBase::AbortTransaction()
1371 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1372 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1374 // ensure the toplevel is in error state too
1375 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1376 I
!= Transaction
.end(); ++I
)
1378 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1379 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1380 // the transaction will abort, so stop anything that is idle
1381 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1382 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1386 bool pkgAcqMetaBase::TransactionHasError()
1388 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1389 I
!= Transaction
.end(); ++I
)
1390 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1391 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1396 // Acquire::CommitTransaction - Commit a transaction /*{{{*/
1397 void pkgAcqMetaBase::CommitTransaction()
1399 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1400 std::clog
<< "CommitTransaction: " << this << std::endl
;
1402 // move new files into place *and* remove files that are not
1403 // part of the transaction but are still on disk
1404 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1405 I
!= Transaction
.end(); ++I
)
1407 if((*I
)->PartialFile
!= "")
1409 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1411 << (*I
)->PartialFile
<< " -> "
1412 << (*I
)->DestFile
<< " "
1415 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1416 chmod((*I
)->DestFile
.c_str(),0644);
1418 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1424 unlink((*I
)->DestFile
.c_str());
1426 // mark that this transaction is finished
1427 (*I
)->TransactionManager
= 0;
1431 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1432 const std::string
&From
,
1433 const std::string
&To
)
1435 I
->PartialFile
= From
;
1439 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1440 const std::string
&FinalFile
)
1442 I
->PartialFile
= "";
1443 I
->DestFile
= FinalFile
;
1448 bool pkgAcqMetaBase::GenerateAuthWarning(const std::string
&RealURI
,
1449 const std::string
&Message
)
1451 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1453 if(FileExists(Final
))
1455 Status
= StatTransientNetworkError
;
1456 _error
->Warning(_("An error occurred during the signature "
1457 "verification. The repository is not updated "
1458 "and the previous index files will be used. "
1459 "GPG error: %s: %s\n"),
1460 Desc
.Description
.c_str(),
1461 LookupTag(Message
,"Message").c_str());
1462 RunScripts("APT::Update::Auth-Failure");
1464 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1465 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1466 _error
->Error(_("GPG error: %s: %s"),
1467 Desc
.Description
.c_str(),
1468 LookupTag(Message
,"Message").c_str());
1472 _error
->Warning(_("GPG error: %s: %s"),
1473 Desc
.Description
.c_str(),
1474 LookupTag(Message
,"Message").c_str());
1476 // gpgv method failed
1477 ReportMirrorFailure("GPGFailure");
1483 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1484 pkgAcqMetaBase
*TransactionManager
,
1485 string URI
,string URIDesc
,string ShortDesc
,
1486 string MetaIndexFile
,
1487 const vector
<IndexTarget
*>* IndexTargets
,
1488 indexRecords
* MetaIndexParser
) :
1489 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1490 HashStringList(), TransactionManager
),
1491 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1492 ShortDesc(ShortDesc
)
1494 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1495 DestFile
+= URItoFileName(URI
);
1497 // remove any partial downloaded sig-file in partial/.
1498 // it may confuse proxies and is too small to warrant a
1499 // partial download anyway
1500 unlink(DestFile
.c_str());
1502 // set the TransactionManager
1503 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1504 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1505 << TransactionManager
<< std::endl
;
1508 Desc
.Description
= URIDesc
;
1510 Desc
.ShortDesc
= ShortDesc
;
1516 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1520 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1521 // ---------------------------------------------------------------------
1522 /* The only header we use is the last-modified header. */
1523 string
pkgAcqMetaSig::Custom600Headers() const
1525 string FinalFile
= _config
->FindDir("Dir::State::lists");
1526 FinalFile
+= URItoFileName(RealURI
);
1529 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1530 return "\nIndex-File: true";
1532 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1535 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
,
1536 pkgAcquire::MethodConfig
*Cfg
)
1538 Item::Done(Message
, Size
, Hashes
, Cfg
);
1540 string FileName
= LookupTag(Message
,"Filename");
1541 if (FileName
.empty() == true)
1544 ErrorText
= "Method gave a blank filename";
1548 if (FileName
!= DestFile
)
1550 // We have to copy it into place
1552 Desc
.URI
= "copy:" + FileName
;
1557 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1560 // adjust paths if its a ims-hit
1563 string FinalFile
= _config
->FindDir("Dir::State::lists");
1564 FinalFile
+= URItoFileName(RealURI
);
1566 TransactionManager
->TransactionStageCopy(this, FinalFile
, FinalFile
);
1570 if(AuthPass
== false)
1573 Desc
.URI
= "gpgv:" + DestFile
;
1574 DestFile
= MetaIndexFile
;
1579 // queue to copy the file in place if it was not a ims hit, on ims
1580 // hit the file is already at the right place
1583 PartialFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1584 PartialFile
+= URItoFileName(RealURI
);
1586 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1587 FinalFile
+= URItoFileName(RealURI
);
1589 TransactionManager
->TransactionStageCopy(this, PartialFile
, FinalFile
);
1592 // we parse the MetaIndexFile here because at this point we can
1594 if(AuthPass
== true)
1596 // load indexes and queue further downloads
1597 MetaIndexParser
->Load(MetaIndexFile
);
1604 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1606 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1608 // FIXME: meh, this is not really elegant
1609 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1611 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1613 if(RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1615 _error
->Error("The repository '%s' is no longer signed.",
1617 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1618 Status
= pkgAcquire::Item::StatError
;
1619 TransactionManager
->AbortTransaction();
1623 // this ensures that any file in the lists/ dir is removed by the
1625 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1626 DestFile
+= URItoFileName(RealURI
);
1627 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1629 // FIXME: duplicated code from pkgAcqMetaIndex
1630 if (AuthPass
== true)
1632 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
1637 // only allow going further if the users explicitely wants it
1638 if(_config
->FindB("APT::Get::AllowUnauthenticated", false) == true)
1640 // we parse the indexes here because at this point the user wanted
1641 // a repository that may potentially harm him
1642 MetaIndexParser
->Load(MetaIndexFile
);
1647 _error
->Warning("Use --allow-unauthenticated to force the update");
1650 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1651 if (Cnf
->LocalOnly
== true ||
1652 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1660 Item::Failed(Message
,Cnf
);
1663 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1664 pkgAcqMetaBase
*TransactionManager
,
1665 string URI
,string URIDesc
,string ShortDesc
,
1666 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1667 const vector
<IndexTarget
*>* IndexTargets
,
1668 indexRecords
* MetaIndexParser
) :
1669 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1670 TransactionManager
),
1671 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1672 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1673 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1675 if(TransactionManager
== NULL
)
1677 this->TransactionManager
= this;
1678 this->TransactionManager
->Add(this);
1681 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1682 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1683 << this->TransactionManager
<< std::endl
;
1686 Init(URIDesc
, ShortDesc
);
1689 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1690 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1692 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1693 DestFile
+= URItoFileName(RealURI
);
1696 Desc
.Description
= URIDesc
;
1698 Desc
.ShortDesc
= ShortDesc
;
1701 // we expect more item
1702 ExpectedAdditionalItems
= IndexTargets
->size();
1705 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1706 // ---------------------------------------------------------------------
1707 /* The only header we use is the last-modified header. */
1708 string
pkgAcqMetaIndex::Custom600Headers() const
1710 string Final
= _config
->FindDir("Dir::State::lists");
1711 Final
+= URItoFileName(RealURI
);
1714 if (stat(Final
.c_str(),&Buf
) != 0)
1715 return "\nIndex-File: true";
1717 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1720 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1721 pkgAcquire::MethodConfig
*Cfg
)
1723 Item::Done(Message
,Size
,Hashes
,Cfg
);
1725 // MetaIndexes are done in two passes: one to download the
1726 // metaindex with an appropriate method, and a second to verify it
1727 // with the gpgv method
1729 if (AuthPass
== true)
1733 // all cool, move Release file into place
1738 RetrievalDone(Message
);
1740 // Still more retrieving to do
1745 // There was a signature file, so pass it to gpgv for
1747 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1748 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1749 << SigFile
<< "," << DestFile
<< ")\n";
1751 Desc
.URI
= "gpgv:" + SigFile
;
1753 ActiveSubprocess
= "gpgv";
1755 #pragma GCC diagnostic push
1756 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
1760 #pragma GCC diagnostic pop
1766 if (Complete
== true)
1768 string FinalFile
= _config
->FindDir("Dir::State::lists");
1769 FinalFile
+= URItoFileName(RealURI
);
1770 if (SigFile
== DestFile
)
1771 SigFile
= FinalFile
;
1773 // queue for copy in place
1774 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1778 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1780 // We have just finished downloading a Release file (it is not
1783 string FileName
= LookupTag(Message
,"Filename");
1784 if (FileName
.empty() == true)
1787 ErrorText
= "Method gave a blank filename";
1791 if (FileName
!= DestFile
)
1794 Desc
.URI
= "copy:" + FileName
;
1799 // make sure to verify against the right file on I-M-S hit
1800 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1803 string FinalFile
= _config
->FindDir("Dir::State::lists");
1804 FinalFile
+= URItoFileName(RealURI
);
1805 if (SigFile
== DestFile
)
1807 SigFile
= FinalFile
;
1809 // constructor of pkgAcqMetaClearSig moved it out of the way,
1810 // now move it back in on IMS hit for the 'old' file
1811 string
const OldClearSig
= DestFile
+ ".reverify";
1812 if (RealFileExists(OldClearSig
) == true)
1813 Rename(OldClearSig
, FinalFile
);
1816 DestFile
= FinalFile
;
1819 // queue a signature
1820 if(SigFile
!= DestFile
)
1821 new pkgAcqMetaSig(Owner
, TransactionManager
,
1822 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1823 MetaIndexSigShortDesc
, DestFile
, IndexTargets
,
1829 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1831 // At this point, the gpgv method has succeeded, so there is a
1832 // valid signature from a key in the trusted keyring. We
1833 // perform additional verification of its contents, and use them
1834 // to verify the indexes we are about to download
1836 if (!MetaIndexParser
->Load(DestFile
))
1838 Status
= StatAuthError
;
1839 ErrorText
= MetaIndexParser
->ErrorText
;
1843 if (!VerifyVendor(Message
))
1848 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1849 std::cerr
<< "Signature verification succeeded: "
1850 << DestFile
<< std::endl
;
1852 // we ensure this by other means
1854 // do not trust any previously unverified content that we may have
1855 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1856 if (DestFile
!= SigFile
)
1857 LastGoodSigFile
.append(".gpg");
1858 LastGoodSigFile
.append(".reverify");
1859 if(IMSHit
== false && RealFileExists(LastGoodSigFile
) == false)
1861 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1862 Target
!= IndexTargets
->end();
1865 // remove old indexes
1866 std::string index
= _config
->FindDir("Dir::State::lists") +
1867 URItoFileName((*Target
)->URI
);
1868 unlink(index
.c_str());
1869 // and also old gzipindexes
1870 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1871 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1873 index
+= '.' + (*t
);
1874 unlink(index
.c_str());
1880 // Download further indexes with verification
1882 // it would be really nice if we could simply do
1883 // if (IMSHit == false) QueueIndexes(true)
1884 // and skip the download if the Release file has not changed
1885 // - but right now the list cleaner will needs to be tricked
1886 // to not delete all our packages/source indexes in this case
1890 // is it a clearsigned MetaIndex file?
1891 if (DestFile
== SigFile
)
1894 // Done, move signature file into position
1895 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1896 URItoFileName(RealURI
) + ".gpg";
1897 Rename(SigFile
,VerifiedSigFile
);
1898 chmod(VerifiedSigFile
.c_str(),0644);
1902 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1904 bool transInRelease
= false;
1906 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1907 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1908 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1909 if (k
->find("Translation-") != std::string::npos
)
1911 transInRelease
= true;
1916 // at this point the real Items are loaded in the fetcher
1917 ExpectedAdditionalItems
= 0;
1918 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1919 Target
!= IndexTargets
->end();
1922 HashStringList ExpectedIndexHashes
;
1923 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1924 bool compressedAvailable
= false;
1927 if ((*Target
)->IsOptional() == true)
1929 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1930 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1931 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1933 compressedAvailable
= true;
1937 else if (verify
== true)
1939 Status
= StatAuthError
;
1940 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1946 ExpectedIndexHashes
= Record
->Hashes
;
1947 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1949 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1950 << "Expected Hash:" << std::endl
;
1951 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1952 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1953 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1955 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1957 Status
= StatAuthError
;
1958 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1963 if ((*Target
)->IsOptional() == true)
1965 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1967 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1968 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1969 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1971 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1976 /* Queue Packages file (either diff or full packages files, depending
1977 on the users option) - we also check if the PDiff Index file is listed
1978 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1979 instead, but passing the required info to it is to much hassle */
1980 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1981 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1982 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1984 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1988 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1990 string::size_type pos
;
1992 // check for missing sigs (that where not fatal because otherwise we had
1995 string msg
= _("There is no public key available for the "
1996 "following key IDs:\n");
1997 pos
= Message
.find("NO_PUBKEY ");
1998 if (pos
!= std::string::npos
)
2000 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2001 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2002 missingkeys
+= (Fingerprint
);
2004 if(!missingkeys
.empty())
2005 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2007 string Transformed
= MetaIndexParser
->GetExpectedDist();
2009 if (Transformed
== "../project/experimental")
2011 Transformed
= "experimental";
2014 pos
= Transformed
.rfind('/');
2015 if (pos
!= string::npos
)
2017 Transformed
= Transformed
.substr(0, pos
);
2020 if (Transformed
== ".")
2025 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2026 MetaIndexParser
->GetValidUntil() > 0) {
2027 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2028 if (invalid_since
> 0)
2029 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2030 // the time since then the file is invalid - formated in the same way as in
2031 // the download progress display (e.g. 7d 3h 42min 1s)
2032 return _error
->Error(
2033 _("Release file for %s is expired (invalid since %s). "
2034 "Updates for this repository will not be applied."),
2035 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2038 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2040 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2041 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2042 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2045 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2047 // This might become fatal one day
2048 // Status = StatAuthError;
2049 // ErrorText = "Conflicting distribution; expected "
2050 // + MetaIndexParser->GetExpectedDist() + " but got "
2051 // + MetaIndexParser->GetDist();
2053 if (!Transformed
.empty())
2055 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2056 Desc
.Description
.c_str(),
2057 Transformed
.c_str(),
2058 MetaIndexParser
->GetDist().c_str());
2065 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
2066 // ---------------------------------------------------------------------
2068 void pkgAcqMetaIndex::Failed(string Message
,
2069 pkgAcquire::MethodConfig
* /*Cnf*/)
2071 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2073 if (AuthPass
== true)
2075 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
2080 /* Always move the meta index, even if gpgv failed. This ensures
2081 * that PackageFile objects are correctly filled in */
2082 if (FileExists(DestFile
))
2084 string FinalFile
= _config
->FindDir("Dir::State::lists");
2085 FinalFile
+= URItoFileName(RealURI
);
2086 /* InRelease files become Release files, otherwise
2087 * they would be considered as trusted later on */
2088 if (SigFile
== DestFile
) {
2089 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2091 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2093 SigFile
= FinalFile
;
2096 // Done, queue for rename on transaction finished
2097 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2100 _error
->Warning(_("The data from '%s' is not signed. Packages "
2101 "from that repository can not be authenticated."),
2104 // No Release file was present, or verification failed, so fall
2105 // back to queueing Packages files without verification
2106 // only allow going further if the users explicitely wants it
2107 if(_config
->FindB("APT::Get::AllowUnauthenticated", false) == true)
2109 QueueIndexes(false);
2111 // warn if the repository is unsinged
2112 _error
->Warning("Use --allow-unauthenticated to force the update");
2117 void pkgAcqMetaIndex::Finished()
2119 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2120 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2121 if(TransactionManager
!= NULL
&&
2122 TransactionManager
->TransactionHasError() == false)
2123 TransactionManager
->CommitTransaction();
2127 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2128 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2129 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2130 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2131 const vector
<IndexTarget
*>* IndexTargets
,
2132 indexRecords
* MetaIndexParser
) :
2133 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2134 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2135 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2139 // index targets + (worst case:) Release/Release.gpg
2140 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2143 // keep the old InRelease around in case of transistent network errors
2144 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2145 if (RealFileExists(Final
) == true)
2147 string
const LastGoodSig
= DestFile
+ ".reverify";
2148 Rename(Final
,LastGoodSig
);
2153 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2156 // if the file was never queued undo file-changes done in the constructor
2157 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
2159 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2160 string
const LastGoodSig
= DestFile
+ ".reverify";
2161 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
2162 Rename(LastGoodSig
, Final
);
2167 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2168 // ---------------------------------------------------------------------
2169 // FIXME: this can go away once the InRelease file is used widely
2170 string
pkgAcqMetaClearSig::Custom600Headers() const
2172 string Final
= _config
->FindDir("Dir::State::lists");
2173 Final
+= URItoFileName(RealURI
);
2176 if (stat(Final
.c_str(),&Buf
) != 0)
2178 if (stat(Final
.c_str(),&Buf
) != 0)
2179 return "\nIndex-File: true\nFail-Ignore: true\n";
2182 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2185 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2186 // ---------------------------------------------------------------------
2187 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2188 HashStringList
const &Hashes
,
2189 pkgAcquire::MethodConfig
*Cnf
)
2191 // if we expect a ClearTextSignature (InRelase), ensure that
2192 // this is what we get and if not fail to queue a
2193 // Release/Release.gpg, see #346386
2194 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2196 pkgAcquire::Item::Failed(Message
, Cnf
);
2197 RenameOnError(NotClearsigned
);
2198 TransactionManager
->AbortTransaction();
2201 pkgAcqMetaIndex::Done(Message
, Size
, Hashes
, Cnf
);
2204 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2206 // we failed, we will not get additional items from this method
2207 ExpectedAdditionalItems
= 0;
2209 if (AuthPass
== false)
2211 // Queue the 'old' InRelease file for removal if we try Release.gpg
2212 // as otherwise the file will stay around and gives a false-auth
2213 // impression (CVE-2012-0214)
2214 string FinalFile
= _config
->FindDir("Dir::State::lists");
2215 FinalFile
.append(URItoFileName(RealURI
));
2216 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2218 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2219 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2220 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2221 IndexTargets
, MetaIndexParser
);
2222 if (Cnf
->LocalOnly
== true ||
2223 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2227 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2230 // AcqArchive::AcqArchive - Constructor /*{{{*/
2231 // ---------------------------------------------------------------------
2232 /* This just sets up the initial fetch environment and queues the first
2234 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2235 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2236 string
&StoreFilename
) :
2237 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2238 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2241 Retries
= _config
->FindI("Acquire::Retries",0);
2243 if (Version
.Arch() == 0)
2245 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2246 "This might mean you need to manually fix this package. "
2247 "(due to missing arch)"),
2248 Version
.ParentPkg().FullName().c_str());
2252 /* We need to find a filename to determine the extension. We make the
2253 assumption here that all the available sources for this version share
2254 the same extension.. */
2255 // Skip not source sources, they do not have file fields.
2256 for (; Vf
.end() == false; ++Vf
)
2258 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2263 // Does not really matter here.. we are going to fail out below
2264 if (Vf
.end() != true)
2266 // If this fails to get a file name we will bomb out below.
2267 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2268 if (_error
->PendingError() == true)
2271 // Generate the final file name as: package_version_arch.foo
2272 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2273 QuoteString(Version
.VerStr(),"_:") + '_' +
2274 QuoteString(Version
.Arch(),"_:.") +
2275 "." + flExtension(Parse
.FileName());
2278 // check if we have one trusted source for the package. if so, switch
2279 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2280 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2281 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2282 bool seenUntrusted
= false;
2283 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2285 pkgIndexFile
*Index
;
2286 if (Sources
->FindIndex(i
.File(),Index
) == false)
2289 if (debugAuth
== true)
2290 std::cerr
<< "Checking index: " << Index
->Describe()
2291 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2293 if (Index
->IsTrusted() == true)
2296 if (allowUnauth
== false)
2300 seenUntrusted
= true;
2303 // "allow-unauthenticated" restores apts old fetching behaviour
2304 // that means that e.g. unauthenticated file:// uris are higher
2305 // priority than authenticated http:// uris
2306 if (allowUnauth
== true && seenUntrusted
== true)
2310 if (QueueNext() == false && _error
->PendingError() == false)
2311 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2312 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2315 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2316 // ---------------------------------------------------------------------
2317 /* This queues the next available file version for download. It checks if
2318 the archive is already available in the cache and stashs the MD5 for
2320 bool pkgAcqArchive::QueueNext()
2322 for (; Vf
.end() == false; ++Vf
)
2324 // Ignore not source sources
2325 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2328 // Try to cross match against the source list
2329 pkgIndexFile
*Index
;
2330 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2333 // only try to get a trusted package from another source if that source
2335 if(Trusted
&& !Index
->IsTrusted())
2338 // Grab the text package record
2339 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2340 if (_error
->PendingError() == true)
2343 string PkgFile
= Parse
.FileName();
2344 ExpectedHashes
= Parse
.Hashes();
2346 if (PkgFile
.empty() == true)
2347 return _error
->Error(_("The package index files are corrupted. No Filename: "
2348 "field for package %s."),
2349 Version
.ParentPkg().Name());
2351 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2352 Desc
.Description
= Index
->ArchiveInfo(Version
);
2354 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2356 // See if we already have the file. (Legacy filenames)
2357 FileSize
= Version
->Size
;
2358 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2360 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2362 // Make sure the size matches
2363 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2368 StoreFilename
= DestFile
= FinalFile
;
2372 /* Hmm, we have a file and its size does not match, this means it is
2373 an old style mismatched arch */
2374 unlink(FinalFile
.c_str());
2377 // Check it again using the new style output filenames
2378 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2379 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2381 // Make sure the size matches
2382 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2387 StoreFilename
= DestFile
= FinalFile
;
2391 /* Hmm, we have a file and its size does not match, this shouldn't
2393 unlink(FinalFile
.c_str());
2396 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2398 // Check the destination file
2399 if (stat(DestFile
.c_str(),&Buf
) == 0)
2401 // Hmm, the partial file is too big, erase it
2402 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2403 unlink(DestFile
.c_str());
2405 PartialSize
= Buf
.st_size
;
2408 // Disables download of archives - useful if no real installation follows,
2409 // e.g. if we are just interested in proposed installation order
2410 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2415 StoreFilename
= DestFile
= FinalFile
;
2429 // AcqArchive::Done - Finished fetching /*{{{*/
2430 // ---------------------------------------------------------------------
2432 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2433 pkgAcquire::MethodConfig
*Cfg
)
2435 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2438 if (Size
!= Version
->Size
)
2440 RenameOnError(SizeMismatch
);
2444 // FIXME: could this empty() check impose *any* sort of security issue?
2445 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2447 RenameOnError(HashSumMismatch
);
2448 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2452 // Grab the output filename
2453 string FileName
= LookupTag(Message
,"Filename");
2454 if (FileName
.empty() == true)
2457 ErrorText
= "Method gave a blank filename";
2463 // Reference filename
2464 if (FileName
!= DestFile
)
2466 StoreFilename
= DestFile
= FileName
;
2471 // Done, move it into position
2472 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2473 FinalFile
+= flNotDir(StoreFilename
);
2474 Rename(DestFile
,FinalFile
);
2476 StoreFilename
= DestFile
= FinalFile
;
2480 // AcqArchive::Failed - Failure handler /*{{{*/
2481 // ---------------------------------------------------------------------
2482 /* Here we try other sources */
2483 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2485 ErrorText
= LookupTag(Message
,"Message");
2487 /* We don't really want to retry on failed media swaps, this prevents
2488 that. An interesting observation is that permanent failures are not
2490 if (Cnf
->Removable
== true &&
2491 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2493 // Vf = Version.FileList();
2494 while (Vf
.end() == false) ++Vf
;
2495 StoreFilename
= string();
2496 Item::Failed(Message
,Cnf
);
2500 if (QueueNext() == false)
2502 // This is the retry counter
2504 Cnf
->LocalOnly
== false &&
2505 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2508 Vf
= Version
.FileList();
2509 if (QueueNext() == true)
2513 StoreFilename
= string();
2514 Item::Failed(Message
,Cnf
);
2518 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2519 // ---------------------------------------------------------------------
2520 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2525 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2526 // ---------------------------------------------------------------------
2528 void pkgAcqArchive::Finished()
2530 if (Status
== pkgAcquire::Item::StatDone
&&
2533 StoreFilename
= string();
2536 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2537 // ---------------------------------------------------------------------
2538 /* The file is added to the queue */
2539 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2540 unsigned long long Size
,string Dsc
,string ShortDesc
,
2541 const string
&DestDir
, const string
&DestFilename
,
2543 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2545 Retries
= _config
->FindI("Acquire::Retries",0);
2547 if(!DestFilename
.empty())
2548 DestFile
= DestFilename
;
2549 else if(!DestDir
.empty())
2550 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2552 DestFile
= flNotDir(URI
);
2556 Desc
.Description
= Dsc
;
2559 // Set the short description to the archive component
2560 Desc
.ShortDesc
= ShortDesc
;
2562 // Get the transfer sizes
2565 if (stat(DestFile
.c_str(),&Buf
) == 0)
2567 // Hmm, the partial file is too big, erase it
2568 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2569 unlink(DestFile
.c_str());
2571 PartialSize
= Buf
.st_size
;
2577 // AcqFile::Done - Item downloaded OK /*{{{*/
2578 // ---------------------------------------------------------------------
2580 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2581 pkgAcquire::MethodConfig
*Cnf
)
2583 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2586 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2588 RenameOnError(HashSumMismatch
);
2589 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2593 string FileName
= LookupTag(Message
,"Filename");
2594 if (FileName
.empty() == true)
2597 ErrorText
= "Method gave a blank filename";
2603 // The files timestamp matches
2604 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2607 // We have to copy it into place
2608 if (FileName
!= DestFile
)
2611 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2612 Cnf
->Removable
== true)
2614 Desc
.URI
= "copy:" + FileName
;
2619 // Erase the file if it is a symlink so we can overwrite it
2621 if (lstat(DestFile
.c_str(),&St
) == 0)
2623 if (S_ISLNK(St
.st_mode
) != 0)
2624 unlink(DestFile
.c_str());
2628 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2630 ErrorText
= "Link to " + DestFile
+ " failure ";
2637 // AcqFile::Failed - Failure handler /*{{{*/
2638 // ---------------------------------------------------------------------
2639 /* Here we try other sources */
2640 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2642 ErrorText
= LookupTag(Message
,"Message");
2644 // This is the retry counter
2646 Cnf
->LocalOnly
== false &&
2647 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2654 Item::Failed(Message
,Cnf
);
2657 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2658 // ---------------------------------------------------------------------
2659 /* The only header we use is the last-modified header. */
2660 string
pkgAcqFile::Custom600Headers() const
2663 return "\nIndex-File: true";