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 /*{{{*/
107 APT_IGNORE_DEPRECATED_PUSH
108 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
109 HashStringList
const &ExpectedHashes
,
110 pkgAcqMetaBase
*TransactionManager
)
111 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
112 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
113 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
117 if(TransactionManager
!= NULL
)
118 TransactionManager
->Add(this);
120 APT_IGNORE_DEPRECATED_POP
122 // Acquire::Item::~Item - Destructor /*{{{*/
123 // ---------------------------------------------------------------------
125 pkgAcquire::Item::~Item()
130 // Acquire::Item::Failed - Item failed to download /*{{{*/
131 // ---------------------------------------------------------------------
132 /* We return to an idle state if there are still other queues that could
134 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
136 if(ErrorText
.empty())
137 ErrorText
= LookupTag(Message
,"Message");
138 UsedMirror
= LookupTag(Message
,"UsedMirror");
139 if (QueueCounter
<= 1)
141 /* This indicates that the file is not available right now but might
142 be sometime later. If we do a retry cycle then this should be
144 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
145 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
160 string
const FailReason
= LookupTag(Message
, "FailReason");
161 if(FailReason
== "MaximumSizeExceeded")
162 RenameOnError(MaximumSizeExceeded
);
164 // report mirror failure back to LP if we actually use a mirror
165 if(FailReason
.size() != 0)
166 ReportMirrorFailure(FailReason
);
168 ReportMirrorFailure(ErrorText
);
171 // Acquire::Item::Start - Item has begun to download /*{{{*/
172 // ---------------------------------------------------------------------
173 /* Stash status and the file size. Note that setting Complete means
174 sub-phases of the acquire process such as decompresion are operating */
175 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
177 Status
= StatFetching
;
179 if (FileSize
== 0 && Complete
== false)
183 // Acquire::Item::Done - Item downloaded OK /*{{{*/
184 // ---------------------------------------------------------------------
186 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
187 pkgAcquire::MethodConfig
* /*Cnf*/)
189 // We just downloaded something..
190 string FileName
= LookupTag(Message
,"Filename");
191 UsedMirror
= LookupTag(Message
,"UsedMirror");
192 if (Complete
== false && !Local
&& FileName
== DestFile
)
195 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
201 ErrorText
= string();
202 Owner
->Dequeue(this);
205 // Acquire::Item::Rename - Rename a file /*{{{*/
206 // ---------------------------------------------------------------------
207 /* This helper function is used by a lot of item methods as their final
209 bool pkgAcquire::Item::Rename(string From
,string To
)
211 if (rename(From
.c_str(),To
.c_str()) == 0)
215 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
216 From
.c_str(),To
.c_str());
222 void pkgAcquire::Item::QueueURI(ItemDesc
&Item
) /*{{{*/
224 Owner
->Enqueue(Item
);
227 void pkgAcquire::Item::Dequeue() /*{{{*/
229 Owner
->Dequeue(this);
232 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
234 if (RealFileExists(DestFile
))
235 Rename(DestFile
, DestFile
+ ".FAILED");
239 case HashSumMismatch
:
240 ErrorText
= _("Hash Sum mismatch");
241 Status
= StatAuthError
;
242 ReportMirrorFailure("HashChecksumFailure");
245 ErrorText
= _("Size mismatch");
246 Status
= StatAuthError
;
247 ReportMirrorFailure("SizeFailure");
250 ErrorText
= _("Invalid file format");
252 // do not report as usually its not the mirrors fault, but Portal/Proxy
255 ErrorText
= _("Signature error");
259 ErrorText
= _("Does not start with a cleartext signature");
262 case MaximumSizeExceeded
:
263 // the method is expected to report a good error for this
270 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
272 ActiveSubprocess
= subprocess
;
273 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
276 // Acquire::Item::ReportMirrorFailure /*{{{*/
277 // ---------------------------------------------------------------------
278 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
280 // we only act if a mirror was used at all
281 if(UsedMirror
.empty())
284 std::cerr
<< "\nReportMirrorFailure: "
286 << " Uri: " << DescURI()
288 << FailCode
<< std::endl
;
290 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
291 "/usr/lib/apt/apt-report-mirror-failure");
292 if(!FileExists(report
))
295 std::vector
<char const*> Args
;
296 Args
.push_back(report
.c_str());
297 Args
.push_back(UsedMirror
.c_str());
298 Args
.push_back(DescURI().c_str());
299 Args
.push_back(FailCode
.c_str());
300 Args
.push_back(NULL
);
302 pid_t pid
= ExecFork();
305 _error
->Error("ReportMirrorFailure Fork failed");
310 execvp(Args
[0], (char**)Args
.data());
311 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
314 if(!ExecWait(pid
, "report-mirror-failure"))
316 _error
->Warning("Couldn't report problem to '%s'",
317 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
321 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
322 // ---------------------------------------------------------------------
323 /* Get the DiffIndex file first and see if there are patches available
324 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
325 * patches. If anything goes wrong in that process, it will fall back to
326 * the original packages file
328 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
329 pkgAcqMetaBase
*TransactionManager
,
330 IndexTarget
const * const Target
,
331 HashStringList
const &ExpectedHashes
,
332 indexRecords
*MetaIndexParser
)
333 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
334 MetaIndexParser
), PackagesFileReadyInPartial(false)
337 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
339 RealURI
= Target
->URI
;
341 Desc
.Description
= Target
->Description
+ ".diff/Index";
342 Desc
.ShortDesc
= Target
->ShortDesc
;
343 Desc
.URI
= Target
->URI
+ ".diff/Index";
345 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
348 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
350 // look for the current package file
351 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
352 CurrentPackagesFile
+= URItoFileName(RealURI
);
354 // FIXME: this file:/ check is a hack to prevent fetching
355 // from local sources. this is really silly, and
356 // should be fixed cleanly as soon as possible
357 if(!FileExists(CurrentPackagesFile
) ||
358 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
360 // we don't have a pkg file or we don't want to queue
361 Failed("No index file, local or canceld by user", NULL
);
366 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
367 << CurrentPackagesFile
<< std::endl
;
373 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
374 // ---------------------------------------------------------------------
375 /* The only header we use is the last-modified header. */
376 #if APT_PKG_ABI >= 413
377 string
pkgAcqDiffIndex::Custom600Headers() const
379 string
pkgAcqDiffIndex::Custom600Headers()
382 string Final
= _config
->FindDir("Dir::State::lists");
383 Final
+= URItoFileName(Desc
.URI
);
386 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
389 if (stat(Final
.c_str(),&Buf
) != 0)
390 return "\nIndex-File: true";
392 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
395 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
397 // failing here is fine: our caller will take care of trying to
398 // get the complete file if patching fails
400 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
403 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
405 if (_error
->PendingError() == true)
409 if(unlikely(TF
.Step(Tags
) == false))
412 HashStringList ServerHashes
;
413 unsigned long long ServerSize
= 0;
415 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
417 std::string tagname
= *type
;
418 tagname
.append("-Current");
419 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
420 if (tmp
.empty() == true)
424 unsigned long long size
;
425 std::stringstream
ss(tmp
);
427 if (unlikely(hash
.empty() == true))
429 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
431 ServerHashes
.push_back(HashString(*type
, hash
));
435 if (ServerHashes
.usable() == false)
438 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
442 if (ServerHashes
!= HashSums())
446 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
447 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, HashSums());
452 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
454 // we have the same sha1 as the server so we are done here
456 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
458 // list cleanup needs to know that this file as well as the already
459 // present index is ours, so we create an empty diff to save it for us
460 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
461 ExpectedHashes
, MetaIndexParser
);
465 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
466 Hashes LocalHashesCalc
;
467 LocalHashesCalc
.AddFD(fd
);
468 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
471 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
472 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
474 // parse all of (provided) history
475 vector
<DiffInfo
> available_patches
;
476 bool firstAcceptedHashes
= true;
477 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
479 if (LocalHashes
.find(*type
) == NULL
)
482 std::string tagname
= *type
;
483 tagname
.append("-History");
484 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
485 if (tmp
.empty() == true)
488 string hash
, filename
;
489 unsigned long long size
;
490 std::stringstream
ss(tmp
);
492 while (ss
>> hash
>> size
>> filename
)
494 if (unlikely(hash
.empty() == true || filename
.empty() == true))
497 // see if we have a record for this file already
498 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
499 for (; cur
!= available_patches
.end(); ++cur
)
501 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
503 cur
->result_hashes
.push_back(HashString(*type
, hash
));
506 if (cur
!= available_patches
.end())
508 if (firstAcceptedHashes
== true)
511 next
.file
= filename
;
512 next
.result_hashes
.push_back(HashString(*type
, hash
));
513 next
.result_size
= size
;
515 available_patches
.push_back(next
);
520 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
521 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
525 firstAcceptedHashes
= false;
528 if (unlikely(available_patches
.empty() == true))
531 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
532 << "Couldn't find any patches for the patch series." << std::endl
;
536 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
538 if (LocalHashes
.find(*type
) == NULL
)
541 std::string tagname
= *type
;
542 tagname
.append("-Patches");
543 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
544 if (tmp
.empty() == true)
547 string hash
, filename
;
548 unsigned long long size
;
549 std::stringstream
ss(tmp
);
551 while (ss
>> hash
>> size
>> filename
)
553 if (unlikely(hash
.empty() == true || filename
.empty() == true))
556 // see if we have a record for this file already
557 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
558 for (; cur
!= available_patches
.end(); ++cur
)
560 if (cur
->file
!= filename
)
562 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
564 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
565 cur
->patch_size
= size
;
568 if (cur
!= available_patches
.end())
571 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
572 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
577 bool foundStart
= false;
578 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
579 cur
!= available_patches
.end(); ++cur
)
581 if (LocalHashes
!= cur
->result_hashes
)
584 available_patches
.erase(available_patches
.begin(), cur
);
589 if (foundStart
== false || unlikely(available_patches
.empty() == true))
592 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
593 << "Couldn't find the start of the patch series." << std::endl
;
597 // patching with too many files is rather slow compared to a fast download
598 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
599 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
602 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
603 << ") so fallback to complete download" << std::endl
;
607 // calculate the size of all patches we have to get
608 // note that all sizes are uncompressed, while we download compressed files
609 unsigned long long patchesSize
= 0;
610 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
611 cur
!= available_patches
.end(); ++cur
)
612 patchesSize
+= cur
->patch_size
;
613 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
614 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
617 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
618 << ") so fallback to complete download" << std::endl
;
622 // FIXME: make this use the method
623 PackagesFileReadyInPartial
= true;
624 std::string
const Partial
= GetPartialFileNameFromURI(RealURI
);
626 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
627 FileFd
To(Partial
, FileFd::WriteEmpty
);
628 if(CopyFile(From
, To
) == false)
629 return _error
->Errno("CopyFile", "failed to copy");
632 std::cerr
<< "Done copying " << CurrentPackagesFile
636 // we have something, queue the diffs
637 string::size_type
const last_space
= Description
.rfind(" ");
638 if(last_space
!= string::npos
)
639 Description
.erase(last_space
, Description
.size()-last_space
);
641 /* decide if we should download patches one by one or in one go:
642 The first is good if the server merges patches, but many don't so client
643 based merging can be attempt in which case the second is better.
644 "bad things" will happen if patches are merged on the server,
645 but client side merging is attempt as well */
646 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
647 if (pdiff_merge
== true)
649 // reprepro adds this flag if it has merged patches on the server
650 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
651 pdiff_merge
= (precedence
!= "merged");
654 if (pdiff_merge
== false)
656 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
657 MetaIndexParser
, available_patches
);
661 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
662 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
663 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
667 available_patches
[i
],
677 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
679 Item::Failed(Message
,Cnf
);
683 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
684 << "Falling back to normal index file acquire" << std::endl
;
686 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
689 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
690 pkgAcquire::MethodConfig
*Cnf
)
693 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
695 Item::Done(Message
, Size
, Hashes
, Cnf
);
697 // verify the index target
698 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
700 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
701 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
702 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
704 RenameOnError(HashSumMismatch
);
705 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
706 Failed(Message
, Cnf
);
713 FinalFile
= _config
->FindDir("Dir::State::lists");
714 FinalFile
+= URItoFileName(Desc
.URI
);
716 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
717 DestFile
= FinalFile
;
719 if(!ParseDiffIndex(DestFile
))
720 return Failed("Message: Couldn't parse pdiff index", Cnf
);
722 // queue for final move
723 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
731 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
732 // ---------------------------------------------------------------------
733 /* The package diff is added to the queue. one object is constructed
734 * for each diff and the index
736 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
737 pkgAcqMetaBase
*TransactionManager
,
738 struct IndexTarget
const * const Target
,
739 HashStringList
const &ExpectedHashes
,
740 indexRecords
*MetaIndexParser
,
741 vector
<DiffInfo
> diffs
)
742 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
743 available_patches(diffs
)
745 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
747 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
749 RealURI
= Target
->URI
;
751 Description
= Target
->Description
;
752 Desc
.ShortDesc
= Target
->ShortDesc
;
754 if(available_patches
.empty() == true)
756 // we are done (yeah!), check hashes against the final file
757 DestFile
= _config
->FindDir("Dir::State::lists");
758 DestFile
+= URItoFileName(Target
->URI
);
764 State
= StateFetchDiff
;
769 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
771 Item::Failed(Message
,Cnf
);
775 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
776 << "Falling back to normal index file acquire" << std::endl
;
777 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
781 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
782 void pkgAcqIndexDiffs::Finish(bool allDone
)
785 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
787 << Desc
.URI
<< std::endl
;
789 // we restore the original name, this is required, otherwise
790 // the file will be cleaned
793 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
795 RenameOnError(HashSumMismatch
);
801 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
802 FinalFile
+= URItoFileName(RealURI
);
803 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
805 // this is for the "real" finish
810 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
815 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
822 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
824 // calc sha1 of the just patched file
825 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
827 if(!FileExists(FinalFile
))
829 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
833 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
834 Hashes LocalHashesCalc
;
835 LocalHashesCalc
.AddFD(fd
);
836 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
839 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
841 if (unlikely(LocalHashes
.usable() == false || ExpectedHashes
.usable() == false))
843 Failed("Local/Expected hashes are not usable", NULL
);
848 // final file reached before all patches are applied
849 if(LocalHashes
== ExpectedHashes
)
855 // remove all patches until the next matching patch is found
856 // this requires the Index file to be ordered
857 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
858 available_patches
.empty() == false &&
859 I
!= available_patches
.end() &&
860 I
->result_hashes
!= LocalHashes
;
863 available_patches
.erase(I
);
866 // error checking and falling back if no patch was found
867 if(available_patches
.empty() == true)
869 Failed("No patches left to reach target", NULL
);
873 // queue the right diff
874 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
875 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
876 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
879 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
886 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
887 pkgAcquire::MethodConfig
*Cnf
)
890 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
892 Item::Done(Message
, Size
, Hashes
, Cnf
);
894 // FIXME: verify this download too before feeding it to rred
895 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
897 // success in downloading a diff, enter ApplyDiff state
898 if(State
== StateFetchDiff
)
900 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
901 class Hashes LocalHashesCalc
;
902 LocalHashesCalc
.AddFD(fd
);
903 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
905 if (fd
.Size() != available_patches
[0].patch_size
||
906 available_patches
[0].patch_hashes
!= LocalHashes
)
908 Failed("Patch has Size/Hashsum mismatch", NULL
);
912 // rred excepts the patch as $FinalFile.ed
913 Rename(DestFile
,FinalFile
+".ed");
916 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
918 State
= StateApplyDiff
;
920 Desc
.URI
= "rred:" + FinalFile
;
922 SetActiveSubprocess("rred");
927 // success in download/apply a diff, queue next (if needed)
928 if(State
== StateApplyDiff
)
930 // remove the just applied patch
931 available_patches
.erase(available_patches
.begin());
932 unlink((FinalFile
+ ".ed").c_str());
937 std::clog
<< "Moving patched file in place: " << std::endl
938 << DestFile
<< " -> " << FinalFile
<< std::endl
;
940 Rename(DestFile
,FinalFile
);
941 chmod(FinalFile
.c_str(),0644);
943 // see if there is more to download
944 if(available_patches
.empty() == false) {
945 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
946 ExpectedHashes
, MetaIndexParser
,
951 DestFile
= FinalFile
;
956 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
957 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
958 pkgAcqMetaBase
*TransactionManager
,
959 struct IndexTarget
const * const Target
,
960 HashStringList
const &ExpectedHashes
,
961 indexRecords
*MetaIndexParser
,
962 DiffInfo
const &patch
,
963 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
964 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
965 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
967 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
969 RealURI
= Target
->URI
;
971 Description
= Target
->Description
;
972 Desc
.ShortDesc
= Target
->ShortDesc
;
974 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
975 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
977 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + patch
.file
);
980 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
985 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
988 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
990 Item::Failed(Message
,Cnf
);
993 // check if we are the first to fail, otherwise we are done here
994 State
= StateDoneDiff
;
995 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
996 I
!= allPatches
->end(); ++I
)
997 if ((*I
)->State
== StateErrorDiff
)
1000 // first failure means we should fallback
1001 State
= StateErrorDiff
;
1002 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
1003 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
1006 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1007 pkgAcquire::MethodConfig
*Cnf
)
1010 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
1012 Item::Done(Message
,Size
,Hashes
,Cnf
);
1014 // FIXME: verify download before feeding it to rred
1015 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1017 if (State
== StateFetchDiff
)
1019 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1020 class Hashes LocalHashesCalc
;
1021 LocalHashesCalc
.AddFD(fd
);
1022 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1024 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1026 Failed("Patch has Size/Hashsum mismatch", NULL
);
1030 // rred expects the patch as $FinalFile.ed.$patchname.gz
1031 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1033 // check if this is the last completed diff
1034 State
= StateDoneDiff
;
1035 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1036 I
!= allPatches
->end(); ++I
)
1037 if ((*I
)->State
!= StateDoneDiff
)
1040 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1044 // this is the last completed diff, so we are ready to apply now
1045 State
= StateApplyDiff
;
1048 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1051 Desc
.URI
= "rred:" + FinalFile
;
1053 SetActiveSubprocess("rred");
1056 // success in download/apply all diffs, clean up
1057 else if (State
== StateApplyDiff
)
1059 // see if we really got the expected file
1060 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
1062 RenameOnError(HashSumMismatch
);
1067 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1068 FinalFile
+= URItoFileName(RealURI
);
1070 // move the result into place
1072 std::clog
<< "Queue patched file in place: " << std::endl
1073 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1075 // queue for copy by the transaction manager
1076 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1078 // ensure the ed's are gone regardless of list-cleanup
1079 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1080 I
!= allPatches
->end(); ++I
)
1082 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1083 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1084 unlink(patch
.c_str());
1090 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1094 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1095 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1097 if(MetaKey
!= "" && Hashes
.usable())
1099 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1100 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1102 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1109 // AcqIndex::AcqIndex - Constructor /*{{{*/
1110 // ---------------------------------------------------------------------
1111 /* The package file is added to the queue and a second class is
1112 instantiated to fetch the revision file */
1113 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1114 string URI
,string URIDesc
,string ShortDesc
,
1115 HashStringList
const &ExpectedHash
)
1116 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1120 AutoSelectCompression();
1121 Init(URI
, URIDesc
, ShortDesc
);
1123 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1124 std::clog
<< "New pkgIndex with TransactionManager "
1125 << TransactionManager
<< std::endl
;
1128 // AcqIndex::AcqIndex - Constructor /*{{{*/
1129 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1130 pkgAcqMetaBase
*TransactionManager
,
1131 IndexTarget
const *Target
,
1132 HashStringList
const &ExpectedHash
,
1133 indexRecords
*MetaIndexParser
)
1134 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1137 RealURI
= Target
->URI
;
1139 // autoselect the compression method
1140 AutoSelectCompression();
1141 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1143 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1144 std::clog
<< "New pkgIndex with TransactionManager "
1145 << TransactionManager
<< std::endl
;
1148 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1149 void pkgAcqIndex::AutoSelectCompression()
1151 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1152 CompressionExtensions
= "";
1153 if (ExpectedHashes
.usable())
1155 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1156 t
!= types
.end(); ++t
)
1158 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1159 if (*t
== "uncompressed" ||
1160 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1161 CompressionExtensions
.append(*t
).append(" ");
1166 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1167 CompressionExtensions
.append(*t
).append(" ");
1169 if (CompressionExtensions
.empty() == false)
1170 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1173 // AcqIndex::Init - defered Constructor /*{{{*/
1174 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1175 string
const &ShortDesc
)
1177 Stage
= STAGE_DOWNLOAD
;
1179 DestFile
= GetPartialFileNameFromURI(URI
);
1181 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1182 if (CurrentCompressionExtension
== "uncompressed")
1186 MetaKey
= string(Target
->MetaKey
);
1190 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1191 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1193 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1196 // load the filesize
1199 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1201 FileSize
= Record
->Size
;
1203 InitByHashIfNeeded(MetaKey
);
1206 Desc
.Description
= URIDesc
;
1208 Desc
.ShortDesc
= ShortDesc
;
1213 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1214 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1217 // - (maybe?) add support for by-hash into the sources.list as flag
1218 // - make apt-ftparchive generate the hashes (and expire?)
1219 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1220 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1221 _config
->FindB(HostKnob
, false) == true ||
1222 MetaIndexParser
->GetSupportsAcquireByHash())
1224 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1227 // FIXME: should we really use the best hash here? or a fixed one?
1228 const HashString
*TargetHash
= Record
->Hashes
.find("");
1229 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1230 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1231 Desc
.URI
= Desc
.URI
.replace(
1233 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1237 "Fetching ByHash requested but can not find record for %s",
1243 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1244 // ---------------------------------------------------------------------
1245 /* The only header we use is the last-modified header. */
1246 #if APT_PKG_ABI >= 413
1247 string
pkgAcqIndex::Custom600Headers() const
1249 string
pkgAcqIndex::Custom600Headers()
1252 string Final
= GetFinalFilename();
1254 string msg
= "\nIndex-File: true";
1256 if (stat(Final
.c_str(),&Buf
) == 0)
1257 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1259 if(Target
->IsOptional())
1260 msg
+= "\nFail-Ignore: true";
1265 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1266 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1268 Item::Failed(Message
,Cnf
);
1270 size_t const nextExt
= CompressionExtensions
.find(' ');
1271 if (nextExt
!= std::string::npos
)
1273 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1274 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1279 // on decompression failure, remove bad versions in partial/
1280 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1282 unlink(EraseFileName
.c_str());
1285 Item::Failed(Message
,Cnf
);
1287 if(Target
->IsOptional() && ExpectedHashes
.empty() && Stage
== STAGE_DOWNLOAD
)
1290 TransactionManager
->AbortTransaction();
1293 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1294 std::string
pkgAcqIndex::GetFinalFilename() const
1296 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1297 FinalFile
+= URItoFileName(RealURI
);
1298 return GetCompressedFileName(RealURI
, FinalFile
, CurrentCompressionExtension
);
1301 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1302 void pkgAcqIndex::ReverifyAfterIMS()
1304 // update destfile to *not* include the compression extension when doing
1305 // a reverify (as its uncompressed on disk already)
1306 DestFile
= GetCompressedFileName(RealURI
, GetPartialFileNameFromURI(RealURI
), CurrentCompressionExtension
);
1308 // copy FinalFile into partial/ so that we check the hash again
1309 string FinalFile
= GetFinalFilename();
1310 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1311 Desc
.URI
= "copy:" + FinalFile
;
1315 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1316 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1318 // FIXME: this can go away once we only ever download stuff that
1319 // has a valid hash and we never do GET based probing
1320 // FIXME2: this also leaks debian-isms into the code and should go therefore
1322 /* Always validate the index file for correctness (all indexes must
1323 * have a Package field) (LP: #346386) (Closes: #627642)
1325 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1326 // Only test for correctness if the content of the file is not empty
1331 pkgTagFile
tag(&fd
);
1333 // all our current indexes have a field 'Package' in each section
1334 if (_error
->PendingError() == true ||
1335 tag
.Step(sec
) == false ||
1336 sec
.Exists("Package") == false)
1342 // AcqIndex::Done - Finished a fetch /*{{{*/
1343 // ---------------------------------------------------------------------
1344 /* This goes through a number of states.. On the initial fetch the
1345 method could possibly return an alternate filename which points
1346 to the uncompressed version of the file. If this is so the file
1347 is copied into the partial directory. In all other cases the file
1348 is decompressed with a compressed uri. */
1349 void pkgAcqIndex::Done(string Message
,
1350 unsigned long long Size
,
1351 HashStringList
const &Hashes
,
1352 pkgAcquire::MethodConfig
*Cfg
)
1354 Item::Done(Message
,Size
,Hashes
,Cfg
);
1358 case STAGE_DOWNLOAD
:
1359 StageDownloadDone(Message
, Hashes
, Cfg
);
1361 case STAGE_DECOMPRESS_AND_VERIFY
:
1362 StageDecompressDone(Message
, Hashes
, Cfg
);
1367 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1368 void pkgAcqIndex::StageDownloadDone(string Message
,
1369 HashStringList
const &Hashes
,
1370 pkgAcquire::MethodConfig
*Cfg
)
1372 // First check if the calculcated Hash of the (compressed) downloaded
1373 // file matches the hash we have in the MetaIndexRecords for this file
1374 if(VerifyHashByMetaKey(Hashes
) == false)
1376 RenameOnError(HashSumMismatch
);
1377 Failed(Message
, Cfg
);
1383 // Handle the unzipd case
1384 string FileName
= LookupTag(Message
,"Alt-Filename");
1385 if (FileName
.empty() == false)
1387 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1389 DestFile
+= ".decomp";
1390 Desc
.URI
= "copy:" + FileName
;
1392 SetActiveSubprocess("copy");
1396 FileName
= LookupTag(Message
,"Filename");
1397 if (FileName
.empty() == true)
1400 ErrorText
= "Method gave a blank filename";
1403 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1404 // not the "DestFile" we set, in this case we uncompress from the local file
1405 if (FileName
!= DestFile
)
1408 EraseFileName
= FileName
;
1410 // we need to verify the file against the current Release file again
1411 // on if-modfied-since hit to avoid a stale attack against us
1412 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1414 // The files timestamp matches, reverify by copy into partial/
1420 // If we have compressed indexes enabled, queue for hash verification
1421 if (_config
->FindB("Acquire::GzipIndexes",false))
1423 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1425 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1426 Desc
.URI
= "copy:" + FileName
;
1428 SetActiveSubprocess("copy");
1432 // get the binary name for your used compression type
1434 if(CurrentCompressionExtension
== "uncompressed")
1435 decompProg
= "copy";
1437 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1438 if(decompProg
.empty() == true)
1440 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1444 // queue uri for the next stage
1445 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1446 DestFile
+= ".decomp";
1447 Desc
.URI
= decompProg
+ ":" + FileName
;
1449 SetActiveSubprocess(decompProg
);
1452 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1453 void pkgAcqIndex::StageDecompressDone(string Message
,
1454 HashStringList
const &Hashes
,
1455 pkgAcquire::MethodConfig
*Cfg
)
1457 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1460 RenameOnError(HashSumMismatch
);
1461 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1462 Failed(Message
, Cfg
);
1466 if(!ValidateFile(DestFile
))
1468 RenameOnError(InvalidFormat
);
1469 Failed(Message
, Cfg
);
1473 // remove the compressed version of the file
1474 unlink(EraseFileName
.c_str());
1476 // Done, queue for rename on transaction finished
1477 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1482 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1483 void pkgAcqMetaBase::Add(Item
*I
)
1485 Transaction
.push_back(I
);
1488 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1489 void pkgAcqMetaBase::AbortTransaction()
1491 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1492 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1494 // ensure the toplevel is in error state too
1495 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1496 I
!= Transaction
.end(); ++I
)
1498 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1499 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1500 // the transaction will abort, so stop anything that is idle
1501 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1503 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1507 Transaction
.clear();
1510 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1511 bool pkgAcqMetaBase::TransactionHasError()
1513 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1514 I
!= Transaction
.end(); ++I
)
1515 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1516 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1522 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1523 void pkgAcqMetaBase::CommitTransaction()
1525 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1526 std::clog
<< "CommitTransaction: " << this << std::endl
;
1528 // move new files into place *and* remove files that are not
1529 // part of the transaction but are still on disk
1530 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1531 I
!= Transaction
.end(); ++I
)
1533 if((*I
)->PartialFile
!= "")
1535 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1536 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1537 << (*I
)->DescURI() << std::endl
;
1539 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1541 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1547 unlink((*I
)->DestFile
.c_str());
1549 // mark that this transaction is finished
1550 (*I
)->TransactionManager
= 0;
1552 Transaction
.clear();
1555 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1556 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1557 const std::string
&From
,
1558 const std::string
&To
)
1560 I
->PartialFile
= From
;
1564 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1565 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1566 const std::string
&FinalFile
)
1568 I
->PartialFile
= "";
1569 I
->DestFile
= FinalFile
;
1572 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1573 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&RealURI
,
1574 const std::string
&Message
)
1576 // FIXME: this entire function can do now that we disallow going to
1577 // a unauthenticated state and can cleanly rollback
1579 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1581 if(FileExists(Final
))
1583 Status
= StatTransientNetworkError
;
1584 _error
->Warning(_("An error occurred during the signature "
1585 "verification. The repository is not updated "
1586 "and the previous index files will be used. "
1587 "GPG error: %s: %s\n"),
1588 Desc
.Description
.c_str(),
1589 LookupTag(Message
,"Message").c_str());
1590 RunScripts("APT::Update::Auth-Failure");
1592 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1593 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1594 _error
->Error(_("GPG error: %s: %s"),
1595 Desc
.Description
.c_str(),
1596 LookupTag(Message
,"Message").c_str());
1600 _error
->Warning(_("GPG error: %s: %s"),
1601 Desc
.Description
.c_str(),
1602 LookupTag(Message
,"Message").c_str());
1604 // gpgv method failed
1605 ReportMirrorFailure("GPGFailure");
1609 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1610 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1611 pkgAcqMetaBase
*TransactionManager
,
1612 string URI
,string URIDesc
,string ShortDesc
,
1613 string MetaIndexFile
,
1614 const vector
<IndexTarget
*>* IndexTargets
,
1615 indexRecords
* MetaIndexParser
) :
1616 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1617 HashStringList(), TransactionManager
),
1618 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1619 ShortDesc(ShortDesc
)
1621 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1622 DestFile
+= URItoFileName(RealURI
);
1624 // remove any partial downloaded sig-file in partial/.
1625 // it may confuse proxies and is too small to warrant a
1626 // partial download anyway
1627 unlink(DestFile
.c_str());
1629 // set the TransactionManager
1630 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1631 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1632 << TransactionManager
<< std::endl
;
1635 Desc
.Description
= URIDesc
;
1637 Desc
.ShortDesc
= ShortDesc
;
1643 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1647 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1648 // ---------------------------------------------------------------------
1649 #if APT_PKG_ABI >= 413
1650 string
pkgAcqMetaSig::Custom600Headers() const
1652 string
pkgAcqMetaSig::Custom600Headers()
1655 std::string Header
= GetCustom600Headers(RealURI
);
1659 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1660 // ---------------------------------------------------------------------
1661 /* The only header we use is the last-modified header. */
1662 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1663 HashStringList
const &Hashes
,
1664 pkgAcquire::MethodConfig
*Cfg
)
1666 Item::Done(Message
, Size
, Hashes
, Cfg
);
1668 if(AuthPass
== false)
1670 if(CheckDownloadDone(Message
, RealURI
) == true)
1672 // destfile will be modified to point to MetaIndexFile for the
1673 // gpgv method, so we need to save it here
1674 MetaIndexFileSignature
= DestFile
;
1675 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1681 if(CheckAuthDone(Message
, RealURI
) == true)
1683 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1684 FinalFile
+= URItoFileName(RealURI
);
1685 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1690 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1692 Item::Failed(Message
,Cnf
);
1694 // check if we need to fail at this point
1695 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1698 // FIXME: meh, this is not really elegant
1699 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1700 string
const InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1702 string
const FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1704 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1706 std::string downgrade_msg
;
1707 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1709 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1711 // meh, the users wants to take risks (we still mark the packages
1712 // from this repository as unauthenticated)
1713 _error
->Warning("%s", downgrade_msg
.c_str());
1714 _error
->Warning(_("This is normally not allowed, but the option "
1715 "Acquire::AllowDowngradeToInsecureRepositories was "
1716 "given to override it."));
1719 _error
->Error("%s", downgrade_msg
.c_str());
1720 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1721 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1722 TransactionManager
->AbortTransaction();
1727 _error
->Warning(_("The data from '%s' is not signed. Packages "
1728 "from that repository can not be authenticated."),
1731 // this ensures that any file in the lists/ dir is removed by the
1733 DestFile
= GetPartialFileNameFromURI(RealURI
);
1734 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1736 // only allow going further if the users explicitely wants it
1737 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
1739 // we parse the indexes here because at this point the user wanted
1740 // a repository that may potentially harm him
1741 MetaIndexParser
->Load(MetaIndexFile
);
1745 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1746 if (Cnf
->LocalOnly
== true ||
1747 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1754 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1755 pkgAcqMetaBase
*TransactionManager
,
1756 string URI
,string URIDesc
,string ShortDesc
,
1757 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1758 const vector
<IndexTarget
*>* IndexTargets
,
1759 indexRecords
* MetaIndexParser
) :
1760 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1761 TransactionManager
),
1762 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1763 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1764 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1766 if(TransactionManager
== NULL
)
1768 this->TransactionManager
= this;
1769 this->TransactionManager
->Add(this);
1772 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1773 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1774 << this->TransactionManager
<< std::endl
;
1777 Init(URIDesc
, ShortDesc
);
1780 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1781 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1783 DestFile
= GetPartialFileNameFromURI(RealURI
);
1786 Desc
.Description
= URIDesc
;
1788 Desc
.ShortDesc
= ShortDesc
;
1791 // we expect more item
1792 ExpectedAdditionalItems
= IndexTargets
->size();
1796 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1797 // ---------------------------------------------------------------------
1798 #if APT_PKG_ABI >= 413
1799 string
pkgAcqMetaIndex::Custom600Headers() const
1801 string
pkgAcqMetaIndex::Custom600Headers()
1804 return GetCustom600Headers(RealURI
);
1807 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1808 HashStringList
const &Hashes
,
1809 pkgAcquire::MethodConfig
*Cfg
)
1811 Item::Done(Message
,Size
,Hashes
,Cfg
);
1813 if(CheckDownloadDone(Message
, RealURI
))
1815 // we have a Release file, now download the Signature, all further
1816 // verify/queue for additional downloads will be done in the
1817 // pkgAcqMetaSig::Done() code
1818 std::string MetaIndexFile
= DestFile
;
1819 new pkgAcqMetaSig(Owner
, TransactionManager
,
1820 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1821 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1824 string FinalFile
= _config
->FindDir("Dir::State::lists");
1825 FinalFile
+= URItoFileName(RealURI
);
1826 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1830 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1832 // At this point, the gpgv method has succeeded, so there is a
1833 // valid signature from a key in the trusted keyring. We
1834 // perform additional verification of its contents, and use them
1835 // to verify the indexes we are about to download
1837 if (!MetaIndexParser
->Load(DestFile
))
1839 Status
= StatAuthError
;
1840 ErrorText
= MetaIndexParser
->ErrorText
;
1844 if (!VerifyVendor(Message
, RealURI
))
1849 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1850 std::cerr
<< "Signature verification succeeded: "
1851 << DestFile
<< std::endl
;
1853 // Download further indexes with verification
1855 // it would be really nice if we could simply do
1856 // if (IMSHit == false) QueueIndexes(true)
1857 // and skip the download if the Release file has not changed
1858 // - but right now the list cleaner will needs to be tricked
1859 // to not delete all our packages/source indexes in this case
1865 // pkgAcqMetaBase::GetCustom600Headers - Get header for AcqMetaBase /*{{{*/
1866 // ---------------------------------------------------------------------
1867 string
pkgAcqMetaBase::GetCustom600Headers(const string
&RealURI
) const
1869 std::string Header
= "\nIndex-File: true";
1870 std::string MaximumSize
;
1871 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1872 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1873 Header
+= MaximumSize
;
1875 string FinalFile
= _config
->FindDir("Dir::State::lists");
1876 FinalFile
+= URItoFileName(RealURI
);
1879 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1880 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1885 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1886 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1887 const std::string
&MetaIndexFileSignature
)
1890 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1891 DestFile
= MetaIndexFile
;
1893 SetActiveSubprocess("gpgv");
1896 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1897 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1898 const std::string
&RealURI
)
1900 // We have just finished downloading a Release file (it is not
1903 string FileName
= LookupTag(Message
,"Filename");
1904 if (FileName
.empty() == true)
1907 ErrorText
= "Method gave a blank filename";
1911 if (FileName
!= DestFile
)
1914 Desc
.URI
= "copy:" + FileName
;
1919 // make sure to verify against the right file on I-M-S hit
1920 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1923 string FinalFile
= _config
->FindDir("Dir::State::lists");
1924 FinalFile
+= URItoFileName(RealURI
);
1925 DestFile
= FinalFile
;
1928 // set Item to complete as the remaining work is all local (verify etc)
1934 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1936 // at this point the real Items are loaded in the fetcher
1937 ExpectedAdditionalItems
= 0;
1939 vector
<struct IndexTarget
*>::const_iterator Target
;
1940 for (Target
= IndexTargets
->begin();
1941 Target
!= IndexTargets
->end();
1944 HashStringList ExpectedIndexHashes
;
1945 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1947 // optional target that we do not have in the Release file are
1949 if (verify
== true && Record
== NULL
&& (*Target
)->IsOptional())
1952 // targets without a hash record are a error when verify is required
1953 if (verify
== true && Record
== NULL
)
1955 Status
= StatAuthError
;
1956 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1961 ExpectedIndexHashes
= Record
->Hashes
;
1963 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1965 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1966 << "Expected Hash:" << std::endl
;
1967 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1968 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1969 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1972 if (verify
== true && ExpectedIndexHashes
.empty() == true)
1974 Status
= StatAuthError
;
1975 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1979 /* Queue the Index file (Packages, Sources, Translation-$foo
1980 (either diff or full packages files, depending
1981 on the users option) - we also check if the PDiff Index file is listed
1982 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1983 instead, but passing the required info to it is to much hassle */
1984 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1985 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1986 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1988 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1992 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
1994 string::size_type pos
;
1996 // check for missing sigs (that where not fatal because otherwise we had
1999 string msg
= _("There is no public key available for the "
2000 "following key IDs:\n");
2001 pos
= Message
.find("NO_PUBKEY ");
2002 if (pos
!= std::string::npos
)
2004 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2005 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2006 missingkeys
+= (Fingerprint
);
2008 if(!missingkeys
.empty())
2009 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2011 string Transformed
= MetaIndexParser
->GetExpectedDist();
2013 if (Transformed
== "../project/experimental")
2015 Transformed
= "experimental";
2018 pos
= Transformed
.rfind('/');
2019 if (pos
!= string::npos
)
2021 Transformed
= Transformed
.substr(0, pos
);
2024 if (Transformed
== ".")
2029 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2030 MetaIndexParser
->GetValidUntil() > 0) {
2031 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2032 if (invalid_since
> 0)
2033 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2034 // the time since then the file is invalid - formated in the same way as in
2035 // the download progress display (e.g. 7d 3h 42min 1s)
2036 return _error
->Error(
2037 _("Release file for %s is expired (invalid since %s). "
2038 "Updates for this repository will not be applied."),
2039 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2042 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2044 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2045 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2046 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2049 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2051 // This might become fatal one day
2052 // Status = StatAuthError;
2053 // ErrorText = "Conflicting distribution; expected "
2054 // + MetaIndexParser->GetExpectedDist() + " but got "
2055 // + MetaIndexParser->GetDist();
2057 if (!Transformed
.empty())
2059 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2060 Desc
.Description
.c_str(),
2061 Transformed
.c_str(),
2062 MetaIndexParser
->GetDist().c_str());
2069 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2070 void pkgAcqMetaIndex::Failed(string Message
,
2071 pkgAcquire::MethodConfig
* Cnf
)
2073 pkgAcquire::Item::Failed(Message
, Cnf
);
2076 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2078 _error
->Warning(_("The repository '%s' does not have a Release file. "
2079 "This is deprecated, please contact the owner of the "
2080 "repository."), URIDesc
.c_str());
2082 // No Release file was present so fall
2083 // back to queueing Packages files without verification
2084 // only allow going further if the users explicitely wants it
2085 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2087 // Done, queue for rename on transaction finished
2088 if (FileExists(DestFile
))
2089 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2091 // queue without any kind of hashsum support
2092 QueueIndexes(false);
2096 void pkgAcqMetaIndex::Finished() /*{{{*/
2098 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2099 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2100 if(TransactionManager
!= NULL
&&
2101 TransactionManager
->TransactionHasError() == false)
2102 TransactionManager
->CommitTransaction();
2105 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2106 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2107 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2108 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2109 const vector
<IndexTarget
*>* IndexTargets
,
2110 indexRecords
* MetaIndexParser
) :
2111 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2112 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2113 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2115 // index targets + (worst case:) Release/Release.gpg
2116 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2120 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2124 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2125 // ---------------------------------------------------------------------
2126 #if APT_PKG_ABI >= 413
2127 string
pkgAcqMetaClearSig::Custom600Headers() const
2129 string
pkgAcqMetaClearSig::Custom600Headers()
2132 string Header
= GetCustom600Headers(RealURI
);
2133 Header
+= "\nFail-Ignore: true";
2137 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2138 // ---------------------------------------------------------------------
2139 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2140 HashStringList
const &Hashes
,
2141 pkgAcquire::MethodConfig
*Cnf
)
2143 Item::Done(Message
, Size
, Hashes
, Cnf
);
2145 // if we expect a ClearTextSignature (InRelase), ensure that
2146 // this is what we get and if not fail to queue a
2147 // Release/Release.gpg, see #346386
2148 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2150 pkgAcquire::Item::Failed(Message
, Cnf
);
2151 RenameOnError(NotClearsigned
);
2152 TransactionManager
->AbortTransaction();
2156 if(AuthPass
== false)
2158 if(CheckDownloadDone(Message
, RealURI
) == true)
2159 QueueForSignatureVerify(DestFile
, DestFile
);
2164 if(CheckAuthDone(Message
, RealURI
) == true)
2166 string FinalFile
= _config
->FindDir("Dir::State::lists");
2167 FinalFile
+= URItoFileName(RealURI
);
2169 // queue for copy in place
2170 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2175 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2177 Item::Failed(Message
, Cnf
);
2179 // we failed, we will not get additional items from this method
2180 ExpectedAdditionalItems
= 0;
2182 if (AuthPass
== false)
2184 // Queue the 'old' InRelease file for removal if we try Release.gpg
2185 // as otherwise the file will stay around and gives a false-auth
2186 // impression (CVE-2012-0214)
2187 string FinalFile
= _config
->FindDir("Dir::State::lists");
2188 FinalFile
.append(URItoFileName(RealURI
));
2189 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2192 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2193 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2194 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2195 IndexTargets
, MetaIndexParser
);
2199 if(CheckStopAuthentication(RealURI
, Message
))
2202 _error
->Warning(_("The data from '%s' is not signed. Packages "
2203 "from that repository can not be authenticated."),
2206 // No Release file was present, or verification failed, so fall
2207 // back to queueing Packages files without verification
2208 // only allow going further if the users explicitely wants it
2209 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2213 /* Always move the meta index, even if gpgv failed. This ensures
2214 * that PackageFile objects are correctly filled in */
2215 if (FileExists(DestFile
))
2217 string FinalFile
= _config
->FindDir("Dir::State::lists");
2218 FinalFile
+= URItoFileName(RealURI
);
2219 /* InRelease files become Release files, otherwise
2220 * they would be considered as trusted later on */
2221 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2223 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2226 // Done, queue for rename on transaction finished
2227 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2229 QueueIndexes(false);
2234 // AcqArchive::AcqArchive - Constructor /*{{{*/
2235 // ---------------------------------------------------------------------
2236 /* This just sets up the initial fetch environment and queues the first
2238 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2239 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2240 string
&StoreFilename
) :
2241 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2242 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2245 Retries
= _config
->FindI("Acquire::Retries",0);
2247 if (Version
.Arch() == 0)
2249 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2250 "This might mean you need to manually fix this package. "
2251 "(due to missing arch)"),
2252 Version
.ParentPkg().FullName().c_str());
2256 /* We need to find a filename to determine the extension. We make the
2257 assumption here that all the available sources for this version share
2258 the same extension.. */
2259 // Skip not source sources, they do not have file fields.
2260 for (; Vf
.end() == false; ++Vf
)
2262 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2267 // Does not really matter here.. we are going to fail out below
2268 if (Vf
.end() != true)
2270 // If this fails to get a file name we will bomb out below.
2271 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2272 if (_error
->PendingError() == true)
2275 // Generate the final file name as: package_version_arch.foo
2276 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2277 QuoteString(Version
.VerStr(),"_:") + '_' +
2278 QuoteString(Version
.Arch(),"_:.") +
2279 "." + flExtension(Parse
.FileName());
2282 // check if we have one trusted source for the package. if so, switch
2283 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2284 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2285 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2286 bool seenUntrusted
= false;
2287 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2289 pkgIndexFile
*Index
;
2290 if (Sources
->FindIndex(i
.File(),Index
) == false)
2293 if (debugAuth
== true)
2294 std::cerr
<< "Checking index: " << Index
->Describe()
2295 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2297 if (Index
->IsTrusted() == true)
2300 if (allowUnauth
== false)
2304 seenUntrusted
= true;
2307 // "allow-unauthenticated" restores apts old fetching behaviour
2308 // that means that e.g. unauthenticated file:// uris are higher
2309 // priority than authenticated http:// uris
2310 if (allowUnauth
== true && seenUntrusted
== true)
2314 if (QueueNext() == false && _error
->PendingError() == false)
2315 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2316 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2319 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2320 // ---------------------------------------------------------------------
2321 /* This queues the next available file version for download. It checks if
2322 the archive is already available in the cache and stashs the MD5 for
2324 bool pkgAcqArchive::QueueNext()
2326 for (; Vf
.end() == false; ++Vf
)
2328 // Ignore not source sources
2329 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2332 // Try to cross match against the source list
2333 pkgIndexFile
*Index
;
2334 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2337 // only try to get a trusted package from another source if that source
2339 if(Trusted
&& !Index
->IsTrusted())
2342 // Grab the text package record
2343 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2344 if (_error
->PendingError() == true)
2347 string PkgFile
= Parse
.FileName();
2348 ExpectedHashes
= Parse
.Hashes();
2350 if (PkgFile
.empty() == true)
2351 return _error
->Error(_("The package index files are corrupted. No Filename: "
2352 "field for package %s."),
2353 Version
.ParentPkg().Name());
2355 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2356 Desc
.Description
= Index
->ArchiveInfo(Version
);
2358 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2360 // See if we already have the file. (Legacy filenames)
2361 FileSize
= Version
->Size
;
2362 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2364 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2366 // Make sure the size matches
2367 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2372 StoreFilename
= DestFile
= FinalFile
;
2376 /* Hmm, we have a file and its size does not match, this means it is
2377 an old style mismatched arch */
2378 unlink(FinalFile
.c_str());
2381 // Check it again using the new style output filenames
2382 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2383 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2385 // Make sure the size matches
2386 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2391 StoreFilename
= DestFile
= FinalFile
;
2395 /* Hmm, we have a file and its size does not match, this shouldn't
2397 unlink(FinalFile
.c_str());
2400 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2402 // Check the destination file
2403 if (stat(DestFile
.c_str(),&Buf
) == 0)
2405 // Hmm, the partial file is too big, erase it
2406 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2407 unlink(DestFile
.c_str());
2409 PartialSize
= Buf
.st_size
;
2412 // Disables download of archives - useful if no real installation follows,
2413 // e.g. if we are just interested in proposed installation order
2414 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2419 StoreFilename
= DestFile
= FinalFile
;
2433 // AcqArchive::Done - Finished fetching /*{{{*/
2434 // ---------------------------------------------------------------------
2436 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2437 pkgAcquire::MethodConfig
*Cfg
)
2439 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2442 if (Size
!= Version
->Size
)
2444 RenameOnError(SizeMismatch
);
2448 // FIXME: could this empty() check impose *any* sort of security issue?
2449 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2451 RenameOnError(HashSumMismatch
);
2452 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2456 // Grab the output filename
2457 string FileName
= LookupTag(Message
,"Filename");
2458 if (FileName
.empty() == true)
2461 ErrorText
= "Method gave a blank filename";
2465 // Reference filename
2466 if (FileName
!= DestFile
)
2468 StoreFilename
= DestFile
= FileName
;
2474 // Done, move it into position
2475 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2476 FinalFile
+= flNotDir(StoreFilename
);
2477 Rename(DestFile
,FinalFile
);
2478 StoreFilename
= DestFile
= FinalFile
;
2482 // AcqArchive::Failed - Failure handler /*{{{*/
2483 // ---------------------------------------------------------------------
2484 /* Here we try other sources */
2485 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2487 Item::Failed(Message
,Cnf
);
2489 /* We don't really want to retry on failed media swaps, this prevents
2490 that. An interesting observation is that permanent failures are not
2492 if (Cnf
->Removable
== true &&
2493 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2495 // Vf = Version.FileList();
2496 while (Vf
.end() == false) ++Vf
;
2497 StoreFilename
= string();
2502 if (QueueNext() == false)
2504 // This is the retry counter
2506 Cnf
->LocalOnly
== false &&
2507 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2510 Vf
= Version
.FileList();
2511 if (QueueNext() == true)
2515 StoreFilename
= string();
2520 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2521 // ---------------------------------------------------------------------
2522 #if APT_PKG_ABI >= 413
2523 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2525 APT_PURE
bool pkgAcqArchive::IsTrusted()
2531 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2532 // ---------------------------------------------------------------------
2534 void pkgAcqArchive::Finished()
2536 if (Status
== pkgAcquire::Item::StatDone
&&
2539 StoreFilename
= string();
2542 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2543 // ---------------------------------------------------------------------
2544 /* The file is added to the queue */
2545 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2546 unsigned long long Size
,string Dsc
,string ShortDesc
,
2547 const string
&DestDir
, const string
&DestFilename
,
2549 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2551 Retries
= _config
->FindI("Acquire::Retries",0);
2553 if(!DestFilename
.empty())
2554 DestFile
= DestFilename
;
2555 else if(!DestDir
.empty())
2556 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2558 DestFile
= flNotDir(URI
);
2562 Desc
.Description
= Dsc
;
2565 // Set the short description to the archive component
2566 Desc
.ShortDesc
= ShortDesc
;
2568 // Get the transfer sizes
2571 if (stat(DestFile
.c_str(),&Buf
) == 0)
2573 // Hmm, the partial file is too big, erase it
2574 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2575 unlink(DestFile
.c_str());
2577 PartialSize
= Buf
.st_size
;
2583 // AcqFile::Done - Item downloaded OK /*{{{*/
2584 // ---------------------------------------------------------------------
2586 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2587 pkgAcquire::MethodConfig
*Cnf
)
2589 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2592 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2594 RenameOnError(HashSumMismatch
);
2595 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2599 string FileName
= LookupTag(Message
,"Filename");
2600 if (FileName
.empty() == true)
2603 ErrorText
= "Method gave a blank filename";
2609 // The files timestamp matches
2610 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2613 // We have to copy it into place
2614 if (FileName
!= DestFile
)
2617 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2618 Cnf
->Removable
== true)
2620 Desc
.URI
= "copy:" + FileName
;
2625 // Erase the file if it is a symlink so we can overwrite it
2627 if (lstat(DestFile
.c_str(),&St
) == 0)
2629 if (S_ISLNK(St
.st_mode
) != 0)
2630 unlink(DestFile
.c_str());
2634 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2636 _error
->PushToStack();
2637 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
2638 std::stringstream msg
;
2639 _error
->DumpErrors(msg
);
2640 _error
->RevertToStack();
2641 ErrorText
= msg
.str();
2648 // AcqFile::Failed - Failure handler /*{{{*/
2649 // ---------------------------------------------------------------------
2650 /* Here we try other sources */
2651 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2653 Item::Failed(Message
,Cnf
);
2655 // This is the retry counter
2657 Cnf
->LocalOnly
== false &&
2658 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2668 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2669 // ---------------------------------------------------------------------
2670 /* The only header we use is the last-modified header. */
2671 #if APT_PKG_ABI >= 413
2672 string
pkgAcqFile::Custom600Headers() const
2674 string
pkgAcqFile::Custom600Headers()
2678 return "\nIndex-File: true";