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
;
1047 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
1048 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
1051 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1052 pkgAcquire::MethodConfig
*Cnf
)
1055 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
1057 Item::Done(Message
,Size
,Hashes
,Cnf
);
1059 // FIXME: verify download before feeding it to rred
1060 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1062 if (State
== StateFetchDiff
)
1064 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1065 class Hashes LocalHashesCalc
;
1066 LocalHashesCalc
.AddFD(fd
);
1067 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1069 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1071 Failed("Patch has Size/Hashsum mismatch", NULL
);
1075 // rred expects the patch as $FinalFile.ed.$patchname.gz
1076 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1078 // check if this is the last completed diff
1079 State
= StateDoneDiff
;
1080 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1081 I
!= allPatches
->end(); ++I
)
1082 if ((*I
)->State
!= StateDoneDiff
)
1085 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1089 // this is the last completed diff, so we are ready to apply now
1090 State
= StateApplyDiff
;
1093 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1096 Desc
.URI
= "rred:" + FinalFile
;
1098 SetActiveSubprocess("rred");
1101 // success in download/apply all diffs, clean up
1102 else if (State
== StateApplyDiff
)
1104 // see if we really got the expected file
1105 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
1107 RenameOnError(HashSumMismatch
);
1112 // move the result into place
1113 std::string
const FinalFile
= GetFinalFilename();
1115 std::clog
<< "Queue patched file in place: " << std::endl
1116 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1118 // queue for copy by the transaction manager
1119 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1121 // ensure the ed's are gone regardless of list-cleanup
1122 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1123 I
!= allPatches
->end(); ++I
)
1125 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1126 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1127 unlink(patch
.c_str());
1133 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1137 // AcqBaseIndex - Constructor /*{{{*/
1138 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
*Owner
,
1139 pkgAcqMetaBase
*TransactionManager
,
1140 struct IndexTarget
const * const Target
,
1141 HashStringList
const &ExpectedHashes
,
1142 indexRecords
*MetaIndexParser
)
1143 : Item(Owner
, ExpectedHashes
, TransactionManager
), Target(Target
),
1144 MetaIndexParser(MetaIndexParser
)
1148 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1149 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1151 if(MetaKey
!= "" && Hashes
.usable())
1153 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1154 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1156 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1163 // AcqBaseIndex::GetFinalFilename - Return the full final file path /*{{{*/
1164 std::string
pkgAcqBaseIndex::GetFinalFilename() const
1166 return GetFinalFileNameFromURI(RealURI
);
1169 // AcqIndex::AcqIndex - Constructor /*{{{*/
1170 // ---------------------------------------------------------------------
1171 /* The package file is added to the queue and a second class is
1172 instantiated to fetch the revision file */
1173 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1174 string URI
,string URIDesc
,string ShortDesc
,
1175 HashStringList
const &ExpectedHash
)
1176 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1180 AutoSelectCompression();
1181 Init(URI
, URIDesc
, ShortDesc
);
1183 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1184 std::clog
<< "New pkgIndex with TransactionManager "
1185 << TransactionManager
<< std::endl
;
1188 // AcqIndex::AcqIndex - Constructor /*{{{*/
1189 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1190 pkgAcqMetaBase
*TransactionManager
,
1191 IndexTarget
const *Target
,
1192 HashStringList
const &ExpectedHash
,
1193 indexRecords
*MetaIndexParser
)
1194 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1197 RealURI
= Target
->URI
;
1199 // autoselect the compression method
1200 AutoSelectCompression();
1201 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1203 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1204 std::clog
<< "New pkgIndex with TransactionManager "
1205 << TransactionManager
<< std::endl
;
1208 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1209 void pkgAcqIndex::AutoSelectCompression()
1211 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1212 CompressionExtensions
= "";
1213 if (ExpectedHashes
.usable())
1215 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1216 t
!= types
.end(); ++t
)
1218 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1219 if (*t
== "uncompressed" ||
1220 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1221 CompressionExtensions
.append(*t
).append(" ");
1226 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1227 CompressionExtensions
.append(*t
).append(" ");
1229 if (CompressionExtensions
.empty() == false)
1230 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1233 // AcqIndex::Init - defered Constructor /*{{{*/
1234 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1235 string
const &ShortDesc
)
1237 Stage
= STAGE_DOWNLOAD
;
1239 DestFile
= GetPartialFileNameFromURI(URI
);
1241 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1242 if (CurrentCompressionExtension
== "uncompressed")
1246 MetaKey
= string(Target
->MetaKey
);
1250 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1251 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1253 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1256 // load the filesize
1259 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1261 FileSize
= Record
->Size
;
1263 InitByHashIfNeeded(MetaKey
);
1266 Desc
.Description
= URIDesc
;
1268 Desc
.ShortDesc
= ShortDesc
;
1273 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1274 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1277 // - (maybe?) add support for by-hash into the sources.list as flag
1278 // - make apt-ftparchive generate the hashes (and expire?)
1279 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1280 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1281 _config
->FindB(HostKnob
, false) == true ||
1282 MetaIndexParser
->GetSupportsAcquireByHash())
1284 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1287 // FIXME: should we really use the best hash here? or a fixed one?
1288 const HashString
*TargetHash
= Record
->Hashes
.find("");
1289 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1290 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1291 Desc
.URI
= Desc
.URI
.replace(
1293 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1297 "Fetching ByHash requested but can not find record for %s",
1303 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1304 // ---------------------------------------------------------------------
1305 /* The only header we use is the last-modified header. */
1306 #if APT_PKG_ABI >= 413
1307 string
pkgAcqIndex::Custom600Headers() const
1309 string
pkgAcqIndex::Custom600Headers()
1312 string Final
= GetFinalFilename();
1314 string msg
= "\nIndex-File: true";
1316 if (stat(Final
.c_str(),&Buf
) == 0)
1317 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1319 if(Target
->IsOptional())
1320 msg
+= "\nFail-Ignore: true";
1325 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1326 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1328 Item::Failed(Message
,Cnf
);
1330 size_t const nextExt
= CompressionExtensions
.find(' ');
1331 if (nextExt
!= std::string::npos
)
1333 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1334 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1339 // on decompression failure, remove bad versions in partial/
1340 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1342 unlink(EraseFileName
.c_str());
1345 Item::Failed(Message
,Cnf
);
1347 if(Target
->IsOptional() && ExpectedHashes
.empty() && Stage
== STAGE_DOWNLOAD
)
1350 TransactionManager
->AbortTransaction();
1353 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1354 std::string
pkgAcqIndex::GetFinalFilename() const
1356 std::string
const FinalFile
= GetFinalFileNameFromURI(RealURI
);
1357 return GetCompressedFileName(RealURI
, FinalFile
, CurrentCompressionExtension
);
1360 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1361 void pkgAcqIndex::ReverifyAfterIMS()
1363 // update destfile to *not* include the compression extension when doing
1364 // a reverify (as its uncompressed on disk already)
1365 DestFile
= GetCompressedFileName(RealURI
, GetPartialFileNameFromURI(RealURI
), CurrentCompressionExtension
);
1367 // copy FinalFile into partial/ so that we check the hash again
1368 string FinalFile
= GetFinalFilename();
1369 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1370 Desc
.URI
= "copy:" + FinalFile
;
1374 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1375 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1377 // FIXME: this can go away once we only ever download stuff that
1378 // has a valid hash and we never do GET based probing
1379 // FIXME2: this also leaks debian-isms into the code and should go therefore
1381 /* Always validate the index file for correctness (all indexes must
1382 * have a Package field) (LP: #346386) (Closes: #627642)
1384 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1385 // Only test for correctness if the content of the file is not empty
1390 pkgTagFile
tag(&fd
);
1392 // all our current indexes have a field 'Package' in each section
1393 if (_error
->PendingError() == true ||
1394 tag
.Step(sec
) == false ||
1395 sec
.Exists("Package") == false)
1401 // AcqIndex::Done - Finished a fetch /*{{{*/
1402 // ---------------------------------------------------------------------
1403 /* This goes through a number of states.. On the initial fetch the
1404 method could possibly return an alternate filename which points
1405 to the uncompressed version of the file. If this is so the file
1406 is copied into the partial directory. In all other cases the file
1407 is decompressed with a compressed uri. */
1408 void pkgAcqIndex::Done(string Message
,
1409 unsigned long long Size
,
1410 HashStringList
const &Hashes
,
1411 pkgAcquire::MethodConfig
*Cfg
)
1413 Item::Done(Message
,Size
,Hashes
,Cfg
);
1417 case STAGE_DOWNLOAD
:
1418 StageDownloadDone(Message
, Hashes
, Cfg
);
1420 case STAGE_DECOMPRESS_AND_VERIFY
:
1421 StageDecompressDone(Message
, Hashes
, Cfg
);
1426 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1427 void pkgAcqIndex::StageDownloadDone(string Message
,
1428 HashStringList
const &Hashes
,
1429 pkgAcquire::MethodConfig
*Cfg
)
1431 // First check if the calculcated Hash of the (compressed) downloaded
1432 // file matches the hash we have in the MetaIndexRecords for this file
1433 if(VerifyHashByMetaKey(Hashes
) == false)
1435 RenameOnError(HashSumMismatch
);
1436 Failed(Message
, Cfg
);
1442 // Handle the unzipd case
1443 string FileName
= LookupTag(Message
,"Alt-Filename");
1444 if (FileName
.empty() == false)
1446 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1448 DestFile
+= ".decomp";
1449 Desc
.URI
= "copy:" + FileName
;
1451 SetActiveSubprocess("copy");
1455 FileName
= LookupTag(Message
,"Filename");
1456 if (FileName
.empty() == true)
1459 ErrorText
= "Method gave a blank filename";
1462 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1463 // not the "DestFile" we set, in this case we uncompress from the local file
1464 if (FileName
!= DestFile
)
1467 EraseFileName
= FileName
;
1469 // we need to verify the file against the current Release file again
1470 // on if-modfied-since hit to avoid a stale attack against us
1471 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1473 // The files timestamp matches, reverify by copy into partial/
1479 // If we have compressed indexes enabled, queue for hash verification
1480 if (_config
->FindB("Acquire::GzipIndexes",false))
1482 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1484 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1485 Desc
.URI
= "copy:" + FileName
;
1487 SetActiveSubprocess("copy");
1491 // get the binary name for your used compression type
1493 if(CurrentCompressionExtension
== "uncompressed")
1494 decompProg
= "copy";
1496 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1497 if(decompProg
.empty() == true)
1499 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1503 // queue uri for the next stage
1504 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1505 DestFile
+= ".decomp";
1506 Desc
.URI
= decompProg
+ ":" + FileName
;
1508 SetActiveSubprocess(decompProg
);
1511 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1512 void pkgAcqIndex::StageDecompressDone(string Message
,
1513 HashStringList
const &Hashes
,
1514 pkgAcquire::MethodConfig
*Cfg
)
1516 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1519 RenameOnError(HashSumMismatch
);
1520 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1521 Failed(Message
, Cfg
);
1525 if(!ValidateFile(DestFile
))
1527 RenameOnError(InvalidFormat
);
1528 Failed(Message
, Cfg
);
1532 // remove the compressed version of the file
1533 unlink(EraseFileName
.c_str());
1535 // Done, queue for rename on transaction finished
1536 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1541 // AcqMetaBase - Constructor /*{{{*/
1542 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
*Owner
,
1543 const std::vector
<IndexTarget
*>* IndexTargets
,
1544 indexRecords
* MetaIndexParser
,
1545 std::string
const &RealURI
,
1546 HashStringList
const &ExpectedHashes
,
1547 pkgAcqMetaBase
*TransactionManager
)
1548 : Item(Owner
, ExpectedHashes
, TransactionManager
),
1549 MetaIndexParser(MetaIndexParser
), IndexTargets(IndexTargets
),
1550 AuthPass(false), RealURI(RealURI
), IMSHit(false)
1554 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1555 void pkgAcqMetaBase::Add(Item
*I
)
1557 Transaction
.push_back(I
);
1560 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1561 void pkgAcqMetaBase::AbortTransaction()
1563 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1564 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1566 // ensure the toplevel is in error state too
1567 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1568 I
!= Transaction
.end(); ++I
)
1570 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1571 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1572 // the transaction will abort, so stop anything that is idle
1573 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1575 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1579 Transaction
.clear();
1582 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1583 bool pkgAcqMetaBase::TransactionHasError()
1585 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1586 I
!= Transaction
.end(); ++I
)
1587 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1588 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1594 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1595 void pkgAcqMetaBase::CommitTransaction()
1597 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1598 std::clog
<< "CommitTransaction: " << this << std::endl
;
1600 // move new files into place *and* remove files that are not
1601 // part of the transaction but are still on disk
1602 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1603 I
!= Transaction
.end(); ++I
)
1605 if((*I
)->PartialFile
!= "")
1607 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1608 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1609 << (*I
)->DescURI() << std::endl
;
1611 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1613 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1619 unlink((*I
)->DestFile
.c_str());
1621 // mark that this transaction is finished
1622 (*I
)->TransactionManager
= 0;
1624 Transaction
.clear();
1627 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1628 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1629 const std::string
&From
,
1630 const std::string
&To
)
1632 I
->PartialFile
= From
;
1636 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1637 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1638 const std::string
&FinalFile
)
1640 I
->PartialFile
= "";
1641 I
->DestFile
= FinalFile
;
1644 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1645 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&Message
)
1647 // FIXME: this entire function can do now that we disallow going to
1648 // a unauthenticated state and can cleanly rollback
1650 string
const Final
= GetFinalFilename();
1651 if(FileExists(Final
))
1653 Status
= StatTransientNetworkError
;
1654 _error
->Warning(_("An error occurred during the signature "
1655 "verification. The repository is not updated "
1656 "and the previous index files will be used. "
1657 "GPG error: %s: %s\n"),
1658 Desc
.Description
.c_str(),
1659 LookupTag(Message
,"Message").c_str());
1660 RunScripts("APT::Update::Auth-Failure");
1662 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1663 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1664 _error
->Error(_("GPG error: %s: %s"),
1665 Desc
.Description
.c_str(),
1666 LookupTag(Message
,"Message").c_str());
1670 _error
->Warning(_("GPG error: %s: %s"),
1671 Desc
.Description
.c_str(),
1672 LookupTag(Message
,"Message").c_str());
1674 // gpgv method failed
1675 ReportMirrorFailure("GPGFailure");
1679 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1680 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1681 pkgAcqMetaBase
*TransactionManager
,
1682 string URI
,string URIDesc
,string ShortDesc
,
1683 string MetaIndexFile
,
1684 const vector
<IndexTarget
*>* IndexTargets
,
1685 indexRecords
* MetaIndexParser
) :
1686 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, URI
,
1687 HashStringList(), TransactionManager
),
1688 MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1689 ShortDesc(ShortDesc
)
1691 DestFile
= GetPartialFileNameFromURI(RealURI
);
1693 // remove any partial downloaded sig-file in partial/.
1694 // it may confuse proxies and is too small to warrant a
1695 // partial download anyway
1696 unlink(DestFile
.c_str());
1698 // set the TransactionManager
1699 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1700 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1701 << TransactionManager
<< std::endl
;
1704 Desc
.Description
= URIDesc
;
1706 Desc
.ShortDesc
= ShortDesc
;
1712 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1716 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1717 // ---------------------------------------------------------------------
1718 /* The only header we use is the last-modified header. */
1719 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1720 HashStringList
const &Hashes
,
1721 pkgAcquire::MethodConfig
*Cfg
)
1723 Item::Done(Message
, Size
, Hashes
, Cfg
);
1725 if(AuthPass
== false)
1727 if(CheckDownloadDone(Message
) == true)
1729 // destfile will be modified to point to MetaIndexFile for the
1730 // gpgv method, so we need to save it here
1731 MetaIndexFileSignature
= DestFile
;
1732 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1736 else if(CheckAuthDone(Message
) == true)
1737 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, GetFinalFilename());
1740 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1742 Item::Failed(Message
,Cnf
);
1744 // check if we need to fail at this point
1745 if (AuthPass
== true && CheckStopAuthentication(Message
))
1748 // FIXME: meh, this is not really elegant
1749 string
const Final
= GetFinalFileNameFromURI(RealURI
);
1750 string
const InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1752 string
const FinalInRelease
= GetFinalFileNameFromURI(InReleaseURI
);
1754 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1756 std::string downgrade_msg
;
1757 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1759 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1761 // meh, the users wants to take risks (we still mark the packages
1762 // from this repository as unauthenticated)
1763 _error
->Warning("%s", downgrade_msg
.c_str());
1764 _error
->Warning(_("This is normally not allowed, but the option "
1765 "Acquire::AllowDowngradeToInsecureRepositories was "
1766 "given to override it."));
1769 _error
->Error("%s", downgrade_msg
.c_str());
1770 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1771 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1772 TransactionManager
->AbortTransaction();
1777 _error
->Warning(_("The data from '%s' is not signed. Packages "
1778 "from that repository can not be authenticated."),
1781 // this ensures that any file in the lists/ dir is removed by the
1783 DestFile
= GetPartialFileNameFromURI(RealURI
);
1784 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1786 // only allow going further if the users explicitely wants it
1787 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
1789 // we parse the indexes here because at this point the user wanted
1790 // a repository that may potentially harm him
1791 MetaIndexParser
->Load(MetaIndexFile
);
1792 if (!VerifyVendor(Message
))
1793 /* expired Release files are still a problem you need extra force for */;
1798 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1799 if (Cnf
->LocalOnly
== true ||
1800 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1807 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1808 pkgAcqMetaBase
*TransactionManager
,
1809 string URI
,string URIDesc
,string ShortDesc
,
1810 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1811 const vector
<IndexTarget
*>* IndexTargets
,
1812 indexRecords
* MetaIndexParser
) :
1813 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, URI
, HashStringList(),
1814 TransactionManager
),
1815 URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1816 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1817 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1819 if(TransactionManager
== NULL
)
1821 this->TransactionManager
= this;
1822 this->TransactionManager
->Add(this);
1825 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1826 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1827 << this->TransactionManager
<< std::endl
;
1830 Init(URIDesc
, ShortDesc
);
1833 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1834 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1836 DestFile
= GetPartialFileNameFromURI(RealURI
);
1839 Desc
.Description
= URIDesc
;
1841 Desc
.ShortDesc
= ShortDesc
;
1844 // we expect more item
1845 ExpectedAdditionalItems
= IndexTargets
->size();
1849 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1850 HashStringList
const &Hashes
,
1851 pkgAcquire::MethodConfig
*Cfg
)
1853 Item::Done(Message
,Size
,Hashes
,Cfg
);
1855 if(CheckDownloadDone(Message
))
1857 // we have a Release file, now download the Signature, all further
1858 // verify/queue for additional downloads will be done in the
1859 // pkgAcqMetaSig::Done() code
1860 std::string MetaIndexFile
= DestFile
;
1861 new pkgAcqMetaSig(Owner
, TransactionManager
,
1862 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1863 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1866 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1870 bool pkgAcqMetaBase::CheckAuthDone(string Message
) /*{{{*/
1872 // At this point, the gpgv method has succeeded, so there is a
1873 // valid signature from a key in the trusted keyring. We
1874 // perform additional verification of its contents, and use them
1875 // to verify the indexes we are about to download
1877 if (!MetaIndexParser
->Load(DestFile
))
1879 Status
= StatAuthError
;
1880 ErrorText
= MetaIndexParser
->ErrorText
;
1884 if (!VerifyVendor(Message
))
1886 Status
= StatAuthError
;
1890 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1891 std::cerr
<< "Signature verification succeeded: "
1892 << DestFile
<< std::endl
;
1894 // Download further indexes with verification
1900 // pkgAcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
1901 // ---------------------------------------------------------------------
1902 #if APT_PKG_ABI >= 413
1903 string
pkgAcqMetaBase::Custom600Headers() const
1905 string
pkgAcqMetaBase::Custom600Headers()
1908 std::string Header
= "\nIndex-File: true";
1909 std::string MaximumSize
;
1910 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1911 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1912 Header
+= MaximumSize
;
1914 string
const FinalFile
= GetFinalFilename();
1917 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1918 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1923 // pkgAcqMetaBase::GetFinalFilename - Return the full final file path /*{{{*/
1924 std::string
pkgAcqMetaBase::GetFinalFilename() const
1926 return GetFinalFileNameFromURI(RealURI
);
1929 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1930 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1931 const std::string
&MetaIndexFileSignature
)
1934 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1935 DestFile
= MetaIndexFile
;
1937 SetActiveSubprocess("gpgv");
1940 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1941 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
)
1943 // We have just finished downloading a Release file (it is not
1946 string FileName
= LookupTag(Message
,"Filename");
1947 if (FileName
.empty() == true)
1950 ErrorText
= "Method gave a blank filename";
1954 if (FileName
!= DestFile
)
1957 Desc
.URI
= "copy:" + FileName
;
1962 // make sure to verify against the right file on I-M-S hit
1963 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1966 // for simplicity, the transaction manager is always InRelease
1967 // even if it doesn't exist.
1968 if (TransactionManager
!= NULL
)
1969 TransactionManager
->IMSHit
= true;
1970 DestFile
= GetFinalFilename();
1973 // set Item to complete as the remaining work is all local (verify etc)
1979 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1981 // at this point the real Items are loaded in the fetcher
1982 ExpectedAdditionalItems
= 0;
1984 vector
<struct IndexTarget
*>::const_iterator Target
;
1985 for (Target
= IndexTargets
->begin();
1986 Target
!= IndexTargets
->end();
1989 HashStringList ExpectedIndexHashes
;
1990 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1992 // optional target that we do not have in the Release file are
1994 if (verify
== true && Record
== NULL
&& (*Target
)->IsOptional())
1997 // targets without a hash record are a error when verify is required
1998 if (verify
== true && Record
== NULL
)
2000 Status
= StatAuthError
;
2001 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2006 ExpectedIndexHashes
= Record
->Hashes
;
2008 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2010 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2011 << "Expected Hash:" << std::endl
;
2012 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2013 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2014 std::cerr
<< "For: " << ((Record
== NULL
) ? "<NULL>" : Record
->MetaKeyFilename
) << std::endl
;
2017 if (verify
== true && ExpectedIndexHashes
.empty() == true)
2019 Status
= StatAuthError
;
2020 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2024 /* Queue the Index file (Packages, Sources, Translation-$foo
2025 (either diff or full packages files, depending
2026 on the users option) - we also check if the PDiff Index file is listed
2027 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2028 instead, but passing the required info to it is to much hassle */
2029 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2030 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2031 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2033 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2037 bool pkgAcqMetaBase::VerifyVendor(string Message
) /*{{{*/
2039 string::size_type pos
;
2041 // check for missing sigs (that where not fatal because otherwise we had
2044 string msg
= _("There is no public key available for the "
2045 "following key IDs:\n");
2046 pos
= Message
.find("NO_PUBKEY ");
2047 if (pos
!= std::string::npos
)
2049 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2050 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2051 missingkeys
+= (Fingerprint
);
2053 if(!missingkeys
.empty())
2054 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2056 string Transformed
= MetaIndexParser
->GetExpectedDist();
2058 if (Transformed
== "../project/experimental")
2060 Transformed
= "experimental";
2063 pos
= Transformed
.rfind('/');
2064 if (pos
!= string::npos
)
2066 Transformed
= Transformed
.substr(0, pos
);
2069 if (Transformed
== ".")
2074 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2075 MetaIndexParser
->GetValidUntil() > 0) {
2076 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2077 if (invalid_since
> 0)
2081 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2082 // the time since then the file is invalid - formated in the same way as in
2083 // the download progress display (e.g. 7d 3h 42min 1s)
2084 _("Release file for %s is expired (invalid since %s). "
2085 "Updates for this repository will not be applied."),
2086 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2087 if (ErrorText
.empty())
2089 return _error
->Error("%s", errmsg
.c_str());
2093 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2095 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2096 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2097 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2100 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2102 // This might become fatal one day
2103 // Status = StatAuthError;
2104 // ErrorText = "Conflicting distribution; expected "
2105 // + MetaIndexParser->GetExpectedDist() + " but got "
2106 // + MetaIndexParser->GetDist();
2108 if (!Transformed
.empty())
2110 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2111 Desc
.Description
.c_str(),
2112 Transformed
.c_str(),
2113 MetaIndexParser
->GetDist().c_str());
2120 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2121 void pkgAcqMetaIndex::Failed(string Message
,
2122 pkgAcquire::MethodConfig
* Cnf
)
2124 pkgAcquire::Item::Failed(Message
, Cnf
);
2127 _error
->Warning(_("The repository '%s' does not have a Release file. "
2128 "This is deprecated, please contact the owner of the "
2129 "repository."), URIDesc
.c_str());
2131 // No Release file was present so fall
2132 // back to queueing Packages files without verification
2133 // only allow going further if the users explicitely wants it
2134 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2136 // Done, queue for rename on transaction finished
2137 if (FileExists(DestFile
))
2138 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2140 // queue without any kind of hashsum support
2141 QueueIndexes(false);
2145 void pkgAcqMetaIndex::Finished() /*{{{*/
2147 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2148 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2149 if(TransactionManager
!= NULL
&&
2150 TransactionManager
->TransactionHasError() == false)
2151 TransactionManager
->CommitTransaction();
2154 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2155 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2156 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2157 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2158 const vector
<IndexTarget
*>* IndexTargets
,
2159 indexRecords
* MetaIndexParser
) :
2160 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2161 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2162 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2164 // index targets + (worst case:) Release/Release.gpg
2165 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2169 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2173 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2174 #if APT_PKG_ABI >= 413
2175 string
pkgAcqMetaClearSig::Custom600Headers() const
2177 string
pkgAcqMetaClearSig::Custom600Headers()
2180 string Header
= pkgAcqMetaBase::Custom600Headers();
2181 Header
+= "\nFail-Ignore: true";
2185 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2186 // ---------------------------------------------------------------------
2187 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2188 HashStringList
const &Hashes
,
2189 pkgAcquire::MethodConfig
*Cnf
)
2191 Item::Done(Message
, Size
, Hashes
, Cnf
);
2193 // if we expect a ClearTextSignature (InRelase), ensure that
2194 // this is what we get and if not fail to queue a
2195 // Release/Release.gpg, see #346386
2196 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2198 pkgAcquire::Item::Failed(Message
, Cnf
);
2199 RenameOnError(NotClearsigned
);
2200 TransactionManager
->AbortTransaction();
2204 if(AuthPass
== false)
2206 if(CheckDownloadDone(Message
) == true)
2207 QueueForSignatureVerify(DestFile
, DestFile
);
2210 else if(CheckAuthDone(Message
) == true)
2211 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2214 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2216 Item::Failed(Message
, Cnf
);
2218 // we failed, we will not get additional items from this method
2219 ExpectedAdditionalItems
= 0;
2221 if (AuthPass
== false)
2223 // Queue the 'old' InRelease file for removal if we try Release.gpg
2224 // as otherwise the file will stay around and gives a false-auth
2225 // impression (CVE-2012-0214)
2226 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
2229 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2230 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2231 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2232 IndexTargets
, MetaIndexParser
);
2236 if(CheckStopAuthentication(Message
))
2239 _error
->Warning(_("The data from '%s' is not signed. Packages "
2240 "from that repository can not be authenticated."),
2243 // No Release file was present, or verification failed, so fall
2244 // back to queueing Packages files without verification
2245 // only allow going further if the users explicitely wants it
2246 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2250 /* Always move the meta index, even if gpgv failed. This ensures
2251 * that PackageFile objects are correctly filled in */
2252 if (FileExists(DestFile
))
2254 string FinalFile
= GetFinalFilename();
2255 /* InRelease files become Release files, otherwise
2256 * they would be considered as trusted later on */
2257 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2259 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2262 // Done, queue for rename on transaction finished
2263 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2265 QueueIndexes(false);
2270 // AcqArchive::AcqArchive - Constructor /*{{{*/
2271 // ---------------------------------------------------------------------
2272 /* This just sets up the initial fetch environment and queues the first
2274 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2275 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2276 string
&StoreFilename
) :
2277 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2278 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2281 Retries
= _config
->FindI("Acquire::Retries",0);
2283 if (Version
.Arch() == 0)
2285 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2286 "This might mean you need to manually fix this package. "
2287 "(due to missing arch)"),
2288 Version
.ParentPkg().FullName().c_str());
2292 /* We need to find a filename to determine the extension. We make the
2293 assumption here that all the available sources for this version share
2294 the same extension.. */
2295 // Skip not source sources, they do not have file fields.
2296 for (; Vf
.end() == false; ++Vf
)
2298 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2303 // Does not really matter here.. we are going to fail out below
2304 if (Vf
.end() != true)
2306 // If this fails to get a file name we will bomb out below.
2307 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2308 if (_error
->PendingError() == true)
2311 // Generate the final file name as: package_version_arch.foo
2312 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2313 QuoteString(Version
.VerStr(),"_:") + '_' +
2314 QuoteString(Version
.Arch(),"_:.") +
2315 "." + flExtension(Parse
.FileName());
2318 // check if we have one trusted source for the package. if so, switch
2319 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2320 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2321 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2322 bool seenUntrusted
= false;
2323 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2325 pkgIndexFile
*Index
;
2326 if (Sources
->FindIndex(i
.File(),Index
) == false)
2329 if (debugAuth
== true)
2330 std::cerr
<< "Checking index: " << Index
->Describe()
2331 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2333 if (Index
->IsTrusted() == true)
2336 if (allowUnauth
== false)
2340 seenUntrusted
= true;
2343 // "allow-unauthenticated" restores apts old fetching behaviour
2344 // that means that e.g. unauthenticated file:// uris are higher
2345 // priority than authenticated http:// uris
2346 if (allowUnauth
== true && seenUntrusted
== true)
2350 if (QueueNext() == false && _error
->PendingError() == false)
2351 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2352 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2355 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2356 // ---------------------------------------------------------------------
2357 /* This queues the next available file version for download. It checks if
2358 the archive is already available in the cache and stashs the MD5 for
2360 bool pkgAcqArchive::QueueNext()
2362 for (; Vf
.end() == false; ++Vf
)
2364 // Ignore not source sources
2365 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2368 // Try to cross match against the source list
2369 pkgIndexFile
*Index
;
2370 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2373 // only try to get a trusted package from another source if that source
2375 if(Trusted
&& !Index
->IsTrusted())
2378 // Grab the text package record
2379 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2380 if (_error
->PendingError() == true)
2383 string PkgFile
= Parse
.FileName();
2384 ExpectedHashes
= Parse
.Hashes();
2386 if (PkgFile
.empty() == true)
2387 return _error
->Error(_("The package index files are corrupted. No Filename: "
2388 "field for package %s."),
2389 Version
.ParentPkg().Name());
2391 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2392 Desc
.Description
= Index
->ArchiveInfo(Version
);
2394 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2396 // See if we already have the file. (Legacy filenames)
2397 FileSize
= Version
->Size
;
2398 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2400 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2402 // Make sure the size matches
2403 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2408 StoreFilename
= DestFile
= FinalFile
;
2412 /* Hmm, we have a file and its size does not match, this means it is
2413 an old style mismatched arch */
2414 unlink(FinalFile
.c_str());
2417 // Check it again using the new style output filenames
2418 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2419 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2421 // Make sure the size matches
2422 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2427 StoreFilename
= DestFile
= FinalFile
;
2431 /* Hmm, we have a file and its size does not match, this shouldn't
2433 unlink(FinalFile
.c_str());
2436 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2438 // Check the destination file
2439 if (stat(DestFile
.c_str(),&Buf
) == 0)
2441 // Hmm, the partial file is too big, erase it
2442 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2443 unlink(DestFile
.c_str());
2445 PartialSize
= Buf
.st_size
;
2448 // Disables download of archives - useful if no real installation follows,
2449 // e.g. if we are just interested in proposed installation order
2450 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2455 StoreFilename
= DestFile
= FinalFile
;
2469 // AcqArchive::Done - Finished fetching /*{{{*/
2470 // ---------------------------------------------------------------------
2472 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2473 pkgAcquire::MethodConfig
*Cfg
)
2475 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2478 if (Size
!= Version
->Size
)
2480 RenameOnError(SizeMismatch
);
2484 // FIXME: could this empty() check impose *any* sort of security issue?
2485 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2487 RenameOnError(HashSumMismatch
);
2488 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2492 // Grab the output filename
2493 string FileName
= LookupTag(Message
,"Filename");
2494 if (FileName
.empty() == true)
2497 ErrorText
= "Method gave a blank filename";
2501 // Reference filename
2502 if (FileName
!= DestFile
)
2504 StoreFilename
= DestFile
= FileName
;
2510 // Done, move it into position
2511 string
const FinalFile
= GetFinalFilename();
2512 Rename(DestFile
,FinalFile
);
2513 StoreFilename
= DestFile
= FinalFile
;
2517 // Acquire::Item::GetFinalFilename - Return the full final file path /*{{{*/
2518 std::string
pkgAcqArchive::GetFinalFilename() const
2520 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2523 // AcqArchive::Failed - Failure handler /*{{{*/
2524 // ---------------------------------------------------------------------
2525 /* Here we try other sources */
2526 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2528 Item::Failed(Message
,Cnf
);
2530 /* We don't really want to retry on failed media swaps, this prevents
2531 that. An interesting observation is that permanent failures are not
2533 if (Cnf
->Removable
== true &&
2534 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2536 // Vf = Version.FileList();
2537 while (Vf
.end() == false) ++Vf
;
2538 StoreFilename
= string();
2543 if (QueueNext() == false)
2545 // This is the retry counter
2547 Cnf
->LocalOnly
== false &&
2548 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2551 Vf
= Version
.FileList();
2552 if (QueueNext() == true)
2556 StoreFilename
= string();
2561 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2562 // ---------------------------------------------------------------------
2563 #if APT_PKG_ABI >= 413
2564 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2566 APT_PURE
bool pkgAcqArchive::IsTrusted()
2572 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2573 // ---------------------------------------------------------------------
2575 void pkgAcqArchive::Finished()
2577 if (Status
== pkgAcquire::Item::StatDone
&&
2580 StoreFilename
= string();
2583 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2584 // ---------------------------------------------------------------------
2585 /* The file is added to the queue */
2586 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2587 unsigned long long Size
,string Dsc
,string ShortDesc
,
2588 const string
&DestDir
, const string
&DestFilename
,
2590 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2592 Retries
= _config
->FindI("Acquire::Retries",0);
2594 if(!DestFilename
.empty())
2595 DestFile
= DestFilename
;
2596 else if(!DestDir
.empty())
2597 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2599 DestFile
= flNotDir(URI
);
2603 Desc
.Description
= Dsc
;
2606 // Set the short description to the archive component
2607 Desc
.ShortDesc
= ShortDesc
;
2609 // Get the transfer sizes
2612 if (stat(DestFile
.c_str(),&Buf
) == 0)
2614 // Hmm, the partial file is too big, erase it
2615 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2616 unlink(DestFile
.c_str());
2618 PartialSize
= Buf
.st_size
;
2624 // AcqFile::Done - Item downloaded OK /*{{{*/
2625 // ---------------------------------------------------------------------
2627 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2628 pkgAcquire::MethodConfig
*Cnf
)
2630 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2633 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2635 RenameOnError(HashSumMismatch
);
2636 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2640 string FileName
= LookupTag(Message
,"Filename");
2641 if (FileName
.empty() == true)
2644 ErrorText
= "Method gave a blank filename";
2650 // The files timestamp matches
2651 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2654 // We have to copy it into place
2655 if (FileName
!= DestFile
)
2658 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2659 Cnf
->Removable
== true)
2661 Desc
.URI
= "copy:" + FileName
;
2666 // Erase the file if it is a symlink so we can overwrite it
2668 if (lstat(DestFile
.c_str(),&St
) == 0)
2670 if (S_ISLNK(St
.st_mode
) != 0)
2671 unlink(DestFile
.c_str());
2675 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2677 _error
->PushToStack();
2678 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
2679 std::stringstream msg
;
2680 _error
->DumpErrors(msg
);
2681 _error
->RevertToStack();
2682 ErrorText
= msg
.str();
2689 // AcqFile::Failed - Failure handler /*{{{*/
2690 // ---------------------------------------------------------------------
2691 /* Here we try other sources */
2692 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2694 Item::Failed(Message
,Cnf
);
2696 // This is the retry counter
2698 Cnf
->LocalOnly
== false &&
2699 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2709 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2710 // ---------------------------------------------------------------------
2711 /* The only header we use is the last-modified header. */
2712 #if APT_PKG_ABI >= 413
2713 string
pkgAcqFile::Custom600Headers() const
2715 string
pkgAcqFile::Custom600Headers()
2719 return "\nIndex-File: true";