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
;
65 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
67 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
72 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
74 return GetPartialFileName(URItoFileName(uri
));
77 static std::string
GetCompressedFileName(std::string
const &URI
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
79 if (Ext
.empty() || Ext
== "uncompressed")
82 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
83 // file when its doing the indexcopy
84 if (URI
.substr(0,6) == "cdrom:")
87 // adjust DestFile if its compressed on disk
88 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
89 return Name
+ '.' + Ext
;
93 static bool AllowInsecureRepositories(indexRecords
const * const MetaIndexParser
, pkgAcqMetaBase
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
95 if(MetaIndexParser
->IsAlwaysTrusted() || _config
->FindB("Acquire::AllowInsecureRepositories") == true)
98 _error
->Error(_("Use --allow-insecure-repositories to force the update"));
99 TransactionManager
->AbortTransaction();
100 I
->Status
= pkgAcquire::Item::StatError
;
106 // Acquire::Item::Item - Constructor /*{{{*/
108 #pragma GCC diagnostic push
109 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
111 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
112 HashStringList
const &ExpectedHashes
,
113 pkgAcqMetaBase
*TransactionManager
)
114 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
115 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
116 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
120 if(TransactionManager
!= NULL
)
121 TransactionManager
->Add(this);
124 #pragma GCC diagnostic pop
127 // Acquire::Item::~Item - Destructor /*{{{*/
128 // ---------------------------------------------------------------------
130 pkgAcquire::Item::~Item()
135 // Acquire::Item::Failed - Item failed to download /*{{{*/
136 // ---------------------------------------------------------------------
137 /* We return to an idle state if there are still other queues that could
139 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
141 if(ErrorText
.empty())
142 ErrorText
= LookupTag(Message
,"Message");
143 UsedMirror
= LookupTag(Message
,"UsedMirror");
144 if (QueueCounter
<= 1)
146 /* This indicates that the file is not available right now but might
147 be sometime later. If we do a retry cycle then this should be
149 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
150 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
165 string
const FailReason
= LookupTag(Message
, "FailReason");
166 if(FailReason
== "MaximumSizeExceeded")
167 RenameOnError(MaximumSizeExceeded
);
169 // report mirror failure back to LP if we actually use a mirror
170 if(FailReason
.size() != 0)
171 ReportMirrorFailure(FailReason
);
173 ReportMirrorFailure(ErrorText
);
176 // Acquire::Item::Start - Item has begun to download /*{{{*/
177 // ---------------------------------------------------------------------
178 /* Stash status and the file size. Note that setting Complete means
179 sub-phases of the acquire process such as decompresion are operating */
180 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
182 Status
= StatFetching
;
184 if (FileSize
== 0 && Complete
== false)
188 // Acquire::Item::Done - Item downloaded OK /*{{{*/
189 // ---------------------------------------------------------------------
191 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
192 pkgAcquire::MethodConfig
* /*Cnf*/)
194 // We just downloaded something..
195 string FileName
= LookupTag(Message
,"Filename");
196 UsedMirror
= LookupTag(Message
,"UsedMirror");
197 if (Complete
== false && !Local
&& FileName
== DestFile
)
200 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
206 ErrorText
= string();
207 Owner
->Dequeue(this);
210 // Acquire::Item::Rename - Rename a file /*{{{*/
211 // ---------------------------------------------------------------------
212 /* This helper function is used by a lot of item methods as their final
214 bool pkgAcquire::Item::Rename(string From
,string To
)
216 if (rename(From
.c_str(),To
.c_str()) == 0)
220 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
221 From
.c_str(),To
.c_str());
227 void pkgAcquire::Item::QueueURI(ItemDesc
&Item
) /*{{{*/
229 Owner
->Enqueue(Item
);
232 void pkgAcquire::Item::Dequeue() /*{{{*/
234 Owner
->Dequeue(this);
237 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
239 if (RealFileExists(DestFile
))
240 Rename(DestFile
, DestFile
+ ".FAILED");
244 case HashSumMismatch
:
245 ErrorText
= _("Hash Sum mismatch");
246 Status
= StatAuthError
;
247 ReportMirrorFailure("HashChecksumFailure");
250 ErrorText
= _("Size mismatch");
251 Status
= StatAuthError
;
252 ReportMirrorFailure("SizeFailure");
255 ErrorText
= _("Invalid file format");
257 // do not report as usually its not the mirrors fault, but Portal/Proxy
260 ErrorText
= _("Signature error");
264 ErrorText
= _("Does not start with a cleartext signature");
267 case MaximumSizeExceeded
:
268 // the method is expected to report a good error for this
275 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
277 ActiveSubprocess
= subprocess
;
279 #pragma GCC diagnostic push
280 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
282 Mode
= ActiveSubprocess
.c_str();
284 #pragma GCC diagnostic pop
288 // Acquire::Item::ReportMirrorFailure /*{{{*/
289 // ---------------------------------------------------------------------
290 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
292 // we only act if a mirror was used at all
293 if(UsedMirror
.empty())
296 std::cerr
<< "\nReportMirrorFailure: "
298 << " Uri: " << DescURI()
300 << FailCode
<< std::endl
;
302 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
303 "/usr/lib/apt/apt-report-mirror-failure");
304 if(!FileExists(report
))
307 std::vector
<char const*> Args
;
308 Args
.push_back(report
.c_str());
309 Args
.push_back(UsedMirror
.c_str());
310 Args
.push_back(DescURI().c_str());
311 Args
.push_back(FailCode
.c_str());
312 Args
.push_back(NULL
);
314 pid_t pid
= ExecFork();
317 _error
->Error("ReportMirrorFailure Fork failed");
322 execvp(Args
[0], (char**)Args
.data());
323 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
326 if(!ExecWait(pid
, "report-mirror-failure"))
328 _error
->Warning("Couldn't report problem to '%s'",
329 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
333 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
334 // ---------------------------------------------------------------------
335 /* Get the DiffIndex file first and see if there are patches available
336 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
337 * patches. If anything goes wrong in that process, it will fall back to
338 * the original packages file
340 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
341 pkgAcqMetaBase
*TransactionManager
,
342 IndexTarget
const * const Target
,
343 HashStringList
const &ExpectedHashes
,
344 indexRecords
*MetaIndexParser
)
345 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
346 MetaIndexParser
), PackagesFileReadyInPartial(false)
349 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
351 RealURI
= Target
->URI
;
353 Desc
.Description
= Target
->Description
+ ".diff/Index";
354 Desc
.ShortDesc
= Target
->ShortDesc
;
355 Desc
.URI
= Target
->URI
+ ".diff/Index";
357 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
360 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
362 // look for the current package file
363 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
364 CurrentPackagesFile
+= URItoFileName(RealURI
);
366 // FIXME: this file:/ check is a hack to prevent fetching
367 // from local sources. this is really silly, and
368 // should be fixed cleanly as soon as possible
369 if(!FileExists(CurrentPackagesFile
) ||
370 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
372 // we don't have a pkg file or we don't want to queue
373 Failed("No index file, local or canceld by user", NULL
);
378 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
379 << CurrentPackagesFile
<< std::endl
;
385 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
386 // ---------------------------------------------------------------------
387 /* The only header we use is the last-modified header. */
388 string
pkgAcqDiffIndex::Custom600Headers() const
390 string Final
= _config
->FindDir("Dir::State::lists");
391 Final
+= URItoFileName(Desc
.URI
);
394 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
397 if (stat(Final
.c_str(),&Buf
) != 0)
398 return "\nIndex-File: true";
400 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
403 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
405 // failing here is fine: our caller will take care of trying to
406 // get the complete file if patching fails
408 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
411 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
413 if (_error
->PendingError() == true)
417 if(unlikely(TF
.Step(Tags
) == false))
420 HashStringList ServerHashes
;
421 unsigned long long ServerSize
= 0;
423 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
425 std::string tagname
= *type
;
426 tagname
.append("-Current");
427 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
428 if (tmp
.empty() == true)
432 unsigned long long size
;
433 std::stringstream
ss(tmp
);
435 if (unlikely(hash
.empty() == true))
437 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
439 ServerHashes
.push_back(HashString(*type
, hash
));
443 if (ServerHashes
.usable() == false)
446 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
450 if (ServerHashes
!= HashSums())
454 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
455 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, HashSums());
460 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
462 // we have the same sha1 as the server so we are done here
464 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
466 // list cleanup needs to know that this file as well as the already
467 // present index is ours, so we create an empty diff to save it for us
468 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
469 ExpectedHashes
, MetaIndexParser
);
473 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
474 Hashes LocalHashesCalc
;
475 LocalHashesCalc
.AddFD(fd
);
476 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
479 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
480 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
482 // parse all of (provided) history
483 vector
<DiffInfo
> available_patches
;
484 bool firstAcceptedHashes
= true;
485 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
487 if (LocalHashes
.find(*type
) == NULL
)
490 std::string tagname
= *type
;
491 tagname
.append("-History");
492 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
493 if (tmp
.empty() == true)
496 string hash
, filename
;
497 unsigned long long size
;
498 std::stringstream
ss(tmp
);
500 while (ss
>> hash
>> size
>> filename
)
502 if (unlikely(hash
.empty() == true || filename
.empty() == true))
505 // see if we have a record for this file already
506 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
507 for (; cur
!= available_patches
.end(); ++cur
)
509 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
511 cur
->result_hashes
.push_back(HashString(*type
, hash
));
514 if (cur
!= available_patches
.end())
516 if (firstAcceptedHashes
== true)
519 next
.file
= filename
;
520 next
.result_hashes
.push_back(HashString(*type
, hash
));
521 next
.result_size
= size
;
523 available_patches
.push_back(next
);
528 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
529 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
533 firstAcceptedHashes
= false;
536 if (unlikely(available_patches
.empty() == true))
539 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
540 << "Couldn't find any patches for the patch series." << std::endl
;
544 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
546 if (LocalHashes
.find(*type
) == NULL
)
549 std::string tagname
= *type
;
550 tagname
.append("-Patches");
551 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
552 if (tmp
.empty() == true)
555 string hash
, filename
;
556 unsigned long long size
;
557 std::stringstream
ss(tmp
);
559 while (ss
>> hash
>> size
>> filename
)
561 if (unlikely(hash
.empty() == true || filename
.empty() == true))
564 // see if we have a record for this file already
565 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
566 for (; cur
!= available_patches
.end(); ++cur
)
568 if (cur
->file
!= filename
)
570 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
572 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
573 cur
->patch_size
= size
;
576 if (cur
!= available_patches
.end())
579 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
580 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
585 bool foundStart
= false;
586 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
587 cur
!= available_patches
.end(); ++cur
)
589 if (LocalHashes
!= cur
->result_hashes
)
592 available_patches
.erase(available_patches
.begin(), cur
);
597 if (foundStart
== false || unlikely(available_patches
.empty() == true))
600 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
601 << "Couldn't find the start of the patch series." << std::endl
;
605 // patching with too many files is rather slow compared to a fast download
606 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
607 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
610 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
611 << ") so fallback to complete download" << std::endl
;
615 // calculate the size of all patches we have to get
616 // note that all sizes are uncompressed, while we download compressed files
617 unsigned long long patchesSize
= 0;
618 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
619 cur
!= available_patches
.end(); ++cur
)
620 patchesSize
+= cur
->patch_size
;
621 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
622 if (false && sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
625 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
626 << ") so fallback to complete download" << std::endl
;
630 // FIXME: make this use the method
631 PackagesFileReadyInPartial
= true;
632 std::string
const Partial
= GetPartialFileNameFromURI(RealURI
);
634 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
635 FileFd
To(Partial
, FileFd::WriteEmpty
);
636 if(CopyFile(From
, To
) == false)
637 return _error
->Errno("CopyFile", "failed to copy");
640 std::cerr
<< "Done copying " << CurrentPackagesFile
644 // we have something, queue the diffs
645 string::size_type
const last_space
= Description
.rfind(" ");
646 if(last_space
!= string::npos
)
647 Description
.erase(last_space
, Description
.size()-last_space
);
649 /* decide if we should download patches one by one or in one go:
650 The first is good if the server merges patches, but many don't so client
651 based merging can be attempt in which case the second is better.
652 "bad things" will happen if patches are merged on the server,
653 but client side merging is attempt as well */
654 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
655 if (pdiff_merge
== true)
657 // reprepro adds this flag if it has merged patches on the server
658 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
659 pdiff_merge
= (precedence
!= "merged");
662 if (pdiff_merge
== false)
664 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
665 MetaIndexParser
, available_patches
);
669 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
670 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
671 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
675 available_patches
[i
],
685 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
687 Item::Failed(Message
,Cnf
);
691 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
692 << "Falling back to normal index file acquire" << std::endl
;
694 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
697 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
698 pkgAcquire::MethodConfig
*Cnf
)
701 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
703 Item::Done(Message
, Size
, Hashes
, Cnf
);
705 // verify the index target
706 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
708 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
709 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
710 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
712 RenameOnError(HashSumMismatch
);
713 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
714 Failed(Message
, Cnf
);
721 FinalFile
= _config
->FindDir("Dir::State::lists");
722 FinalFile
+= URItoFileName(Desc
.URI
);
724 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
725 DestFile
= FinalFile
;
727 if(!ParseDiffIndex(DestFile
))
728 return Failed("Message: Couldn't parse pdiff index", Cnf
);
730 // queue for final move
731 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
739 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
740 // ---------------------------------------------------------------------
741 /* The package diff is added to the queue. one object is constructed
742 * for each diff and the index
744 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
745 pkgAcqMetaBase
*TransactionManager
,
746 struct IndexTarget
const * const Target
,
747 HashStringList
const &ExpectedHashes
,
748 indexRecords
*MetaIndexParser
,
749 vector
<DiffInfo
> diffs
)
750 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
751 available_patches(diffs
)
753 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
755 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
757 RealURI
= Target
->URI
;
759 Description
= Target
->Description
;
760 Desc
.ShortDesc
= Target
->ShortDesc
;
762 if(available_patches
.empty() == true)
764 // we are done (yeah!), check hashes against the final file
765 DestFile
= _config
->FindDir("Dir::State::lists");
766 DestFile
+= URItoFileName(Target
->URI
);
772 State
= StateFetchDiff
;
777 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
779 Item::Failed(Message
,Cnf
);
783 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
784 << "Falling back to normal index file acquire" << std::endl
;
785 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
789 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
790 void pkgAcqIndexDiffs::Finish(bool allDone
)
793 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
795 << Desc
.URI
<< std::endl
;
797 // we restore the original name, this is required, otherwise
798 // the file will be cleaned
801 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
803 RenameOnError(HashSumMismatch
);
809 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
810 FinalFile
+= URItoFileName(RealURI
);
811 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
813 // this is for the "real" finish
818 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
823 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
830 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
832 // calc sha1 of the just patched file
833 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
835 if(!FileExists(FinalFile
))
837 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
841 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
842 Hashes LocalHashesCalc
;
843 LocalHashesCalc
.AddFD(fd
);
844 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
847 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
849 if (unlikely(LocalHashes
.usable() == false || ExpectedHashes
.usable() == false))
851 Failed("Local/Expected hashes are not usable", NULL
);
856 // final file reached before all patches are applied
857 if(LocalHashes
== ExpectedHashes
)
863 // remove all patches until the next matching patch is found
864 // this requires the Index file to be ordered
865 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
866 available_patches
.empty() == false &&
867 I
!= available_patches
.end() &&
868 I
->result_hashes
!= LocalHashes
;
871 available_patches
.erase(I
);
874 // error checking and falling back if no patch was found
875 if(available_patches
.empty() == true)
877 Failed("No patches left to reach target", NULL
);
881 // queue the right diff
882 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
883 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
884 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
887 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
894 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
895 pkgAcquire::MethodConfig
*Cnf
)
898 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
900 Item::Done(Message
, Size
, Hashes
, Cnf
);
902 // FIXME: verify this download too before feeding it to rred
903 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
905 // success in downloading a diff, enter ApplyDiff state
906 if(State
== StateFetchDiff
)
908 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
909 class Hashes LocalHashesCalc
;
910 LocalHashesCalc
.AddFD(fd
);
911 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
913 if (fd
.Size() != available_patches
[0].patch_size
||
914 available_patches
[0].patch_hashes
!= LocalHashes
)
916 Failed("Patch has Size/Hashsum mismatch", NULL
);
920 // rred excepts the patch as $FinalFile.ed
921 Rename(DestFile
,FinalFile
+".ed");
924 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
926 State
= StateApplyDiff
;
928 Desc
.URI
= "rred:" + FinalFile
;
930 SetActiveSubprocess("rred");
935 // success in download/apply a diff, queue next (if needed)
936 if(State
== StateApplyDiff
)
938 // remove the just applied patch
939 available_patches
.erase(available_patches
.begin());
940 unlink((FinalFile
+ ".ed").c_str());
945 std::clog
<< "Moving patched file in place: " << std::endl
946 << DestFile
<< " -> " << FinalFile
<< std::endl
;
948 Rename(DestFile
,FinalFile
);
949 chmod(FinalFile
.c_str(),0644);
951 // see if there is more to download
952 if(available_patches
.empty() == false) {
953 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
954 ExpectedHashes
, MetaIndexParser
,
959 DestFile
= FinalFile
;
964 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
965 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
966 pkgAcqMetaBase
*TransactionManager
,
967 struct IndexTarget
const * const Target
,
968 HashStringList
const &ExpectedHashes
,
969 indexRecords
*MetaIndexParser
,
970 DiffInfo
const &patch
,
971 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
972 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
973 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
975 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
977 RealURI
= Target
->URI
;
979 Description
= Target
->Description
;
980 Desc
.ShortDesc
= Target
->ShortDesc
;
982 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
983 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
985 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + patch
.file
);
988 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
993 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
996 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
998 Item::Failed(Message
,Cnf
);
1001 // check if we are the first to fail, otherwise we are done here
1002 State
= StateDoneDiff
;
1003 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1004 I
!= allPatches
->end(); ++I
)
1005 if ((*I
)->State
== StateErrorDiff
)
1008 // first failure means we should fallback
1009 State
= StateErrorDiff
;
1010 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
1011 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
1014 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1015 pkgAcquire::MethodConfig
*Cnf
)
1018 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
1020 Item::Done(Message
,Size
,Hashes
,Cnf
);
1022 // FIXME: verify download before feeding it to rred
1023 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1025 if (State
== StateFetchDiff
)
1027 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1028 class Hashes LocalHashesCalc
;
1029 LocalHashesCalc
.AddFD(fd
);
1030 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1032 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1034 Failed("Patch has Size/Hashsum mismatch", NULL
);
1038 // rred expects the patch as $FinalFile.ed.$patchname.gz
1039 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1041 // check if this is the last completed diff
1042 State
= StateDoneDiff
;
1043 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1044 I
!= allPatches
->end(); ++I
)
1045 if ((*I
)->State
!= StateDoneDiff
)
1048 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1052 // this is the last completed diff, so we are ready to apply now
1053 State
= StateApplyDiff
;
1056 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1059 Desc
.URI
= "rred:" + FinalFile
;
1061 SetActiveSubprocess("rred");
1064 // success in download/apply all diffs, clean up
1065 else if (State
== StateApplyDiff
)
1067 // see if we really got the expected file
1068 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
1070 RenameOnError(HashSumMismatch
);
1075 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1076 FinalFile
+= URItoFileName(RealURI
);
1078 // move the result into place
1080 std::clog
<< "Queue patched file in place: " << std::endl
1081 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1083 // queue for copy by the transaction manager
1084 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1086 // ensure the ed's are gone regardless of list-cleanup
1087 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1088 I
!= allPatches
->end(); ++I
)
1090 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1091 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1092 unlink(patch
.c_str());
1098 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1102 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1103 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1105 if(MetaKey
!= "" && Hashes
.usable())
1107 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1108 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1110 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1117 // AcqIndex::AcqIndex - Constructor /*{{{*/
1118 // ---------------------------------------------------------------------
1119 /* The package file is added to the queue and a second class is
1120 instantiated to fetch the revision file */
1121 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1122 string URI
,string URIDesc
,string ShortDesc
,
1123 HashStringList
const &ExpectedHash
)
1124 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1128 AutoSelectCompression();
1129 Init(URI
, URIDesc
, ShortDesc
);
1131 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1132 std::clog
<< "New pkgIndex with TransactionManager "
1133 << TransactionManager
<< std::endl
;
1136 // AcqIndex::AcqIndex - Constructor /*{{{*/
1137 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1138 pkgAcqMetaBase
*TransactionManager
,
1139 IndexTarget
const *Target
,
1140 HashStringList
const &ExpectedHash
,
1141 indexRecords
*MetaIndexParser
)
1142 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1145 RealURI
= Target
->URI
;
1147 // autoselect the compression method
1148 AutoSelectCompression();
1149 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1151 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1152 std::clog
<< "New pkgIndex with TransactionManager "
1153 << TransactionManager
<< std::endl
;
1156 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1157 void pkgAcqIndex::AutoSelectCompression()
1159 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1160 CompressionExtensions
= "";
1161 if (ExpectedHashes
.usable())
1163 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1164 t
!= types
.end(); ++t
)
1166 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1167 if (*t
== "uncompressed" ||
1168 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1169 CompressionExtensions
.append(*t
).append(" ");
1174 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1175 CompressionExtensions
.append(*t
).append(" ");
1177 if (CompressionExtensions
.empty() == false)
1178 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1181 // AcqIndex::Init - defered Constructor /*{{{*/
1182 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1183 string
const &ShortDesc
)
1185 Stage
= STAGE_DOWNLOAD
;
1187 DestFile
= GetPartialFileNameFromURI(URI
);
1189 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1190 if (CurrentCompressionExtension
== "uncompressed")
1194 MetaKey
= string(Target
->MetaKey
);
1198 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1199 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1201 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1204 // load the filesize
1207 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1209 FileSize
= Record
->Size
;
1211 InitByHashIfNeeded(MetaKey
);
1214 Desc
.Description
= URIDesc
;
1216 Desc
.ShortDesc
= ShortDesc
;
1221 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1222 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1225 // - (maybe?) add support for by-hash into the sources.list as flag
1226 // - make apt-ftparchive generate the hashes (and expire?)
1227 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1228 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1229 _config
->FindB(HostKnob
, false) == true ||
1230 MetaIndexParser
->GetSupportsAcquireByHash())
1232 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1235 // FIXME: should we really use the best hash here? or a fixed one?
1236 const HashString
*TargetHash
= Record
->Hashes
.find("");
1237 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1238 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1239 Desc
.URI
= Desc
.URI
.replace(
1241 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1245 "Fetching ByHash requested but can not find record for %s",
1251 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1252 // ---------------------------------------------------------------------
1253 /* The only header we use is the last-modified header. */
1254 string
pkgAcqIndex::Custom600Headers() const
1256 string Final
= GetFinalFilename();
1258 string msg
= "\nIndex-File: true";
1260 if (stat(Final
.c_str(),&Buf
) == 0)
1261 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1266 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1267 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1269 Item::Failed(Message
,Cnf
);
1271 size_t const nextExt
= CompressionExtensions
.find(' ');
1272 if (nextExt
!= std::string::npos
)
1274 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1275 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1280 // on decompression failure, remove bad versions in partial/
1281 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1283 unlink(EraseFileName
.c_str());
1286 /// cancel the entire transaction
1287 TransactionManager
->AbortTransaction();
1290 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1291 std::string
pkgAcqIndex::GetFinalFilename() const
1293 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1294 FinalFile
+= URItoFileName(RealURI
);
1295 return GetCompressedFileName(RealURI
, FinalFile
, CurrentCompressionExtension
);
1298 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1299 void pkgAcqIndex::ReverifyAfterIMS()
1301 // update destfile to *not* include the compression extension when doing
1302 // a reverify (as its uncompressed on disk already)
1303 DestFile
= GetCompressedFileName(RealURI
, GetPartialFileNameFromURI(RealURI
), CurrentCompressionExtension
);
1305 // copy FinalFile into partial/ so that we check the hash again
1306 string FinalFile
= GetFinalFilename();
1307 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1308 Desc
.URI
= "copy:" + FinalFile
;
1312 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1313 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1315 // FIXME: this can go away once we only ever download stuff that
1316 // has a valid hash and we never do GET based probing
1317 // FIXME2: this also leaks debian-isms into the code and should go therefore
1319 /* Always validate the index file for correctness (all indexes must
1320 * have a Package field) (LP: #346386) (Closes: #627642)
1322 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1323 // Only test for correctness if the content of the file is not empty
1328 pkgTagFile
tag(&fd
);
1330 // all our current indexes have a field 'Package' in each section
1331 if (_error
->PendingError() == true ||
1332 tag
.Step(sec
) == false ||
1333 sec
.Exists("Package") == false)
1339 // AcqIndex::Done - Finished a fetch /*{{{*/
1340 // ---------------------------------------------------------------------
1341 /* This goes through a number of states.. On the initial fetch the
1342 method could possibly return an alternate filename which points
1343 to the uncompressed version of the file. If this is so the file
1344 is copied into the partial directory. In all other cases the file
1345 is decompressed with a compressed uri. */
1346 void pkgAcqIndex::Done(string Message
,
1347 unsigned long long Size
,
1348 HashStringList
const &Hashes
,
1349 pkgAcquire::MethodConfig
*Cfg
)
1351 Item::Done(Message
,Size
,Hashes
,Cfg
);
1355 case STAGE_DOWNLOAD
:
1356 StageDownloadDone(Message
, Hashes
, Cfg
);
1358 case STAGE_DECOMPRESS_AND_VERIFY
:
1359 StageDecompressDone(Message
, Hashes
, Cfg
);
1364 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1365 void pkgAcqIndex::StageDownloadDone(string Message
,
1366 HashStringList
const &Hashes
,
1367 pkgAcquire::MethodConfig
*Cfg
)
1369 // First check if the calculcated Hash of the (compressed) downloaded
1370 // file matches the hash we have in the MetaIndexRecords for this file
1371 if(VerifyHashByMetaKey(Hashes
) == false)
1373 RenameOnError(HashSumMismatch
);
1374 Failed(Message
, Cfg
);
1380 // Handle the unzipd case
1381 string FileName
= LookupTag(Message
,"Alt-Filename");
1382 if (FileName
.empty() == false)
1384 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1386 DestFile
+= ".decomp";
1387 Desc
.URI
= "copy:" + FileName
;
1389 SetActiveSubprocess("copy");
1393 FileName
= LookupTag(Message
,"Filename");
1394 if (FileName
.empty() == true)
1397 ErrorText
= "Method gave a blank filename";
1400 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1401 // not the "DestFile" we set, in this case we uncompress from the local file
1402 if (FileName
!= DestFile
)
1405 EraseFileName
= FileName
;
1407 // we need to verify the file against the current Release file again
1408 // on if-modfied-since hit to avoid a stale attack against us
1409 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1411 // The files timestamp matches, reverify by copy into partial/
1417 // If we have compressed indexes enabled, queue for hash verification
1418 if (_config
->FindB("Acquire::GzipIndexes",false))
1420 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1422 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1423 Desc
.URI
= "copy:" + FileName
;
1425 SetActiveSubprocess("copy");
1429 // get the binary name for your used compression type
1431 if(CurrentCompressionExtension
== "uncompressed")
1432 decompProg
= "copy";
1434 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1435 if(decompProg
.empty() == true)
1437 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1441 // queue uri for the next stage
1442 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1443 DestFile
+= ".decomp";
1444 Desc
.URI
= decompProg
+ ":" + FileName
;
1446 SetActiveSubprocess(decompProg
);
1449 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1450 void pkgAcqIndex::StageDecompressDone(string Message
,
1451 HashStringList
const &Hashes
,
1452 pkgAcquire::MethodConfig
*Cfg
)
1454 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1457 RenameOnError(HashSumMismatch
);
1458 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1459 Failed(Message
, Cfg
);
1463 if(!ValidateFile(DestFile
))
1465 RenameOnError(InvalidFormat
);
1466 Failed(Message
, Cfg
);
1470 // remove the compressed version of the file
1471 unlink(EraseFileName
.c_str());
1473 // Done, queue for rename on transaction finished
1474 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1479 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1480 // ---------------------------------------------------------------------
1481 /* The Translation file is added to the queue */
1482 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1483 string URI
,string URIDesc
,string ShortDesc
)
1484 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1487 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1488 pkgAcqMetaBase
*TransactionManager
,
1489 IndexTarget
const * const Target
,
1490 HashStringList
const &ExpectedHashes
,
1491 indexRecords
*MetaIndexParser
)
1492 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1496 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1497 string
pkgAcqIndexTrans::Custom600Headers() const
1499 string Final
= GetFinalFilename();
1502 if (stat(Final
.c_str(),&Buf
) != 0)
1503 return "\nFail-Ignore: true\nIndex-File: true";
1504 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1507 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1508 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1510 Item::Failed(Message
,Cnf
);
1512 size_t const nextExt
= CompressionExtensions
.find(' ');
1513 if (nextExt
!= std::string::npos
)
1515 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1516 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1521 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1522 if (Cnf
->LocalOnly
== true ||
1523 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1530 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1531 void pkgAcqMetaBase::Add(Item
*I
)
1533 Transaction
.push_back(I
);
1536 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1537 void pkgAcqMetaBase::AbortTransaction()
1539 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1540 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1542 // ensure the toplevel is in error state too
1543 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1544 I
!= Transaction
.end(); ++I
)
1546 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1547 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1548 // the transaction will abort, so stop anything that is idle
1549 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1550 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1552 Transaction
.clear();
1555 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1556 bool pkgAcqMetaBase::TransactionHasError()
1558 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1559 I
!= Transaction
.end(); ++I
)
1560 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1561 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1567 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1568 void pkgAcqMetaBase::CommitTransaction()
1570 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1571 std::clog
<< "CommitTransaction: " << this << std::endl
;
1573 // move new files into place *and* remove files that are not
1574 // part of the transaction but are still on disk
1575 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1576 I
!= Transaction
.end(); ++I
)
1578 if((*I
)->PartialFile
!= "")
1580 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1581 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1582 << (*I
)->DescURI() << std::endl
;
1584 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1586 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1592 unlink((*I
)->DestFile
.c_str());
1594 // mark that this transaction is finished
1595 (*I
)->TransactionManager
= 0;
1597 Transaction
.clear();
1600 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1601 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1602 const std::string
&From
,
1603 const std::string
&To
)
1605 I
->PartialFile
= From
;
1609 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1610 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1611 const std::string
&FinalFile
)
1613 I
->PartialFile
= "";
1614 I
->DestFile
= FinalFile
;
1617 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1618 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&RealURI
,
1619 const std::string
&Message
)
1621 // FIXME: this entire function can do now that we disallow going to
1622 // a unauthenticated state and can cleanly rollback
1624 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1626 if(FileExists(Final
))
1628 Status
= StatTransientNetworkError
;
1629 _error
->Warning(_("An error occurred during the signature "
1630 "verification. The repository is not updated "
1631 "and the previous index files will be used. "
1632 "GPG error: %s: %s\n"),
1633 Desc
.Description
.c_str(),
1634 LookupTag(Message
,"Message").c_str());
1635 RunScripts("APT::Update::Auth-Failure");
1637 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1638 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1639 _error
->Error(_("GPG error: %s: %s"),
1640 Desc
.Description
.c_str(),
1641 LookupTag(Message
,"Message").c_str());
1645 _error
->Warning(_("GPG error: %s: %s"),
1646 Desc
.Description
.c_str(),
1647 LookupTag(Message
,"Message").c_str());
1649 // gpgv method failed
1650 ReportMirrorFailure("GPGFailure");
1654 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1655 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1656 pkgAcqMetaBase
*TransactionManager
,
1657 string URI
,string URIDesc
,string ShortDesc
,
1658 string MetaIndexFile
,
1659 const vector
<IndexTarget
*>* IndexTargets
,
1660 indexRecords
* MetaIndexParser
) :
1661 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1662 HashStringList(), TransactionManager
),
1663 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1664 ShortDesc(ShortDesc
)
1666 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1667 DestFile
+= URItoFileName(RealURI
);
1669 // remove any partial downloaded sig-file in partial/.
1670 // it may confuse proxies and is too small to warrant a
1671 // partial download anyway
1672 unlink(DestFile
.c_str());
1674 // set the TransactionManager
1675 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1676 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1677 << TransactionManager
<< std::endl
;
1680 Desc
.Description
= URIDesc
;
1682 Desc
.ShortDesc
= ShortDesc
;
1688 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1692 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1693 // ---------------------------------------------------------------------
1694 string
pkgAcqMetaSig::Custom600Headers() const
1696 std::string Header
= GetCustom600Headers(RealURI
);
1700 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1701 // ---------------------------------------------------------------------
1702 /* The only header we use is the last-modified header. */
1703 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1704 HashStringList
const &Hashes
,
1705 pkgAcquire::MethodConfig
*Cfg
)
1707 Item::Done(Message
, Size
, Hashes
, Cfg
);
1709 if(AuthPass
== false)
1711 if(CheckDownloadDone(Message
, RealURI
) == true)
1713 // destfile will be modified to point to MetaIndexFile for the
1714 // gpgv method, so we need to save it here
1715 MetaIndexFileSignature
= DestFile
;
1716 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1722 if(CheckAuthDone(Message
, RealURI
) == true)
1724 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1725 FinalFile
+= URItoFileName(RealURI
);
1726 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1731 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1733 Item::Failed(Message
,Cnf
);
1735 // check if we need to fail at this point
1736 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1739 // FIXME: meh, this is not really elegant
1740 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1741 string
const InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1743 string
const FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1745 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1747 std::string downgrade_msg
;
1748 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1750 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1752 // meh, the users wants to take risks (we still mark the packages
1753 // from this repository as unauthenticated)
1754 _error
->Warning("%s", downgrade_msg
.c_str());
1755 _error
->Warning(_("This is normally not allowed, but the option "
1756 "Acquire::AllowDowngradeToInsecureRepositories was "
1757 "given to override it."));
1760 _error
->Error("%s", downgrade_msg
.c_str());
1761 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1762 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1763 TransactionManager
->AbortTransaction();
1768 _error
->Warning(_("The data from '%s' is not signed. Packages "
1769 "from that repository can not be authenticated."),
1772 // this ensures that any file in the lists/ dir is removed by the
1774 DestFile
= GetPartialFileNameFromURI(RealURI
);
1775 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1777 // only allow going further if the users explicitely wants it
1778 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
1780 // we parse the indexes here because at this point the user wanted
1781 // a repository that may potentially harm him
1782 MetaIndexParser
->Load(MetaIndexFile
);
1786 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1787 if (Cnf
->LocalOnly
== true ||
1788 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1795 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1796 pkgAcqMetaBase
*TransactionManager
,
1797 string URI
,string URIDesc
,string ShortDesc
,
1798 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1799 const vector
<IndexTarget
*>* IndexTargets
,
1800 indexRecords
* MetaIndexParser
) :
1801 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1802 TransactionManager
),
1803 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1804 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1805 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1807 if(TransactionManager
== NULL
)
1809 this->TransactionManager
= this;
1810 this->TransactionManager
->Add(this);
1813 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1814 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1815 << this->TransactionManager
<< std::endl
;
1818 Init(URIDesc
, ShortDesc
);
1821 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1822 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1824 DestFile
= GetPartialFileNameFromURI(RealURI
);
1827 Desc
.Description
= URIDesc
;
1829 Desc
.ShortDesc
= ShortDesc
;
1832 // we expect more item
1833 ExpectedAdditionalItems
= IndexTargets
->size();
1837 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1838 // ---------------------------------------------------------------------
1839 string
pkgAcqMetaIndex::Custom600Headers() const
1841 return GetCustom600Headers(RealURI
);
1844 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1845 HashStringList
const &Hashes
,
1846 pkgAcquire::MethodConfig
*Cfg
)
1848 Item::Done(Message
,Size
,Hashes
,Cfg
);
1850 if(CheckDownloadDone(Message
, RealURI
))
1852 // we have a Release file, now download the Signature, all further
1853 // verify/queue for additional downloads will be done in the
1854 // pkgAcqMetaSig::Done() code
1855 std::string MetaIndexFile
= DestFile
;
1856 new pkgAcqMetaSig(Owner
, TransactionManager
,
1857 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1858 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1861 string FinalFile
= _config
->FindDir("Dir::State::lists");
1862 FinalFile
+= URItoFileName(RealURI
);
1863 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1867 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1869 // At this point, the gpgv method has succeeded, so there is a
1870 // valid signature from a key in the trusted keyring. We
1871 // perform additional verification of its contents, and use them
1872 // to verify the indexes we are about to download
1874 if (!MetaIndexParser
->Load(DestFile
))
1876 Status
= StatAuthError
;
1877 ErrorText
= MetaIndexParser
->ErrorText
;
1881 if (!VerifyVendor(Message
, RealURI
))
1886 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1887 std::cerr
<< "Signature verification succeeded: "
1888 << DestFile
<< std::endl
;
1890 // Download further indexes with verification
1892 // it would be really nice if we could simply do
1893 // if (IMSHit == false) QueueIndexes(true)
1894 // and skip the download if the Release file has not changed
1895 // - but right now the list cleaner will needs to be tricked
1896 // to not delete all our packages/source indexes in this case
1902 // pkgAcqMetaBase::GetCustom600Headers - Get header for AcqMetaBase /*{{{*/
1903 // ---------------------------------------------------------------------
1904 string
pkgAcqMetaBase::GetCustom600Headers(const string
&RealURI
) const
1906 std::string Header
= "\nIndex-File: true";
1907 std::string MaximumSize
;
1908 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1909 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1910 Header
+= MaximumSize
;
1912 string FinalFile
= _config
->FindDir("Dir::State::lists");
1913 FinalFile
+= URItoFileName(RealURI
);
1916 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1917 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1922 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1923 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1924 const std::string
&MetaIndexFileSignature
)
1927 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1928 DestFile
= MetaIndexFile
;
1930 SetActiveSubprocess("gpgv");
1933 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1934 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1935 const std::string
&RealURI
)
1937 // We have just finished downloading a Release file (it is not
1940 string FileName
= LookupTag(Message
,"Filename");
1941 if (FileName
.empty() == true)
1944 ErrorText
= "Method gave a blank filename";
1948 if (FileName
!= DestFile
)
1951 Desc
.URI
= "copy:" + FileName
;
1956 // make sure to verify against the right file on I-M-S hit
1957 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1960 string FinalFile
= _config
->FindDir("Dir::State::lists");
1961 FinalFile
+= URItoFileName(RealURI
);
1962 DestFile
= FinalFile
;
1965 // set Item to complete as the remaining work is all local (verify etc)
1971 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1973 bool transInRelease
= false;
1975 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1976 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1977 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1978 if (k
->find("Translation-") != std::string::npos
)
1980 transInRelease
= true;
1985 // at this point the real Items are loaded in the fetcher
1986 ExpectedAdditionalItems
= 0;
1987 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1988 Target
!= IndexTargets
->end();
1991 HashStringList ExpectedIndexHashes
;
1992 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1993 bool compressedAvailable
= false;
1996 if ((*Target
)->IsOptional() == true)
1998 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1999 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2000 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
2002 compressedAvailable
= true;
2006 else if (verify
== true)
2008 Status
= StatAuthError
;
2009 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2015 ExpectedIndexHashes
= Record
->Hashes
;
2016 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2018 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2019 << "Expected Hash:" << std::endl
;
2020 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2021 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2022 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
2024 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
2026 Status
= StatAuthError
;
2027 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2032 if ((*Target
)->IsOptional() == true)
2034 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
2036 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
2037 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
2038 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2040 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2045 /* Queue Packages file (either diff or full packages files, depending
2046 on the users option) - we also check if the PDiff Index file is listed
2047 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2048 instead, but passing the required info to it is to much hassle */
2049 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2050 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2051 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2053 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2057 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
2059 string::size_type pos
;
2061 // check for missing sigs (that where not fatal because otherwise we had
2064 string msg
= _("There is no public key available for the "
2065 "following key IDs:\n");
2066 pos
= Message
.find("NO_PUBKEY ");
2067 if (pos
!= std::string::npos
)
2069 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2070 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2071 missingkeys
+= (Fingerprint
);
2073 if(!missingkeys
.empty())
2074 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2076 string Transformed
= MetaIndexParser
->GetExpectedDist();
2078 if (Transformed
== "../project/experimental")
2080 Transformed
= "experimental";
2083 pos
= Transformed
.rfind('/');
2084 if (pos
!= string::npos
)
2086 Transformed
= Transformed
.substr(0, pos
);
2089 if (Transformed
== ".")
2094 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2095 MetaIndexParser
->GetValidUntil() > 0) {
2096 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2097 if (invalid_since
> 0)
2098 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2099 // the time since then the file is invalid - formated in the same way as in
2100 // the download progress display (e.g. 7d 3h 42min 1s)
2101 return _error
->Error(
2102 _("Release file for %s is expired (invalid since %s). "
2103 "Updates for this repository will not be applied."),
2104 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2107 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2109 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2110 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2111 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2114 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2116 // This might become fatal one day
2117 // Status = StatAuthError;
2118 // ErrorText = "Conflicting distribution; expected "
2119 // + MetaIndexParser->GetExpectedDist() + " but got "
2120 // + MetaIndexParser->GetDist();
2122 if (!Transformed
.empty())
2124 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2125 Desc
.Description
.c_str(),
2126 Transformed
.c_str(),
2127 MetaIndexParser
->GetDist().c_str());
2134 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2135 void pkgAcqMetaIndex::Failed(string Message
,
2136 pkgAcquire::MethodConfig
* Cnf
)
2138 pkgAcquire::Item::Failed(Message
, Cnf
);
2141 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2143 _error
->Warning(_("The repository '%s' does not have a Release file. "
2144 "This is deprecated, please contact the owner of the "
2145 "repository."), URIDesc
.c_str());
2147 // No Release file was present so fall
2148 // back to queueing Packages files without verification
2149 // only allow going further if the users explicitely wants it
2150 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2152 // Done, queue for rename on transaction finished
2153 if (FileExists(DestFile
))
2154 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2156 // queue without any kind of hashsum support
2157 QueueIndexes(false);
2161 void pkgAcqMetaIndex::Finished() /*{{{*/
2163 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2164 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2165 if(TransactionManager
!= NULL
&&
2166 TransactionManager
->TransactionHasError() == false)
2167 TransactionManager
->CommitTransaction();
2170 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2171 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2172 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2173 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2174 const vector
<IndexTarget
*>* IndexTargets
,
2175 indexRecords
* MetaIndexParser
) :
2176 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2177 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2178 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2180 // index targets + (worst case:) Release/Release.gpg
2181 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2185 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2189 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2190 // ---------------------------------------------------------------------
2191 string
pkgAcqMetaClearSig::Custom600Headers() const
2193 string Header
= GetCustom600Headers(RealURI
);
2194 Header
+= "\nFail-Ignore: true";
2198 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2199 // ---------------------------------------------------------------------
2200 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2201 HashStringList
const &Hashes
,
2202 pkgAcquire::MethodConfig
*Cnf
)
2204 Item::Done(Message
, Size
, Hashes
, Cnf
);
2206 // if we expect a ClearTextSignature (InRelase), ensure that
2207 // this is what we get and if not fail to queue a
2208 // Release/Release.gpg, see #346386
2209 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2211 pkgAcquire::Item::Failed(Message
, Cnf
);
2212 RenameOnError(NotClearsigned
);
2213 TransactionManager
->AbortTransaction();
2217 if(AuthPass
== false)
2219 if(CheckDownloadDone(Message
, RealURI
) == true)
2220 QueueForSignatureVerify(DestFile
, DestFile
);
2225 if(CheckAuthDone(Message
, RealURI
) == true)
2227 string FinalFile
= _config
->FindDir("Dir::State::lists");
2228 FinalFile
+= URItoFileName(RealURI
);
2230 // queue for copy in place
2231 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2236 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2238 Item::Failed(Message
, Cnf
);
2240 // we failed, we will not get additional items from this method
2241 ExpectedAdditionalItems
= 0;
2243 if (AuthPass
== false)
2245 // Queue the 'old' InRelease file for removal if we try Release.gpg
2246 // as otherwise the file will stay around and gives a false-auth
2247 // impression (CVE-2012-0214)
2248 string FinalFile
= _config
->FindDir("Dir::State::lists");
2249 FinalFile
.append(URItoFileName(RealURI
));
2250 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2253 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2254 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2255 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2256 IndexTargets
, MetaIndexParser
);
2260 if(CheckStopAuthentication(RealURI
, Message
))
2263 _error
->Warning(_("The data from '%s' is not signed. Packages "
2264 "from that repository can not be authenticated."),
2267 // No Release file was present, or verification failed, so fall
2268 // back to queueing Packages files without verification
2269 // only allow going further if the users explicitely wants it
2270 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2274 /* Always move the meta index, even if gpgv failed. This ensures
2275 * that PackageFile objects are correctly filled in */
2276 if (FileExists(DestFile
))
2278 string FinalFile
= _config
->FindDir("Dir::State::lists");
2279 FinalFile
+= URItoFileName(RealURI
);
2280 /* InRelease files become Release files, otherwise
2281 * they would be considered as trusted later on */
2282 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2284 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2287 // Done, queue for rename on transaction finished
2288 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2290 QueueIndexes(false);
2295 // AcqArchive::AcqArchive - Constructor /*{{{*/
2296 // ---------------------------------------------------------------------
2297 /* This just sets up the initial fetch environment and queues the first
2299 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2300 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2301 string
&StoreFilename
) :
2302 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2303 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2306 Retries
= _config
->FindI("Acquire::Retries",0);
2308 if (Version
.Arch() == 0)
2310 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2311 "This might mean you need to manually fix this package. "
2312 "(due to missing arch)"),
2313 Version
.ParentPkg().FullName().c_str());
2317 /* We need to find a filename to determine the extension. We make the
2318 assumption here that all the available sources for this version share
2319 the same extension.. */
2320 // Skip not source sources, they do not have file fields.
2321 for (; Vf
.end() == false; ++Vf
)
2323 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2328 // Does not really matter here.. we are going to fail out below
2329 if (Vf
.end() != true)
2331 // If this fails to get a file name we will bomb out below.
2332 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2333 if (_error
->PendingError() == true)
2336 // Generate the final file name as: package_version_arch.foo
2337 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2338 QuoteString(Version
.VerStr(),"_:") + '_' +
2339 QuoteString(Version
.Arch(),"_:.") +
2340 "." + flExtension(Parse
.FileName());
2343 // check if we have one trusted source for the package. if so, switch
2344 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2345 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2346 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2347 bool seenUntrusted
= false;
2348 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2350 pkgIndexFile
*Index
;
2351 if (Sources
->FindIndex(i
.File(),Index
) == false)
2354 if (debugAuth
== true)
2355 std::cerr
<< "Checking index: " << Index
->Describe()
2356 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2358 if (Index
->IsTrusted() == true)
2361 if (allowUnauth
== false)
2365 seenUntrusted
= true;
2368 // "allow-unauthenticated" restores apts old fetching behaviour
2369 // that means that e.g. unauthenticated file:// uris are higher
2370 // priority than authenticated http:// uris
2371 if (allowUnauth
== true && seenUntrusted
== true)
2375 if (QueueNext() == false && _error
->PendingError() == false)
2376 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2377 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2380 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2381 // ---------------------------------------------------------------------
2382 /* This queues the next available file version for download. It checks if
2383 the archive is already available in the cache and stashs the MD5 for
2385 bool pkgAcqArchive::QueueNext()
2387 for (; Vf
.end() == false; ++Vf
)
2389 // Ignore not source sources
2390 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2393 // Try to cross match against the source list
2394 pkgIndexFile
*Index
;
2395 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2398 // only try to get a trusted package from another source if that source
2400 if(Trusted
&& !Index
->IsTrusted())
2403 // Grab the text package record
2404 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2405 if (_error
->PendingError() == true)
2408 string PkgFile
= Parse
.FileName();
2409 ExpectedHashes
= Parse
.Hashes();
2411 if (PkgFile
.empty() == true)
2412 return _error
->Error(_("The package index files are corrupted. No Filename: "
2413 "field for package %s."),
2414 Version
.ParentPkg().Name());
2416 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2417 Desc
.Description
= Index
->ArchiveInfo(Version
);
2419 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2421 // See if we already have the file. (Legacy filenames)
2422 FileSize
= Version
->Size
;
2423 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2425 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2427 // Make sure the size matches
2428 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2433 StoreFilename
= DestFile
= FinalFile
;
2437 /* Hmm, we have a file and its size does not match, this means it is
2438 an old style mismatched arch */
2439 unlink(FinalFile
.c_str());
2442 // Check it again using the new style output filenames
2443 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2444 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2446 // Make sure the size matches
2447 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2452 StoreFilename
= DestFile
= FinalFile
;
2456 /* Hmm, we have a file and its size does not match, this shouldn't
2458 unlink(FinalFile
.c_str());
2461 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2463 // Check the destination file
2464 if (stat(DestFile
.c_str(),&Buf
) == 0)
2466 // Hmm, the partial file is too big, erase it
2467 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2468 unlink(DestFile
.c_str());
2470 PartialSize
= Buf
.st_size
;
2473 // Disables download of archives - useful if no real installation follows,
2474 // e.g. if we are just interested in proposed installation order
2475 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2480 StoreFilename
= DestFile
= FinalFile
;
2494 // AcqArchive::Done - Finished fetching /*{{{*/
2495 // ---------------------------------------------------------------------
2497 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2498 pkgAcquire::MethodConfig
*Cfg
)
2500 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2503 if (Size
!= Version
->Size
)
2505 RenameOnError(SizeMismatch
);
2509 // FIXME: could this empty() check impose *any* sort of security issue?
2510 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2512 RenameOnError(HashSumMismatch
);
2513 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2517 // Grab the output filename
2518 string FileName
= LookupTag(Message
,"Filename");
2519 if (FileName
.empty() == true)
2522 ErrorText
= "Method gave a blank filename";
2526 // Reference filename
2527 if (FileName
!= DestFile
)
2529 StoreFilename
= DestFile
= FileName
;
2535 // Done, move it into position
2536 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2537 FinalFile
+= flNotDir(StoreFilename
);
2538 Rename(DestFile
,FinalFile
);
2539 StoreFilename
= DestFile
= FinalFile
;
2543 // AcqArchive::Failed - Failure handler /*{{{*/
2544 // ---------------------------------------------------------------------
2545 /* Here we try other sources */
2546 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2548 Item::Failed(Message
,Cnf
);
2550 /* We don't really want to retry on failed media swaps, this prevents
2551 that. An interesting observation is that permanent failures are not
2553 if (Cnf
->Removable
== true &&
2554 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2556 // Vf = Version.FileList();
2557 while (Vf
.end() == false) ++Vf
;
2558 StoreFilename
= string();
2563 if (QueueNext() == false)
2565 // This is the retry counter
2567 Cnf
->LocalOnly
== false &&
2568 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2571 Vf
= Version
.FileList();
2572 if (QueueNext() == true)
2576 StoreFilename
= string();
2581 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2582 // ---------------------------------------------------------------------
2583 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2588 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2589 // ---------------------------------------------------------------------
2591 void pkgAcqArchive::Finished()
2593 if (Status
== pkgAcquire::Item::StatDone
&&
2596 StoreFilename
= string();
2599 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2600 // ---------------------------------------------------------------------
2601 /* The file is added to the queue */
2602 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2603 unsigned long long Size
,string Dsc
,string ShortDesc
,
2604 const string
&DestDir
, const string
&DestFilename
,
2606 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2608 Retries
= _config
->FindI("Acquire::Retries",0);
2610 if(!DestFilename
.empty())
2611 DestFile
= DestFilename
;
2612 else if(!DestDir
.empty())
2613 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2615 DestFile
= flNotDir(URI
);
2619 Desc
.Description
= Dsc
;
2622 // Set the short description to the archive component
2623 Desc
.ShortDesc
= ShortDesc
;
2625 // Get the transfer sizes
2628 if (stat(DestFile
.c_str(),&Buf
) == 0)
2630 // Hmm, the partial file is too big, erase it
2631 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2632 unlink(DestFile
.c_str());
2634 PartialSize
= Buf
.st_size
;
2640 // AcqFile::Done - Item downloaded OK /*{{{*/
2641 // ---------------------------------------------------------------------
2643 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2644 pkgAcquire::MethodConfig
*Cnf
)
2646 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2649 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2651 RenameOnError(HashSumMismatch
);
2652 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2656 string FileName
= LookupTag(Message
,"Filename");
2657 if (FileName
.empty() == true)
2660 ErrorText
= "Method gave a blank filename";
2666 // The files timestamp matches
2667 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2670 // We have to copy it into place
2671 if (FileName
!= DestFile
)
2674 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2675 Cnf
->Removable
== true)
2677 Desc
.URI
= "copy:" + FileName
;
2682 // Erase the file if it is a symlink so we can overwrite it
2684 if (lstat(DestFile
.c_str(),&St
) == 0)
2686 if (S_ISLNK(St
.st_mode
) != 0)
2687 unlink(DestFile
.c_str());
2691 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2693 _error
->PushToStack();
2694 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
2695 std::stringstream msg
;
2696 _error
->DumpErrors(msg
);
2697 _error
->RevertToStack();
2698 ErrorText
= msg
.str();
2705 // AcqFile::Failed - Failure handler /*{{{*/
2706 // ---------------------------------------------------------------------
2707 /* Here we try other sources */
2708 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2710 Item::Failed(Message
,Cnf
);
2712 // This is the retry counter
2714 Cnf
->LocalOnly
== false &&
2715 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2725 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2726 // ---------------------------------------------------------------------
2727 /* The only header we use is the last-modified header. */
2728 string
pkgAcqFile::Custom600Headers() const
2731 return "\nIndex-File: true";