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
GetFinalFileNameFromURI(std::string
const &uri
) /*{{{*/
79 return _config
->FindDir("Dir::State::lists") + URItoFileName(uri
);
82 static std::string
GetCompressedFileName(std::string
const &URI
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
84 if (Ext
.empty() || Ext
== "uncompressed")
87 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
88 // file when its doing the indexcopy
89 if (URI
.substr(0,6) == "cdrom:")
92 // adjust DestFile if its compressed on disk
93 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
94 return Name
+ '.' + Ext
;
98 static bool AllowInsecureRepositories(indexRecords
const * const MetaIndexParser
, pkgAcqMetaBase
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
100 if(MetaIndexParser
->IsAlwaysTrusted() || _config
->FindB("Acquire::AllowInsecureRepositories") == true)
103 _error
->Error(_("Use --allow-insecure-repositories to force the update"));
104 TransactionManager
->AbortTransaction();
105 I
->Status
= pkgAcquire::Item::StatError
;
111 // Acquire::Item::Item - Constructor /*{{{*/
112 APT_IGNORE_DEPRECATED_PUSH
113 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
114 HashStringList
const &ExpectedHashes
,
115 pkgAcqMetaBase
*TransactionManager
)
116 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
117 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
118 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
122 if(TransactionManager
!= NULL
)
123 TransactionManager
->Add(this);
125 APT_IGNORE_DEPRECATED_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 (From
== To
|| 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 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
228 /* The idea here is that an item isn't queued if it exists on disk and the
229 transition manager was a hit as this means that the files it contains
230 the checksums for can't be updated either (or they are and we are asking
231 for a hashsum mismatch to happen which helps nobody) */
232 bool pkgAcquire::Item::QueueURI(ItemDesc
&Item
)
234 std::string
const FinalFile
= GetFinalFilename();
235 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
236 FileExists(FinalFile
) == true)
238 PartialFile
= DestFile
= FinalFile
;
243 Owner
->Enqueue(Item
);
246 /* The transition manager InRelease itself (or its older sisters-in-law
247 Release & Release.gpg) is always queued as this allows us to rerun gpgv
248 on it to verify that we aren't stalled with old files */
249 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
251 Owner
->Enqueue(Item
);
254 /* the Diff/Index needs to queue also the up-to-date complete index file
255 to ensure that the list cleaner isn't eating it */
256 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
258 if (pkgAcquire::Item::QueueURI(Item
) == true)
264 void pkgAcquire::Item::Dequeue() /*{{{*/
266 Owner
->Dequeue(this);
269 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
271 if (RealFileExists(DestFile
))
272 Rename(DestFile
, DestFile
+ ".FAILED");
276 case HashSumMismatch
:
277 ErrorText
= _("Hash Sum mismatch");
278 Status
= StatAuthError
;
279 ReportMirrorFailure("HashChecksumFailure");
282 ErrorText
= _("Size mismatch");
283 Status
= StatAuthError
;
284 ReportMirrorFailure("SizeFailure");
287 ErrorText
= _("Invalid file format");
289 // do not report as usually its not the mirrors fault, but Portal/Proxy
292 ErrorText
= _("Signature error");
296 ErrorText
= _("Does not start with a cleartext signature");
299 case MaximumSizeExceeded
:
300 // the method is expected to report a good error for this
307 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
309 ActiveSubprocess
= subprocess
;
310 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
313 // Acquire::Item::GetFinalFilename - Return the full final file path /*{{{*/
314 std::string
pkgAcquire::Item::GetFinalFilename() const
316 return GetFinalFileNameFromURI(Desc
.URI
);
319 // Acquire::Item::ReportMirrorFailure /*{{{*/
320 // ---------------------------------------------------------------------
321 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
323 // we only act if a mirror was used at all
324 if(UsedMirror
.empty())
327 std::cerr
<< "\nReportMirrorFailure: "
329 << " Uri: " << DescURI()
331 << FailCode
<< std::endl
;
333 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
334 "/usr/lib/apt/apt-report-mirror-failure");
335 if(!FileExists(report
))
338 std::vector
<char const*> Args
;
339 Args
.push_back(report
.c_str());
340 Args
.push_back(UsedMirror
.c_str());
341 Args
.push_back(DescURI().c_str());
342 Args
.push_back(FailCode
.c_str());
343 Args
.push_back(NULL
);
345 pid_t pid
= ExecFork();
348 _error
->Error("ReportMirrorFailure Fork failed");
353 execvp(Args
[0], (char**)Args
.data());
354 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
357 if(!ExecWait(pid
, "report-mirror-failure"))
359 _error
->Warning("Couldn't report problem to '%s'",
360 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
364 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
365 // ---------------------------------------------------------------------
366 /* Get the DiffIndex file first and see if there are patches available
367 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
368 * patches. If anything goes wrong in that process, it will fall back to
369 * the original packages file
371 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
372 pkgAcqMetaBase
*TransactionManager
,
373 IndexTarget
const * const Target
,
374 HashStringList
const &ExpectedHashes
,
375 indexRecords
*MetaIndexParser
)
376 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
377 MetaIndexParser
), PackagesFileReadyInPartial(false)
380 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
382 RealURI
= Target
->URI
;
384 Desc
.Description
= Target
->Description
+ ".diff/Index";
385 Desc
.ShortDesc
= Target
->ShortDesc
;
386 Desc
.URI
= Target
->URI
+ ".diff/Index";
388 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
391 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
393 // look for the current package file
394 CurrentPackagesFile
= GetFinalFileNameFromURI(RealURI
);
396 // FIXME: this file:/ check is a hack to prevent fetching
397 // from local sources. this is really silly, and
398 // should be fixed cleanly as soon as possible
399 if(!FileExists(CurrentPackagesFile
) ||
400 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
402 // we don't have a pkg file or we don't want to queue
403 Failed("No index file, local or canceld by user", NULL
);
408 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
409 << CurrentPackagesFile
<< std::endl
;
415 // Acquire::Item::GetFinalFilename - Return the full final file path /*{{{*/
416 std::string
pkgAcqDiffIndex::GetFinalFilename() const
418 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
419 return pkgAcquire::Item::GetFinalFilename();
422 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
423 // ---------------------------------------------------------------------
424 /* The only header we use is the last-modified header. */
425 #if APT_PKG_ABI >= 413
426 string
pkgAcqDiffIndex::Custom600Headers() const
428 string
pkgAcqDiffIndex::Custom600Headers()
431 string
const Final
= GetFinalFilename();
434 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
437 if (stat(Final
.c_str(),&Buf
) != 0)
438 return "\nIndex-File: true";
440 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
443 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
445 // list cleanup needs to know that this file as well as the already
446 // present index is ours, so we create an empty diff to save it for us
447 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
448 ExpectedHashes
, MetaIndexParser
);
451 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
453 // failing here is fine: our caller will take care of trying to
454 // get the complete file if patching fails
456 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
459 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
461 if (_error
->PendingError() == true)
465 if(unlikely(TF
.Step(Tags
) == false))
468 HashStringList ServerHashes
;
469 unsigned long long ServerSize
= 0;
471 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
473 std::string tagname
= *type
;
474 tagname
.append("-Current");
475 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
476 if (tmp
.empty() == true)
480 unsigned long long size
;
481 std::stringstream
ss(tmp
);
483 if (unlikely(hash
.empty() == true))
485 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
487 ServerHashes
.push_back(HashString(*type
, hash
));
491 if (ServerHashes
.usable() == false)
494 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
498 if (ServerHashes
!= HashSums())
502 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
503 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, HashSums());
508 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
510 // we have the same sha1 as the server so we are done here
512 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
517 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
518 Hashes LocalHashesCalc
;
519 LocalHashesCalc
.AddFD(fd
);
520 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
523 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
524 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
526 // parse all of (provided) history
527 vector
<DiffInfo
> available_patches
;
528 bool firstAcceptedHashes
= true;
529 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
531 if (LocalHashes
.find(*type
) == NULL
)
534 std::string tagname
= *type
;
535 tagname
.append("-History");
536 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
537 if (tmp
.empty() == true)
540 string hash
, filename
;
541 unsigned long long size
;
542 std::stringstream
ss(tmp
);
544 while (ss
>> hash
>> size
>> filename
)
546 if (unlikely(hash
.empty() == true || filename
.empty() == true))
549 // see if we have a record for this file already
550 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
551 for (; cur
!= available_patches
.end(); ++cur
)
553 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
555 cur
->result_hashes
.push_back(HashString(*type
, hash
));
558 if (cur
!= available_patches
.end())
560 if (firstAcceptedHashes
== true)
563 next
.file
= filename
;
564 next
.result_hashes
.push_back(HashString(*type
, hash
));
565 next
.result_size
= size
;
567 available_patches
.push_back(next
);
572 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
573 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
577 firstAcceptedHashes
= false;
580 if (unlikely(available_patches
.empty() == true))
583 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
584 << "Couldn't find any patches for the patch series." << std::endl
;
588 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
590 if (LocalHashes
.find(*type
) == NULL
)
593 std::string tagname
= *type
;
594 tagname
.append("-Patches");
595 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
596 if (tmp
.empty() == true)
599 string hash
, filename
;
600 unsigned long long size
;
601 std::stringstream
ss(tmp
);
603 while (ss
>> hash
>> size
>> filename
)
605 if (unlikely(hash
.empty() == true || filename
.empty() == true))
608 // see if we have a record for this file already
609 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
610 for (; cur
!= available_patches
.end(); ++cur
)
612 if (cur
->file
!= filename
)
614 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
616 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
617 cur
->patch_size
= size
;
620 if (cur
!= available_patches
.end())
623 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
624 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
629 bool foundStart
= false;
630 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
631 cur
!= available_patches
.end(); ++cur
)
633 if (LocalHashes
!= cur
->result_hashes
)
636 available_patches
.erase(available_patches
.begin(), cur
);
641 if (foundStart
== false || unlikely(available_patches
.empty() == true))
644 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
645 << "Couldn't find the start of the patch series." << std::endl
;
649 // patching with too many files is rather slow compared to a fast download
650 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
651 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
654 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
655 << ") so fallback to complete download" << std::endl
;
659 // calculate the size of all patches we have to get
660 // note that all sizes are uncompressed, while we download compressed files
661 unsigned long long patchesSize
= 0;
662 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
663 cur
!= available_patches
.end(); ++cur
)
664 patchesSize
+= cur
->patch_size
;
665 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
666 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
669 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
670 << ") so fallback to complete download" << std::endl
;
674 // FIXME: make this use the method
675 PackagesFileReadyInPartial
= true;
676 std::string
const Partial
= GetPartialFileNameFromURI(RealURI
);
678 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
679 FileFd
To(Partial
, FileFd::WriteEmpty
);
680 if(CopyFile(From
, To
) == false)
681 return _error
->Errno("CopyFile", "failed to copy");
684 std::cerr
<< "Done copying " << CurrentPackagesFile
688 // we have something, queue the diffs
689 string::size_type
const last_space
= Description
.rfind(" ");
690 if(last_space
!= string::npos
)
691 Description
.erase(last_space
, Description
.size()-last_space
);
693 /* decide if we should download patches one by one or in one go:
694 The first is good if the server merges patches, but many don't so client
695 based merging can be attempt in which case the second is better.
696 "bad things" will happen if patches are merged on the server,
697 but client side merging is attempt as well */
698 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
699 if (pdiff_merge
== true)
701 // reprepro adds this flag if it has merged patches on the server
702 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
703 pdiff_merge
= (precedence
!= "merged");
706 if (pdiff_merge
== false)
708 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
709 MetaIndexParser
, available_patches
);
713 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
714 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
715 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
719 available_patches
[i
],
729 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
731 Item::Failed(Message
,Cnf
);
735 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
736 << "Falling back to normal index file acquire" << std::endl
;
738 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
741 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
742 pkgAcquire::MethodConfig
*Cnf
)
745 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
747 Item::Done(Message
, Size
, Hashes
, Cnf
);
749 // verify the index target
750 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
752 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
753 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
754 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
756 RenameOnError(HashSumMismatch
);
757 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
758 Failed(Message
, Cnf
);
764 string
const FinalFile
= GetFinalFilename();
765 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
766 DestFile
= FinalFile
;
768 if(!ParseDiffIndex(DestFile
))
769 return Failed("Message: Couldn't parse pdiff index", Cnf
);
771 // queue for final move
772 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
780 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
781 // ---------------------------------------------------------------------
782 /* The package diff is added to the queue. one object is constructed
783 * for each diff and the index
785 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
786 pkgAcqMetaBase
*TransactionManager
,
787 struct IndexTarget
const * const Target
,
788 HashStringList
const &ExpectedHashes
,
789 indexRecords
*MetaIndexParser
,
790 vector
<DiffInfo
> diffs
)
791 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
792 available_patches(diffs
)
794 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
796 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
798 RealURI
= Target
->URI
;
800 Description
= Target
->Description
;
801 Desc
.ShortDesc
= Target
->ShortDesc
;
803 if(available_patches
.empty() == true)
805 // we are done (yeah!), check hashes against the final file
806 DestFile
= GetFinalFileNameFromURI(Target
->URI
);
812 State
= StateFetchDiff
;
817 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
819 Item::Failed(Message
,Cnf
);
823 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
824 << "Falling back to normal index file acquire" << std::endl
;
825 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
829 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
830 void pkgAcqIndexDiffs::Finish(bool allDone
)
833 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
835 << Desc
.URI
<< std::endl
;
837 // we restore the original name, this is required, otherwise
838 // the file will be cleaned
841 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
843 RenameOnError(HashSumMismatch
);
848 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
850 // this is for the "real" finish
855 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
860 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
867 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
869 // calc sha1 of the just patched file
870 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
872 if(!FileExists(FinalFile
))
874 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
878 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
879 Hashes LocalHashesCalc
;
880 LocalHashesCalc
.AddFD(fd
);
881 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
884 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
886 if (unlikely(LocalHashes
.usable() == false || ExpectedHashes
.usable() == false))
888 Failed("Local/Expected hashes are not usable", NULL
);
893 // final file reached before all patches are applied
894 if(LocalHashes
== ExpectedHashes
)
900 // remove all patches until the next matching patch is found
901 // this requires the Index file to be ordered
902 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
903 available_patches
.empty() == false &&
904 I
!= available_patches
.end() &&
905 I
->result_hashes
!= LocalHashes
;
908 available_patches
.erase(I
);
911 // error checking and falling back if no patch was found
912 if(available_patches
.empty() == true)
914 Failed("No patches left to reach target", NULL
);
918 // queue the right diff
919 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
920 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
921 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
924 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
931 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
932 pkgAcquire::MethodConfig
*Cnf
)
935 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
937 Item::Done(Message
, Size
, Hashes
, Cnf
);
939 // FIXME: verify this download too before feeding it to rred
940 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
942 // success in downloading a diff, enter ApplyDiff state
943 if(State
== StateFetchDiff
)
945 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
946 class Hashes LocalHashesCalc
;
947 LocalHashesCalc
.AddFD(fd
);
948 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
950 if (fd
.Size() != available_patches
[0].patch_size
||
951 available_patches
[0].patch_hashes
!= LocalHashes
)
953 Failed("Patch has Size/Hashsum mismatch", NULL
);
957 // rred excepts the patch as $FinalFile.ed
958 Rename(DestFile
,FinalFile
+".ed");
961 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
963 State
= StateApplyDiff
;
965 Desc
.URI
= "rred:" + FinalFile
;
967 SetActiveSubprocess("rred");
972 // success in download/apply a diff, queue next (if needed)
973 if(State
== StateApplyDiff
)
975 // remove the just applied patch
976 available_patches
.erase(available_patches
.begin());
977 unlink((FinalFile
+ ".ed").c_str());
982 std::clog
<< "Moving patched file in place: " << std::endl
983 << DestFile
<< " -> " << FinalFile
<< std::endl
;
985 Rename(DestFile
,FinalFile
);
986 chmod(FinalFile
.c_str(),0644);
988 // see if there is more to download
989 if(available_patches
.empty() == false) {
990 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
991 ExpectedHashes
, MetaIndexParser
,
996 DestFile
= FinalFile
;
1001 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
1002 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
1003 pkgAcqMetaBase
*TransactionManager
,
1004 struct IndexTarget
const * const Target
,
1005 HashStringList
const &ExpectedHashes
,
1006 indexRecords
*MetaIndexParser
,
1007 DiffInfo
const &patch
,
1008 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
1009 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
1010 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
1012 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1014 RealURI
= Target
->URI
;
1016 Description
= Target
->Description
;
1017 Desc
.ShortDesc
= Target
->ShortDesc
;
1019 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
1020 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
1022 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + patch
.file
);
1025 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
1030 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
1033 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
1035 Item::Failed(Message
,Cnf
);
1038 // check if we are the first to fail, otherwise we are done here
1039 State
= StateDoneDiff
;
1040 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1041 I
!= allPatches
->end(); ++I
)
1042 if ((*I
)->State
== StateErrorDiff
)
1045 // first failure means we should fallback
1046 State
= StateErrorDiff
;
1048 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
1049 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
1052 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1053 pkgAcquire::MethodConfig
*Cnf
)
1056 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
1058 Item::Done(Message
,Size
,Hashes
,Cnf
);
1060 // FIXME: verify download before feeding it to rred
1061 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1063 if (State
== StateFetchDiff
)
1065 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1066 class Hashes LocalHashesCalc
;
1067 LocalHashesCalc
.AddFD(fd
);
1068 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1070 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1072 Failed("Patch has Size/Hashsum mismatch", NULL
);
1076 // rred expects the patch as $FinalFile.ed.$patchname.gz
1077 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1079 // check if this is the last completed diff
1080 State
= StateDoneDiff
;
1081 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1082 I
!= allPatches
->end(); ++I
)
1083 if ((*I
)->State
!= StateDoneDiff
)
1086 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1090 // this is the last completed diff, so we are ready to apply now
1091 State
= StateApplyDiff
;
1094 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1097 Desc
.URI
= "rred:" + FinalFile
;
1099 SetActiveSubprocess("rred");
1102 // success in download/apply all diffs, clean up
1103 else if (State
== StateApplyDiff
)
1105 // see if we really got the expected file
1106 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
1108 RenameOnError(HashSumMismatch
);
1113 // move the result into place
1114 std::string
const FinalFile
= GetFinalFilename();
1116 std::clog
<< "Queue patched file in place: " << std::endl
1117 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1119 // queue for copy by the transaction manager
1120 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1122 // ensure the ed's are gone regardless of list-cleanup
1123 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1124 I
!= allPatches
->end(); ++I
)
1126 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1127 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1128 unlink(patch
.c_str());
1134 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1138 // AcqBaseIndex - Constructor /*{{{*/
1139 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
*Owner
,
1140 pkgAcqMetaBase
*TransactionManager
,
1141 struct IndexTarget
const * const Target
,
1142 HashStringList
const &ExpectedHashes
,
1143 indexRecords
*MetaIndexParser
)
1144 : Item(Owner
, ExpectedHashes
, TransactionManager
), Target(Target
),
1145 MetaIndexParser(MetaIndexParser
)
1149 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1150 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1152 if(MetaKey
!= "" && Hashes
.usable())
1154 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1155 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1157 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1164 // AcqBaseIndex::GetFinalFilename - Return the full final file path /*{{{*/
1165 std::string
pkgAcqBaseIndex::GetFinalFilename() const
1167 return GetFinalFileNameFromURI(RealURI
);
1170 // AcqIndex::AcqIndex - Constructor /*{{{*/
1171 // ---------------------------------------------------------------------
1172 /* The package file is added to the queue and a second class is
1173 instantiated to fetch the revision file */
1174 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1175 string URI
,string URIDesc
,string ShortDesc
,
1176 HashStringList
const &ExpectedHash
)
1177 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1181 AutoSelectCompression();
1182 Init(URI
, URIDesc
, ShortDesc
);
1184 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1185 std::clog
<< "New pkgIndex with TransactionManager "
1186 << TransactionManager
<< std::endl
;
1189 // AcqIndex::AcqIndex - Constructor /*{{{*/
1190 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1191 pkgAcqMetaBase
*TransactionManager
,
1192 IndexTarget
const *Target
,
1193 HashStringList
const &ExpectedHash
,
1194 indexRecords
*MetaIndexParser
)
1195 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1198 RealURI
= Target
->URI
;
1200 // autoselect the compression method
1201 AutoSelectCompression();
1202 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1204 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1205 std::clog
<< "New pkgIndex with TransactionManager "
1206 << TransactionManager
<< std::endl
;
1209 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1210 void pkgAcqIndex::AutoSelectCompression()
1212 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1213 CompressionExtensions
= "";
1214 if (ExpectedHashes
.usable())
1216 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1217 t
!= types
.end(); ++t
)
1219 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1220 if (*t
== "uncompressed" ||
1221 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1222 CompressionExtensions
.append(*t
).append(" ");
1227 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1228 CompressionExtensions
.append(*t
).append(" ");
1230 if (CompressionExtensions
.empty() == false)
1231 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1234 // AcqIndex::Init - defered Constructor /*{{{*/
1235 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1236 string
const &ShortDesc
)
1238 Stage
= STAGE_DOWNLOAD
;
1240 DestFile
= GetPartialFileNameFromURI(URI
);
1242 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1243 if (CurrentCompressionExtension
== "uncompressed")
1247 MetaKey
= string(Target
->MetaKey
);
1251 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1252 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1254 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1257 // load the filesize
1260 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1262 FileSize
= Record
->Size
;
1264 InitByHashIfNeeded(MetaKey
);
1267 Desc
.Description
= URIDesc
;
1269 Desc
.ShortDesc
= ShortDesc
;
1274 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1275 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1278 // - (maybe?) add support for by-hash into the sources.list as flag
1279 // - make apt-ftparchive generate the hashes (and expire?)
1280 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1281 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1282 _config
->FindB(HostKnob
, false) == true ||
1283 MetaIndexParser
->GetSupportsAcquireByHash())
1285 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1288 // FIXME: should we really use the best hash here? or a fixed one?
1289 const HashString
*TargetHash
= Record
->Hashes
.find("");
1290 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1291 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1292 Desc
.URI
= Desc
.URI
.replace(
1294 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1298 "Fetching ByHash requested but can not find record for %s",
1304 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1305 // ---------------------------------------------------------------------
1306 /* The only header we use is the last-modified header. */
1307 #if APT_PKG_ABI >= 413
1308 string
pkgAcqIndex::Custom600Headers() const
1310 string
pkgAcqIndex::Custom600Headers()
1313 string Final
= GetFinalFilename();
1315 string msg
= "\nIndex-File: true";
1317 if (stat(Final
.c_str(),&Buf
) == 0)
1318 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1320 if(Target
->IsOptional())
1321 msg
+= "\nFail-Ignore: true";
1326 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1327 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1329 Item::Failed(Message
,Cnf
);
1331 size_t const nextExt
= CompressionExtensions
.find(' ');
1332 if (nextExt
!= std::string::npos
)
1334 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1335 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1340 // on decompression failure, remove bad versions in partial/
1341 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1343 unlink(EraseFileName
.c_str());
1346 Item::Failed(Message
,Cnf
);
1348 if(Target
->IsOptional() && ExpectedHashes
.empty() && Stage
== STAGE_DOWNLOAD
)
1351 TransactionManager
->AbortTransaction();
1354 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1355 std::string
pkgAcqIndex::GetFinalFilename() const
1357 std::string
const FinalFile
= GetFinalFileNameFromURI(RealURI
);
1358 return GetCompressedFileName(RealURI
, FinalFile
, CurrentCompressionExtension
);
1361 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1362 void pkgAcqIndex::ReverifyAfterIMS()
1364 // update destfile to *not* include the compression extension when doing
1365 // a reverify (as its uncompressed on disk already)
1366 DestFile
= GetCompressedFileName(RealURI
, GetPartialFileNameFromURI(RealURI
), CurrentCompressionExtension
);
1368 // copy FinalFile into partial/ so that we check the hash again
1369 string FinalFile
= GetFinalFilename();
1370 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1371 Desc
.URI
= "copy:" + FinalFile
;
1375 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1376 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1378 // FIXME: this can go away once we only ever download stuff that
1379 // has a valid hash and we never do GET based probing
1380 // FIXME2: this also leaks debian-isms into the code and should go therefore
1382 /* Always validate the index file for correctness (all indexes must
1383 * have a Package field) (LP: #346386) (Closes: #627642)
1385 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1386 // Only test for correctness if the content of the file is not empty
1391 pkgTagFile
tag(&fd
);
1393 // all our current indexes have a field 'Package' in each section
1394 if (_error
->PendingError() == true ||
1395 tag
.Step(sec
) == false ||
1396 sec
.Exists("Package") == false)
1402 // AcqIndex::Done - Finished a fetch /*{{{*/
1403 // ---------------------------------------------------------------------
1404 /* This goes through a number of states.. On the initial fetch the
1405 method could possibly return an alternate filename which points
1406 to the uncompressed version of the file. If this is so the file
1407 is copied into the partial directory. In all other cases the file
1408 is decompressed with a compressed uri. */
1409 void pkgAcqIndex::Done(string Message
,
1410 unsigned long long Size
,
1411 HashStringList
const &Hashes
,
1412 pkgAcquire::MethodConfig
*Cfg
)
1414 Item::Done(Message
,Size
,Hashes
,Cfg
);
1418 case STAGE_DOWNLOAD
:
1419 StageDownloadDone(Message
, Hashes
, Cfg
);
1421 case STAGE_DECOMPRESS_AND_VERIFY
:
1422 StageDecompressDone(Message
, Hashes
, Cfg
);
1427 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1428 void pkgAcqIndex::StageDownloadDone(string Message
,
1429 HashStringList
const &Hashes
,
1430 pkgAcquire::MethodConfig
*Cfg
)
1432 // First check if the calculcated Hash of the (compressed) downloaded
1433 // file matches the hash we have in the MetaIndexRecords for this file
1434 if(VerifyHashByMetaKey(Hashes
) == false)
1436 RenameOnError(HashSumMismatch
);
1437 Failed(Message
, Cfg
);
1443 // Handle the unzipd case
1444 string FileName
= LookupTag(Message
,"Alt-Filename");
1445 if (FileName
.empty() == false)
1447 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1449 DestFile
+= ".decomp";
1450 Desc
.URI
= "copy:" + FileName
;
1452 SetActiveSubprocess("copy");
1456 FileName
= LookupTag(Message
,"Filename");
1457 if (FileName
.empty() == true)
1460 ErrorText
= "Method gave a blank filename";
1463 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1464 // not the "DestFile" we set, in this case we uncompress from the local file
1465 if (FileName
!= DestFile
)
1468 EraseFileName
= FileName
;
1470 // we need to verify the file against the current Release file again
1471 // on if-modfied-since hit to avoid a stale attack against us
1472 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1474 // The files timestamp matches, reverify by copy into partial/
1480 // If we have compressed indexes enabled, queue for hash verification
1481 if (_config
->FindB("Acquire::GzipIndexes",false))
1483 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1485 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1486 Desc
.URI
= "copy:" + FileName
;
1488 SetActiveSubprocess("copy");
1492 // get the binary name for your used compression type
1494 if(CurrentCompressionExtension
== "uncompressed")
1495 decompProg
= "copy";
1497 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1498 if(decompProg
.empty() == true)
1500 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1504 // queue uri for the next stage
1505 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1506 DestFile
+= ".decomp";
1507 Desc
.URI
= decompProg
+ ":" + FileName
;
1509 SetActiveSubprocess(decompProg
);
1512 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1513 void pkgAcqIndex::StageDecompressDone(string Message
,
1514 HashStringList
const &Hashes
,
1515 pkgAcquire::MethodConfig
*Cfg
)
1517 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1520 RenameOnError(HashSumMismatch
);
1521 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1522 Failed(Message
, Cfg
);
1526 if(!ValidateFile(DestFile
))
1528 RenameOnError(InvalidFormat
);
1529 Failed(Message
, Cfg
);
1533 // remove the compressed version of the file
1534 unlink(EraseFileName
.c_str());
1536 // Done, queue for rename on transaction finished
1537 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1542 // AcqMetaBase - Constructor /*{{{*/
1543 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
*Owner
,
1544 const std::vector
<IndexTarget
*>* IndexTargets
,
1545 indexRecords
* MetaIndexParser
,
1546 std::string
const &RealURI
,
1547 HashStringList
const &ExpectedHashes
,
1548 pkgAcqMetaBase
*TransactionManager
)
1549 : Item(Owner
, ExpectedHashes
, TransactionManager
),
1550 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
),
1551 AuthPass(false), RealURI(RealURI
), IMSHit(false)
1555 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1556 void pkgAcqMetaBase::Add(Item
*I
)
1558 Transaction
.push_back(I
);
1561 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1562 void pkgAcqMetaBase::AbortTransaction()
1564 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1565 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1567 // ensure the toplevel is in error state too
1568 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1569 I
!= Transaction
.end(); ++I
)
1571 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1572 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1573 // the transaction will abort, so stop anything that is idle
1574 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1576 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1580 Transaction
.clear();
1583 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1584 bool pkgAcqMetaBase::TransactionHasError()
1586 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1587 I
!= Transaction
.end(); ++I
)
1588 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1589 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1595 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1596 void pkgAcqMetaBase::CommitTransaction()
1598 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1599 std::clog
<< "CommitTransaction: " << this << std::endl
;
1601 // move new files into place *and* remove files that are not
1602 // part of the transaction but are still on disk
1603 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1604 I
!= Transaction
.end(); ++I
)
1606 if((*I
)->PartialFile
!= "")
1608 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1609 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1610 << (*I
)->DescURI() << std::endl
;
1612 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1614 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1620 unlink((*I
)->DestFile
.c_str());
1622 // mark that this transaction is finished
1623 (*I
)->TransactionManager
= 0;
1625 Transaction
.clear();
1628 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1629 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1630 const std::string
&From
,
1631 const std::string
&To
)
1633 I
->PartialFile
= From
;
1637 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1638 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1639 const std::string
&FinalFile
)
1641 I
->PartialFile
= "";
1642 I
->DestFile
= FinalFile
;
1645 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1646 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&Message
)
1648 // FIXME: this entire function can do now that we disallow going to
1649 // a unauthenticated state and can cleanly rollback
1651 string
const Final
= GetFinalFilename();
1652 if(FileExists(Final
))
1654 Status
= StatTransientNetworkError
;
1655 _error
->Warning(_("An error occurred during the signature "
1656 "verification. The repository is not updated "
1657 "and the previous index files will be used. "
1658 "GPG error: %s: %s\n"),
1659 Desc
.Description
.c_str(),
1660 LookupTag(Message
,"Message").c_str());
1661 RunScripts("APT::Update::Auth-Failure");
1663 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1664 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1665 _error
->Error(_("GPG error: %s: %s"),
1666 Desc
.Description
.c_str(),
1667 LookupTag(Message
,"Message").c_str());
1671 _error
->Warning(_("GPG error: %s: %s"),
1672 Desc
.Description
.c_str(),
1673 LookupTag(Message
,"Message").c_str());
1675 // gpgv method failed
1676 ReportMirrorFailure("GPGFailure");
1680 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1681 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1682 pkgAcqMetaBase
*TransactionManager
,
1683 string URI
,string URIDesc
,string ShortDesc
,
1684 string MetaIndexFile
,
1685 const vector
<IndexTarget
*>* IndexTargets
,
1686 indexRecords
* MetaIndexParser
) :
1687 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, URI
,
1688 HashStringList(), TransactionManager
),
1689 MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1690 ShortDesc(ShortDesc
)
1692 DestFile
= GetPartialFileNameFromURI(RealURI
);
1694 // remove any partial downloaded sig-file in partial/.
1695 // it may confuse proxies and is too small to warrant a
1696 // partial download anyway
1697 unlink(DestFile
.c_str());
1699 // set the TransactionManager
1700 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1701 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1702 << TransactionManager
<< std::endl
;
1705 Desc
.Description
= URIDesc
;
1707 Desc
.ShortDesc
= ShortDesc
;
1713 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1717 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1718 // ---------------------------------------------------------------------
1719 /* The only header we use is the last-modified header. */
1720 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1721 HashStringList
const &Hashes
,
1722 pkgAcquire::MethodConfig
*Cfg
)
1724 Item::Done(Message
, Size
, Hashes
, Cfg
);
1726 if(AuthPass
== false)
1728 if(CheckDownloadDone(Message
) == true)
1730 // destfile will be modified to point to MetaIndexFile for the
1731 // gpgv method, so we need to save it here
1732 MetaIndexFileSignature
= DestFile
;
1733 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1737 else if(CheckAuthDone(Message
) == true)
1738 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, GetFinalFilename());
1741 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1743 Item::Failed(Message
,Cnf
);
1745 // check if we need to fail at this point
1746 if (AuthPass
== true && CheckStopAuthentication(Message
))
1749 // FIXME: meh, this is not really elegant
1750 string
const Final
= GetFinalFileNameFromURI(RealURI
);
1751 string
const InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1753 string
const FinalInRelease
= GetFinalFileNameFromURI(InReleaseURI
);
1755 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1757 std::string downgrade_msg
;
1758 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1760 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1762 // meh, the users wants to take risks (we still mark the packages
1763 // from this repository as unauthenticated)
1764 _error
->Warning("%s", downgrade_msg
.c_str());
1765 _error
->Warning(_("This is normally not allowed, but the option "
1766 "Acquire::AllowDowngradeToInsecureRepositories was "
1767 "given to override it."));
1770 _error
->Error("%s", downgrade_msg
.c_str());
1771 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1772 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1773 TransactionManager
->AbortTransaction();
1778 _error
->Warning(_("The data from '%s' is not signed. Packages "
1779 "from that repository can not be authenticated."),
1782 // this ensures that any file in the lists/ dir is removed by the
1784 DestFile
= GetPartialFileNameFromURI(RealURI
);
1785 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1787 // only allow going further if the users explicitely wants it
1788 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
1790 // we parse the indexes here because at this point the user wanted
1791 // a repository that may potentially harm him
1792 MetaIndexParser
->Load(MetaIndexFile
);
1793 if (!VerifyVendor(Message
))
1794 /* expired Release files are still a problem you need extra force for */;
1799 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1800 if (Cnf
->LocalOnly
== true ||
1801 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1808 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1809 pkgAcqMetaBase
*TransactionManager
,
1810 string URI
,string URIDesc
,string ShortDesc
,
1811 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1812 const vector
<IndexTarget
*>* IndexTargets
,
1813 indexRecords
* MetaIndexParser
) :
1814 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, URI
, HashStringList(),
1815 TransactionManager
),
1816 URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1817 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1818 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1820 if(TransactionManager
== NULL
)
1822 this->TransactionManager
= this;
1823 this->TransactionManager
->Add(this);
1826 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1827 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1828 << this->TransactionManager
<< std::endl
;
1831 Init(URIDesc
, ShortDesc
);
1834 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1835 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1837 DestFile
= GetPartialFileNameFromURI(RealURI
);
1840 Desc
.Description
= URIDesc
;
1842 Desc
.ShortDesc
= ShortDesc
;
1845 // we expect more item
1846 ExpectedAdditionalItems
= IndexTargets
->size();
1850 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1851 HashStringList
const &Hashes
,
1852 pkgAcquire::MethodConfig
*Cfg
)
1854 Item::Done(Message
,Size
,Hashes
,Cfg
);
1856 if(CheckDownloadDone(Message
))
1858 // we have a Release file, now download the Signature, all further
1859 // verify/queue for additional downloads will be done in the
1860 // pkgAcqMetaSig::Done() code
1861 std::string MetaIndexFile
= DestFile
;
1862 new pkgAcqMetaSig(Owner
, TransactionManager
,
1863 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1864 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1867 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1871 bool pkgAcqMetaBase::CheckAuthDone(string Message
) /*{{{*/
1873 // At this point, the gpgv method has succeeded, so there is a
1874 // valid signature from a key in the trusted keyring. We
1875 // perform additional verification of its contents, and use them
1876 // to verify the indexes we are about to download
1878 if (!MetaIndexParser
->Load(DestFile
))
1880 Status
= StatAuthError
;
1881 ErrorText
= MetaIndexParser
->ErrorText
;
1885 if (!VerifyVendor(Message
))
1887 Status
= StatAuthError
;
1891 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1892 std::cerr
<< "Signature verification succeeded: "
1893 << DestFile
<< std::endl
;
1895 // Download further indexes with verification
1901 // pkgAcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
1902 // ---------------------------------------------------------------------
1903 #if APT_PKG_ABI >= 413
1904 string
pkgAcqMetaBase::Custom600Headers() const
1906 string
pkgAcqMetaBase::Custom600Headers()
1909 std::string Header
= "\nIndex-File: true";
1910 std::string MaximumSize
;
1911 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1912 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1913 Header
+= MaximumSize
;
1915 string
const FinalFile
= GetFinalFilename();
1918 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1919 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1924 // pkgAcqMetaBase::GetFinalFilename - Return the full final file path /*{{{*/
1925 std::string
pkgAcqMetaBase::GetFinalFilename() const
1927 return GetFinalFileNameFromURI(RealURI
);
1930 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1931 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1932 const std::string
&MetaIndexFileSignature
)
1935 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1936 DestFile
= MetaIndexFile
;
1938 SetActiveSubprocess("gpgv");
1941 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1942 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
)
1944 // We have just finished downloading a Release file (it is not
1947 string FileName
= LookupTag(Message
,"Filename");
1948 if (FileName
.empty() == true)
1951 ErrorText
= "Method gave a blank filename";
1955 if (FileName
!= DestFile
)
1958 Desc
.URI
= "copy:" + FileName
;
1963 // make sure to verify against the right file on I-M-S hit
1964 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1967 // for simplicity, the transaction manager is always InRelease
1968 // even if it doesn't exist.
1969 if (TransactionManager
!= NULL
)
1970 TransactionManager
->IMSHit
= true;
1971 DestFile
= GetFinalFilename();
1974 // set Item to complete as the remaining work is all local (verify etc)
1980 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1982 // at this point the real Items are loaded in the fetcher
1983 ExpectedAdditionalItems
= 0;
1985 vector
<struct IndexTarget
*>::const_iterator Target
;
1986 for (Target
= IndexTargets
->begin();
1987 Target
!= IndexTargets
->end();
1990 HashStringList ExpectedIndexHashes
;
1991 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1993 // optional target that we do not have in the Release file are
1995 if (verify
== true && Record
== NULL
&& (*Target
)->IsOptional())
1998 // targets without a hash record are a error when verify is required
1999 if (verify
== true && Record
== NULL
)
2001 Status
= StatAuthError
;
2002 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2007 ExpectedIndexHashes
= Record
->Hashes
;
2009 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2011 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2012 << "Expected Hash:" << std::endl
;
2013 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2014 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2015 std::cerr
<< "For: " << ((Record
== NULL
) ? "<NULL>" : Record
->MetaKeyFilename
) << std::endl
;
2018 if (verify
== true && ExpectedIndexHashes
.empty() == true)
2020 Status
= StatAuthError
;
2021 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2025 /* Queue the Index file (Packages, Sources, Translation-$foo
2026 (either diff or full packages files, depending
2027 on the users option) - we also check if the PDiff Index file is listed
2028 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2029 instead, but passing the required info to it is to much hassle */
2030 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2031 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2032 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2034 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2038 bool pkgAcqMetaBase::VerifyVendor(string Message
) /*{{{*/
2040 string::size_type pos
;
2042 // check for missing sigs (that where not fatal because otherwise we had
2045 string msg
= _("There is no public key available for the "
2046 "following key IDs:\n");
2047 pos
= Message
.find("NO_PUBKEY ");
2048 if (pos
!= std::string::npos
)
2050 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2051 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2052 missingkeys
+= (Fingerprint
);
2054 if(!missingkeys
.empty())
2055 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2057 string Transformed
= MetaIndexParser
->GetExpectedDist();
2059 if (Transformed
== "../project/experimental")
2061 Transformed
= "experimental";
2064 pos
= Transformed
.rfind('/');
2065 if (pos
!= string::npos
)
2067 Transformed
= Transformed
.substr(0, pos
);
2070 if (Transformed
== ".")
2075 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2076 MetaIndexParser
->GetValidUntil() > 0) {
2077 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2078 if (invalid_since
> 0)
2082 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2083 // the time since then the file is invalid - formated in the same way as in
2084 // the download progress display (e.g. 7d 3h 42min 1s)
2085 _("Release file for %s is expired (invalid since %s). "
2086 "Updates for this repository will not be applied."),
2087 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2088 if (ErrorText
.empty())
2090 return _error
->Error("%s", errmsg
.c_str());
2094 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2096 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2097 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2098 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2101 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2103 // This might become fatal one day
2104 // Status = StatAuthError;
2105 // ErrorText = "Conflicting distribution; expected "
2106 // + MetaIndexParser->GetExpectedDist() + " but got "
2107 // + MetaIndexParser->GetDist();
2109 if (!Transformed
.empty())
2111 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2112 Desc
.Description
.c_str(),
2113 Transformed
.c_str(),
2114 MetaIndexParser
->GetDist().c_str());
2121 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2122 void pkgAcqMetaIndex::Failed(string Message
,
2123 pkgAcquire::MethodConfig
* Cnf
)
2125 pkgAcquire::Item::Failed(Message
, Cnf
);
2128 _error
->Warning(_("The repository '%s' does not have a Release file. "
2129 "This is deprecated, please contact the owner of the "
2130 "repository."), URIDesc
.c_str());
2132 // No Release file was present so fall
2133 // back to queueing Packages files without verification
2134 // only allow going further if the users explicitely wants it
2135 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2137 // Done, queue for rename on transaction finished
2138 if (FileExists(DestFile
))
2139 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2141 // queue without any kind of hashsum support
2142 QueueIndexes(false);
2146 void pkgAcqMetaIndex::Finished() /*{{{*/
2148 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2149 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2150 if(TransactionManager
!= NULL
&&
2151 TransactionManager
->TransactionHasError() == false)
2152 TransactionManager
->CommitTransaction();
2155 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2156 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2157 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2158 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2159 const vector
<IndexTarget
*>* IndexTargets
,
2160 indexRecords
* MetaIndexParser
) :
2161 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2162 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2163 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2165 // index targets + (worst case:) Release/Release.gpg
2166 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2170 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2174 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2175 #if APT_PKG_ABI >= 413
2176 string
pkgAcqMetaClearSig::Custom600Headers() const
2178 string
pkgAcqMetaClearSig::Custom600Headers()
2181 string Header
= pkgAcqMetaBase::Custom600Headers();
2182 Header
+= "\nFail-Ignore: true";
2186 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2187 // ---------------------------------------------------------------------
2188 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2189 HashStringList
const &Hashes
,
2190 pkgAcquire::MethodConfig
*Cnf
)
2192 Item::Done(Message
, Size
, Hashes
, Cnf
);
2194 // if we expect a ClearTextSignature (InRelase), ensure that
2195 // this is what we get and if not fail to queue a
2196 // Release/Release.gpg, see #346386
2197 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2199 pkgAcquire::Item::Failed(Message
, Cnf
);
2200 RenameOnError(NotClearsigned
);
2201 TransactionManager
->AbortTransaction();
2205 if(AuthPass
== false)
2207 if(CheckDownloadDone(Message
) == true)
2208 QueueForSignatureVerify(DestFile
, DestFile
);
2211 else if(CheckAuthDone(Message
) == true)
2212 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2215 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2217 Item::Failed(Message
, Cnf
);
2219 // we failed, we will not get additional items from this method
2220 ExpectedAdditionalItems
= 0;
2222 if (AuthPass
== false)
2224 // Queue the 'old' InRelease file for removal if we try Release.gpg
2225 // as otherwise the file will stay around and gives a false-auth
2226 // impression (CVE-2012-0214)
2227 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
2230 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2231 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2232 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2233 IndexTargets
, MetaIndexParser
);
2237 if(CheckStopAuthentication(Message
))
2240 _error
->Warning(_("The data from '%s' is not signed. Packages "
2241 "from that repository can not be authenticated."),
2244 // No Release file was present, or verification failed, so fall
2245 // back to queueing Packages files without verification
2246 // only allow going further if the users explicitely wants it
2247 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2251 /* Always move the meta index, even if gpgv failed. This ensures
2252 * that PackageFile objects are correctly filled in */
2253 if (FileExists(DestFile
))
2255 string FinalFile
= GetFinalFilename();
2256 /* InRelease files become Release files, otherwise
2257 * they would be considered as trusted later on */
2258 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2260 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2263 // Done, queue for rename on transaction finished
2264 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2266 QueueIndexes(false);
2271 // AcqArchive::AcqArchive - Constructor /*{{{*/
2272 // ---------------------------------------------------------------------
2273 /* This just sets up the initial fetch environment and queues the first
2275 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2276 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2277 string
&StoreFilename
) :
2278 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2279 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2282 Retries
= _config
->FindI("Acquire::Retries",0);
2284 if (Version
.Arch() == 0)
2286 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2287 "This might mean you need to manually fix this package. "
2288 "(due to missing arch)"),
2289 Version
.ParentPkg().FullName().c_str());
2293 /* We need to find a filename to determine the extension. We make the
2294 assumption here that all the available sources for this version share
2295 the same extension.. */
2296 // Skip not source sources, they do not have file fields.
2297 for (; Vf
.end() == false; ++Vf
)
2299 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2304 // Does not really matter here.. we are going to fail out below
2305 if (Vf
.end() != true)
2307 // If this fails to get a file name we will bomb out below.
2308 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2309 if (_error
->PendingError() == true)
2312 // Generate the final file name as: package_version_arch.foo
2313 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2314 QuoteString(Version
.VerStr(),"_:") + '_' +
2315 QuoteString(Version
.Arch(),"_:.") +
2316 "." + flExtension(Parse
.FileName());
2319 // check if we have one trusted source for the package. if so, switch
2320 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2321 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2322 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2323 bool seenUntrusted
= false;
2324 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2326 pkgIndexFile
*Index
;
2327 if (Sources
->FindIndex(i
.File(),Index
) == false)
2330 if (debugAuth
== true)
2331 std::cerr
<< "Checking index: " << Index
->Describe()
2332 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2334 if (Index
->IsTrusted() == true)
2337 if (allowUnauth
== false)
2341 seenUntrusted
= true;
2344 // "allow-unauthenticated" restores apts old fetching behaviour
2345 // that means that e.g. unauthenticated file:// uris are higher
2346 // priority than authenticated http:// uris
2347 if (allowUnauth
== true && seenUntrusted
== true)
2351 if (QueueNext() == false && _error
->PendingError() == false)
2352 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2353 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2356 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2357 // ---------------------------------------------------------------------
2358 /* This queues the next available file version for download. It checks if
2359 the archive is already available in the cache and stashs the MD5 for
2361 bool pkgAcqArchive::QueueNext()
2363 for (; Vf
.end() == false; ++Vf
)
2365 // Ignore not source sources
2366 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2369 // Try to cross match against the source list
2370 pkgIndexFile
*Index
;
2371 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2374 // only try to get a trusted package from another source if that source
2376 if(Trusted
&& !Index
->IsTrusted())
2379 // Grab the text package record
2380 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2381 if (_error
->PendingError() == true)
2384 string PkgFile
= Parse
.FileName();
2385 ExpectedHashes
= Parse
.Hashes();
2387 if (PkgFile
.empty() == true)
2388 return _error
->Error(_("The package index files are corrupted. No Filename: "
2389 "field for package %s."),
2390 Version
.ParentPkg().Name());
2392 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2393 Desc
.Description
= Index
->ArchiveInfo(Version
);
2395 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2397 // See if we already have the file. (Legacy filenames)
2398 FileSize
= Version
->Size
;
2399 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2401 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2403 // Make sure the size matches
2404 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2409 StoreFilename
= DestFile
= FinalFile
;
2413 /* Hmm, we have a file and its size does not match, this means it is
2414 an old style mismatched arch */
2415 unlink(FinalFile
.c_str());
2418 // Check it again using the new style output filenames
2419 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2420 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2422 // Make sure the size matches
2423 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2428 StoreFilename
= DestFile
= FinalFile
;
2432 /* Hmm, we have a file and its size does not match, this shouldn't
2434 unlink(FinalFile
.c_str());
2437 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2439 // Check the destination file
2440 if (stat(DestFile
.c_str(),&Buf
) == 0)
2442 // Hmm, the partial file is too big, erase it
2443 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2444 unlink(DestFile
.c_str());
2446 PartialSize
= Buf
.st_size
;
2449 // Disables download of archives - useful if no real installation follows,
2450 // e.g. if we are just interested in proposed installation order
2451 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2456 StoreFilename
= DestFile
= FinalFile
;
2470 // AcqArchive::Done - Finished fetching /*{{{*/
2471 // ---------------------------------------------------------------------
2473 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2474 pkgAcquire::MethodConfig
*Cfg
)
2476 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2479 if (Size
!= Version
->Size
)
2481 RenameOnError(SizeMismatch
);
2485 // FIXME: could this empty() check impose *any* sort of security issue?
2486 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2488 RenameOnError(HashSumMismatch
);
2489 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2493 // Grab the output filename
2494 string FileName
= LookupTag(Message
,"Filename");
2495 if (FileName
.empty() == true)
2498 ErrorText
= "Method gave a blank filename";
2502 // Reference filename
2503 if (FileName
!= DestFile
)
2505 StoreFilename
= DestFile
= FileName
;
2511 // Done, move it into position
2512 string
const FinalFile
= GetFinalFilename();
2513 Rename(DestFile
,FinalFile
);
2514 StoreFilename
= DestFile
= FinalFile
;
2518 // Acquire::Item::GetFinalFilename - Return the full final file path /*{{{*/
2519 std::string
pkgAcqArchive::GetFinalFilename() const
2521 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2524 // AcqArchive::Failed - Failure handler /*{{{*/
2525 // ---------------------------------------------------------------------
2526 /* Here we try other sources */
2527 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2529 Item::Failed(Message
,Cnf
);
2531 /* We don't really want to retry on failed media swaps, this prevents
2532 that. An interesting observation is that permanent failures are not
2534 if (Cnf
->Removable
== true &&
2535 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2537 // Vf = Version.FileList();
2538 while (Vf
.end() == false) ++Vf
;
2539 StoreFilename
= string();
2544 if (QueueNext() == false)
2546 // This is the retry counter
2548 Cnf
->LocalOnly
== false &&
2549 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2552 Vf
= Version
.FileList();
2553 if (QueueNext() == true)
2557 StoreFilename
= string();
2562 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2563 // ---------------------------------------------------------------------
2564 #if APT_PKG_ABI >= 413
2565 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2567 APT_PURE
bool pkgAcqArchive::IsTrusted()
2573 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2574 // ---------------------------------------------------------------------
2576 void pkgAcqArchive::Finished()
2578 if (Status
== pkgAcquire::Item::StatDone
&&
2581 StoreFilename
= string();
2584 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2585 // ---------------------------------------------------------------------
2586 /* The file is added to the queue */
2587 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2588 unsigned long long Size
,string Dsc
,string ShortDesc
,
2589 const string
&DestDir
, const string
&DestFilename
,
2591 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2593 Retries
= _config
->FindI("Acquire::Retries",0);
2595 if(!DestFilename
.empty())
2596 DestFile
= DestFilename
;
2597 else if(!DestDir
.empty())
2598 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2600 DestFile
= flNotDir(URI
);
2604 Desc
.Description
= Dsc
;
2607 // Set the short description to the archive component
2608 Desc
.ShortDesc
= ShortDesc
;
2610 // Get the transfer sizes
2613 if (stat(DestFile
.c_str(),&Buf
) == 0)
2615 // Hmm, the partial file is too big, erase it
2616 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2617 unlink(DestFile
.c_str());
2619 PartialSize
= Buf
.st_size
;
2625 // AcqFile::Done - Item downloaded OK /*{{{*/
2626 // ---------------------------------------------------------------------
2628 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2629 pkgAcquire::MethodConfig
*Cnf
)
2631 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2634 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2636 RenameOnError(HashSumMismatch
);
2637 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2641 string FileName
= LookupTag(Message
,"Filename");
2642 if (FileName
.empty() == true)
2645 ErrorText
= "Method gave a blank filename";
2651 // The files timestamp matches
2652 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2655 // We have to copy it into place
2656 if (FileName
!= DestFile
)
2659 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2660 Cnf
->Removable
== true)
2662 Desc
.URI
= "copy:" + FileName
;
2667 // Erase the file if it is a symlink so we can overwrite it
2669 if (lstat(DestFile
.c_str(),&St
) == 0)
2671 if (S_ISLNK(St
.st_mode
) != 0)
2672 unlink(DestFile
.c_str());
2676 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2678 _error
->PushToStack();
2679 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
2680 std::stringstream msg
;
2681 _error
->DumpErrors(msg
);
2682 _error
->RevertToStack();
2683 ErrorText
= msg
.str();
2690 // AcqFile::Failed - Failure handler /*{{{*/
2691 // ---------------------------------------------------------------------
2692 /* Here we try other sources */
2693 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2695 Item::Failed(Message
,Cnf
);
2697 // This is the retry counter
2699 Cnf
->LocalOnly
== false &&
2700 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2710 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2711 // ---------------------------------------------------------------------
2712 /* The only header we use is the last-modified header. */
2713 #if APT_PKG_ABI >= 413
2714 string
pkgAcqFile::Custom600Headers() const
2716 string
pkgAcqFile::Custom600Headers()
2720 return "\nIndex-File: true";