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 bool pkgAcquire::Item::TransactionState(TransactionStates
const state
) /*{{{*/
178 bool const Debug
= _config
->FindB("Debug::Acquire::Transaction", false);
181 case TransactionAbort
:
183 std::clog
<< " Cancel: " << DestFile
<< std::endl
;
184 if (Status
== pkgAcquire::Item::StatIdle
)
186 Status
= pkgAcquire::Item::StatDone
;
190 case TransactionCommit
:
191 if(PartialFile
!= "")
194 std::clog
<< "mv " << PartialFile
<< " -> "<< DestFile
<< " # " << DescURI() << std::endl
;
196 Rename(PartialFile
, DestFile
);
199 std::clog
<< "rm " << DestFile
<< " # " << DescURI() << std::endl
;
200 unlink(DestFile
.c_str());
202 // mark that this transaction is finished
203 TransactionManager
= 0;
209 // Acquire::Item::Start - Item has begun to download /*{{{*/
210 // ---------------------------------------------------------------------
211 /* Stash status and the file size. Note that setting Complete means
212 sub-phases of the acquire process such as decompresion are operating */
213 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
215 Status
= StatFetching
;
217 if (FileSize
== 0 && Complete
== false)
221 // Acquire::Item::Done - Item downloaded OK /*{{{*/
222 // ---------------------------------------------------------------------
224 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
225 pkgAcquire::MethodConfig
* /*Cnf*/)
227 // We just downloaded something..
228 string FileName
= LookupTag(Message
,"Filename");
229 UsedMirror
= LookupTag(Message
,"UsedMirror");
230 if (Complete
== false && !Local
&& FileName
== DestFile
)
233 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
239 ErrorText
= string();
240 Owner
->Dequeue(this);
243 // Acquire::Item::Rename - Rename a file /*{{{*/
244 // ---------------------------------------------------------------------
245 /* This helper function is used by a lot of item methods as their final
247 bool pkgAcquire::Item::Rename(string From
,string To
)
249 if (From
== To
|| rename(From
.c_str(),To
.c_str()) == 0)
253 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
254 From
.c_str(),To
.c_str());
256 if (ErrorText
.empty())
259 ErrorText
= ErrorText
+ ": " + S
;
263 // Acquire::Item::QueueURI and specialisations from child classes /*{{{*/
264 /* The idea here is that an item isn't queued if it exists on disk and the
265 transition manager was a hit as this means that the files it contains
266 the checksums for can't be updated either (or they are and we are asking
267 for a hashsum mismatch to happen which helps nobody) */
268 bool pkgAcquire::Item::QueueURI(ItemDesc
&Item
)
270 std::string
const FinalFile
= GetFinalFilename();
271 if (TransactionManager
!= NULL
&& TransactionManager
->IMSHit
== true &&
272 FileExists(FinalFile
) == true)
274 PartialFile
= DestFile
= FinalFile
;
279 Owner
->Enqueue(Item
);
282 /* The transition manager InRelease itself (or its older sisters-in-law
283 Release & Release.gpg) is always queued as this allows us to rerun gpgv
284 on it to verify that we aren't stalled with old files */
285 bool pkgAcqMetaBase::QueueURI(pkgAcquire::ItemDesc
&Item
)
287 Owner
->Enqueue(Item
);
290 /* the Diff/Index needs to queue also the up-to-date complete index file
291 to ensure that the list cleaner isn't eating it */
292 bool pkgAcqDiffIndex::QueueURI(pkgAcquire::ItemDesc
&Item
)
294 if (pkgAcquire::Item::QueueURI(Item
) == true)
300 void pkgAcquire::Item::Dequeue() /*{{{*/
302 Owner
->Dequeue(this);
305 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
307 if (RealFileExists(DestFile
))
308 Rename(DestFile
, DestFile
+ ".FAILED");
312 case HashSumMismatch
:
313 ErrorText
= _("Hash Sum mismatch");
314 Status
= StatAuthError
;
315 ReportMirrorFailure("HashChecksumFailure");
318 ErrorText
= _("Size mismatch");
319 Status
= StatAuthError
;
320 ReportMirrorFailure("SizeFailure");
323 ErrorText
= _("Invalid file format");
325 // do not report as usually its not the mirrors fault, but Portal/Proxy
328 ErrorText
= _("Signature error");
332 ErrorText
= _("Does not start with a cleartext signature");
335 case MaximumSizeExceeded
:
336 // the method is expected to report a good error for this
340 // no handling here, done by callers
346 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
348 ActiveSubprocess
= subprocess
;
349 APT_IGNORE_DEPRECATED(Mode
= ActiveSubprocess
.c_str();)
352 // Acquire::Item::GetFinalFilename - Return the full final file path /*{{{*/
353 std::string
pkgAcquire::Item::GetFinalFilename() const
355 return GetFinalFileNameFromURI(Desc
.URI
);
358 // Acquire::Item::ReportMirrorFailure /*{{{*/
359 // ---------------------------------------------------------------------
360 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
362 // we only act if a mirror was used at all
363 if(UsedMirror
.empty())
366 std::cerr
<< "\nReportMirrorFailure: "
368 << " Uri: " << DescURI()
370 << FailCode
<< std::endl
;
372 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
373 "/usr/lib/apt/apt-report-mirror-failure");
374 if(!FileExists(report
))
377 std::vector
<char const*> Args
;
378 Args
.push_back(report
.c_str());
379 Args
.push_back(UsedMirror
.c_str());
380 Args
.push_back(DescURI().c_str());
381 Args
.push_back(FailCode
.c_str());
382 Args
.push_back(NULL
);
384 pid_t pid
= ExecFork();
387 _error
->Error("ReportMirrorFailure Fork failed");
392 execvp(Args
[0], (char**)Args
.data());
393 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
396 if(!ExecWait(pid
, "report-mirror-failure"))
398 _error
->Warning("Couldn't report problem to '%s'",
399 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
403 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
404 // ---------------------------------------------------------------------
405 /* Get the DiffIndex file first and see if there are patches available
406 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
407 * patches. If anything goes wrong in that process, it will fall back to
408 * the original packages file
410 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
411 pkgAcqMetaBase
*TransactionManager
,
412 IndexTarget
const * const Target
,
413 HashStringList
const &ExpectedHashes
,
414 indexRecords
*MetaIndexParser
)
415 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
419 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
421 RealURI
= Target
->URI
;
423 Desc
.Description
= Target
->Description
+ ".diff/Index";
424 Desc
.ShortDesc
= Target
->ShortDesc
;
425 Desc
.URI
= Target
->URI
+ ".diff/Index";
427 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
430 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
432 // look for the current package file
433 CurrentPackagesFile
= GetFinalFileNameFromURI(RealURI
);
435 // FIXME: this file:/ check is a hack to prevent fetching
436 // from local sources. this is really silly, and
437 // should be fixed cleanly as soon as possible
438 if(!FileExists(CurrentPackagesFile
) ||
439 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
441 // we don't have a pkg file or we don't want to queue
442 Failed("No index file, local or canceld by user", NULL
);
447 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
448 << CurrentPackagesFile
<< std::endl
;
454 // Acquire::Item::GetFinalFilename - Return the full final file path /*{{{*/
455 std::string
pkgAcqDiffIndex::GetFinalFilename() const
457 // the logic we inherent from pkgAcqBaseIndex isn't what we need here
458 return pkgAcquire::Item::GetFinalFilename();
461 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
462 // ---------------------------------------------------------------------
463 /* The only header we use is the last-modified header. */
464 #if APT_PKG_ABI >= 413
465 string
pkgAcqDiffIndex::Custom600Headers() const
467 string
pkgAcqDiffIndex::Custom600Headers()
470 string
const Final
= GetFinalFilename();
473 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
476 if (stat(Final
.c_str(),&Buf
) != 0)
477 return "\nIndex-File: true";
479 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
482 void pkgAcqDiffIndex::QueueOnIMSHit() const /*{{{*/
484 // list cleanup needs to know that this file as well as the already
485 // present index is ours, so we create an empty diff to save it for us
486 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
487 ExpectedHashes
, MetaIndexParser
);
490 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
492 // failing here is fine: our caller will take care of trying to
493 // get the complete file if patching fails
495 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
498 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
500 if (_error
->PendingError() == true)
504 if(unlikely(TF
.Step(Tags
) == false))
507 HashStringList ServerHashes
;
508 unsigned long long ServerSize
= 0;
510 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
512 std::string tagname
= *type
;
513 tagname
.append("-Current");
514 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
515 if (tmp
.empty() == true)
519 unsigned long long size
;
520 std::stringstream
ss(tmp
);
522 if (unlikely(hash
.empty() == true))
524 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
526 ServerHashes
.push_back(HashString(*type
, hash
));
530 if (ServerHashes
.usable() == false)
533 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
537 if (ServerHashes
!= HashSums())
541 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
542 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, HashSums());
547 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
549 // we have the same sha1 as the server so we are done here
551 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
556 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
557 Hashes LocalHashesCalc
;
558 LocalHashesCalc
.AddFD(fd
);
559 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
562 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
563 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
565 // parse all of (provided) history
566 vector
<DiffInfo
> available_patches
;
567 bool firstAcceptedHashes
= true;
568 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
570 if (LocalHashes
.find(*type
) == NULL
)
573 std::string tagname
= *type
;
574 tagname
.append("-History");
575 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
576 if (tmp
.empty() == true)
579 string hash
, filename
;
580 unsigned long long size
;
581 std::stringstream
ss(tmp
);
583 while (ss
>> hash
>> size
>> filename
)
585 if (unlikely(hash
.empty() == true || filename
.empty() == true))
588 // see if we have a record for this file already
589 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
590 for (; cur
!= available_patches
.end(); ++cur
)
592 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
594 cur
->result_hashes
.push_back(HashString(*type
, hash
));
597 if (cur
!= available_patches
.end())
599 if (firstAcceptedHashes
== true)
602 next
.file
= filename
;
603 next
.result_hashes
.push_back(HashString(*type
, hash
));
604 next
.result_size
= size
;
606 available_patches
.push_back(next
);
611 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
612 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
616 firstAcceptedHashes
= false;
619 if (unlikely(available_patches
.empty() == true))
622 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
623 << "Couldn't find any patches for the patch series." << std::endl
;
627 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
629 if (LocalHashes
.find(*type
) == NULL
)
632 std::string tagname
= *type
;
633 tagname
.append("-Patches");
634 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
635 if (tmp
.empty() == true)
638 string hash
, filename
;
639 unsigned long long size
;
640 std::stringstream
ss(tmp
);
642 while (ss
>> hash
>> size
>> filename
)
644 if (unlikely(hash
.empty() == true || filename
.empty() == true))
647 // see if we have a record for this file already
648 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
649 for (; cur
!= available_patches
.end(); ++cur
)
651 if (cur
->file
!= filename
)
653 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
655 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
656 cur
->patch_size
= size
;
659 if (cur
!= available_patches
.end())
662 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
663 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
668 bool foundStart
= false;
669 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
670 cur
!= available_patches
.end(); ++cur
)
672 if (LocalHashes
!= cur
->result_hashes
)
675 available_patches
.erase(available_patches
.begin(), cur
);
680 if (foundStart
== false || unlikely(available_patches
.empty() == true))
683 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
684 << "Couldn't find the start of the patch series." << std::endl
;
688 // patching with too many files is rather slow compared to a fast download
689 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
690 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
693 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
694 << ") so fallback to complete download" << std::endl
;
698 // calculate the size of all patches we have to get
699 // note that all sizes are uncompressed, while we download compressed files
700 unsigned long long patchesSize
= 0;
701 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
702 cur
!= available_patches
.end(); ++cur
)
703 patchesSize
+= cur
->patch_size
;
704 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
705 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
708 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
709 << ") so fallback to complete download" << std::endl
;
713 // we have something, queue the diffs
714 string::size_type
const last_space
= Description
.rfind(" ");
715 if(last_space
!= string::npos
)
716 Description
.erase(last_space
, Description
.size()-last_space
);
718 /* decide if we should download patches one by one or in one go:
719 The first is good if the server merges patches, but many don't so client
720 based merging can be attempt in which case the second is better.
721 "bad things" will happen if patches are merged on the server,
722 but client side merging is attempt as well */
723 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
724 if (pdiff_merge
== true)
726 // reprepro adds this flag if it has merged patches on the server
727 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
728 pdiff_merge
= (precedence
!= "merged");
731 if (pdiff_merge
== false)
733 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
734 MetaIndexParser
, available_patches
);
738 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
739 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
740 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
744 available_patches
[i
],
754 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
756 Item::Failed(Message
,Cnf
);
760 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
761 << "Falling back to normal index file acquire" << std::endl
;
763 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
766 bool pkgAcqDiffIndex::TransactionState(TransactionStates
const state
) /*{{{*/
768 if (pkgAcquire::Item::TransactionState(state
) == false)
773 case TransactionCommit
:
775 case TransactionAbort
:
776 std::string
const Partial
= GetPartialFileNameFromURI(RealURI
);
777 unlink(Partial
.c_str());
784 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
785 pkgAcquire::MethodConfig
*Cnf
)
788 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
790 Item::Done(Message
, Size
, Hashes
, Cnf
);
792 // verify the index target
793 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
795 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
796 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
797 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
799 RenameOnError(HashSumMismatch
);
800 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
801 Failed(Message
, Cnf
);
807 string
const FinalFile
= GetFinalFilename();
808 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
809 DestFile
= FinalFile
;
811 if(ParseDiffIndex(DestFile
) == false)
813 Failed("Message: Couldn't parse pdiff index", Cnf
);
814 // queue for final move - this should happen even if we fail
815 // while parsing (e.g. on sizelimit) and download the complete file.
816 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
820 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
829 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
830 // ---------------------------------------------------------------------
831 /* The package diff is added to the queue. one object is constructed
832 * for each diff and the index
834 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
835 pkgAcqMetaBase
*TransactionManager
,
836 struct IndexTarget
const * const Target
,
837 HashStringList
const &ExpectedHashes
,
838 indexRecords
*MetaIndexParser
,
839 vector
<DiffInfo
> diffs
)
840 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
841 available_patches(diffs
)
843 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
845 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
847 RealURI
= Target
->URI
;
849 Description
= Target
->Description
;
850 Desc
.ShortDesc
= Target
->ShortDesc
;
852 if(available_patches
.empty() == true)
854 // we are done (yeah!), check hashes against the final file
855 DestFile
= GetFinalFileNameFromURI(Target
->URI
);
860 // patching needs to be bootstrapped with the 'old' version
861 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
862 if (RealFileExists(PartialFile
) == false)
864 if (symlink(GetFinalFilename().c_str(), PartialFile
.c_str()) != 0)
866 Failed("Link creation of " + PartialFile
+ " to " + GetFinalFilename() + " failed", NULL
);
872 State
= StateFetchDiff
;
877 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
879 Item::Failed(Message
,Cnf
);
883 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
884 << "Falling back to normal index file acquire" << std::endl
;
885 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
886 RenameOnError(PDiffError
);
887 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
891 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
892 void pkgAcqIndexDiffs::Finish(bool allDone
)
895 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
897 << Desc
.URI
<< std::endl
;
899 // we restore the original name, this is required, otherwise
900 // the file will be cleaned
903 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
905 RenameOnError(HashSumMismatch
);
910 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
912 // this is for the "real" finish
917 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
922 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
929 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
931 // calc sha1 of the just patched file
932 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
934 if(!FileExists(FinalFile
))
936 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
940 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
941 Hashes LocalHashesCalc
;
942 LocalHashesCalc
.AddFD(fd
);
943 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
946 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
948 if (unlikely(LocalHashes
.usable() == false || ExpectedHashes
.usable() == false))
950 Failed("Local/Expected hashes are not usable", NULL
);
955 // final file reached before all patches are applied
956 if(LocalHashes
== ExpectedHashes
)
962 // remove all patches until the next matching patch is found
963 // this requires the Index file to be ordered
964 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
965 available_patches
.empty() == false &&
966 I
!= available_patches
.end() &&
967 I
->result_hashes
!= LocalHashes
;
970 available_patches
.erase(I
);
973 // error checking and falling back if no patch was found
974 if(available_patches
.empty() == true)
976 Failed("No patches left to reach target", NULL
);
980 // queue the right diff
981 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
982 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
983 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
986 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
993 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
994 pkgAcquire::MethodConfig
*Cnf
)
997 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
999 Item::Done(Message
, Size
, Hashes
, Cnf
);
1001 // FIXME: verify this download too before feeding it to rred
1002 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1004 // success in downloading a diff, enter ApplyDiff state
1005 if(State
== StateFetchDiff
)
1007 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1008 class Hashes LocalHashesCalc
;
1009 LocalHashesCalc
.AddFD(fd
);
1010 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1012 if (fd
.Size() != available_patches
[0].patch_size
||
1013 available_patches
[0].patch_hashes
!= LocalHashes
)
1015 // patchfiles are dated, so bad indicates a bad download, so kill it
1016 unlink(DestFile
.c_str());
1017 Failed("Patch has Size/Hashsum mismatch", NULL
);
1021 // rred excepts the patch as $FinalFile.ed
1022 Rename(DestFile
,FinalFile
+".ed");
1025 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1027 State
= StateApplyDiff
;
1029 Desc
.URI
= "rred:" + FinalFile
;
1031 SetActiveSubprocess("rred");
1036 // success in download/apply a diff, queue next (if needed)
1037 if(State
== StateApplyDiff
)
1039 // remove the just applied patch
1040 available_patches
.erase(available_patches
.begin());
1041 unlink((FinalFile
+ ".ed").c_str());
1046 std::clog
<< "Moving patched file in place: " << std::endl
1047 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1049 Rename(DestFile
,FinalFile
);
1050 chmod(FinalFile
.c_str(),0644);
1052 // see if there is more to download
1053 if(available_patches
.empty() == false) {
1054 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
1055 ExpectedHashes
, MetaIndexParser
,
1060 DestFile
= FinalFile
;
1061 return Finish(true);
1065 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
1066 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
1067 pkgAcqMetaBase
*TransactionManager
,
1068 struct IndexTarget
const * const Target
,
1069 HashStringList
const &ExpectedHashes
,
1070 indexRecords
*MetaIndexParser
,
1071 DiffInfo
const &patch
,
1072 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
1073 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
1074 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
1076 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1078 RealURI
= Target
->URI
;
1080 Description
= Target
->Description
;
1081 Desc
.ShortDesc
= Target
->ShortDesc
;
1083 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
1084 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
1086 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + patch
.file
);
1089 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
1094 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
1097 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
1099 Item::Failed(Message
,Cnf
);
1102 // check if we are the first to fail, otherwise we are done here
1103 State
= StateDoneDiff
;
1104 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1105 I
!= allPatches
->end(); ++I
)
1106 if ((*I
)->State
== StateErrorDiff
)
1109 // first failure means we should fallback
1110 State
= StateErrorDiff
;
1112 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
1113 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
1114 RenameOnError(PDiffError
);
1115 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
1118 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1119 pkgAcquire::MethodConfig
*Cnf
)
1122 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
1124 Item::Done(Message
,Size
,Hashes
,Cnf
);
1126 // FIXME: verify download before feeding it to rred
1127 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1129 if (State
== StateFetchDiff
)
1131 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1132 class Hashes LocalHashesCalc
;
1133 LocalHashesCalc
.AddFD(fd
);
1134 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1136 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1138 // patchfiles are dated, so bad indicates a bad download, so kill it
1139 unlink(DestFile
.c_str());
1140 Failed("Patch has Size/Hashsum mismatch", NULL
);
1144 // rred expects the patch as $FinalFile.ed.$patchname.gz
1145 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1147 // check if this is the last completed diff
1148 State
= StateDoneDiff
;
1149 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1150 I
!= allPatches
->end(); ++I
)
1151 if ((*I
)->State
!= StateDoneDiff
)
1154 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1158 // this is the last completed diff, so we are ready to apply now
1159 State
= StateApplyDiff
;
1161 // patching needs to be bootstrapped with the 'old' version
1162 if (symlink(GetFinalFilename().c_str(), FinalFile
.c_str()) != 0)
1164 Failed("Link creation of " + FinalFile
+ " to " + GetFinalFilename() + " failed", NULL
);
1169 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1172 Desc
.URI
= "rred:" + FinalFile
;
1174 SetActiveSubprocess("rred");
1177 // success in download/apply all diffs, clean up
1178 else if (State
== StateApplyDiff
)
1180 // see if we really got the expected file
1181 if(ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1183 RenameOnError(HashSumMismatch
);
1187 // move the result into place
1188 std::string
const Final
= GetFinalFilename();
1190 std::clog
<< "Queue patched file in place: " << std::endl
1191 << DestFile
<< " -> " << Final
<< std::endl
;
1193 // queue for copy by the transaction manager
1194 TransactionManager
->TransactionStageCopy(this, DestFile
, Final
);
1196 // ensure the ed's are gone regardless of list-cleanup
1197 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1198 I
!= allPatches
->end(); ++I
)
1200 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1201 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1202 unlink(patch
.c_str());
1204 unlink(FinalFile
.c_str());
1209 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1213 // AcqBaseIndex - Constructor /*{{{*/
1214 pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire
*Owner
,
1215 pkgAcqMetaBase
*TransactionManager
,
1216 struct IndexTarget
const * const Target
,
1217 HashStringList
const &ExpectedHashes
,
1218 indexRecords
*MetaIndexParser
)
1219 : Item(Owner
, ExpectedHashes
, TransactionManager
), Target(Target
),
1220 MetaIndexParser(MetaIndexParser
)
1224 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1225 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1227 if(MetaKey
!= "" && Hashes
.usable())
1229 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1230 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1232 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1239 // AcqBaseIndex::GetFinalFilename - Return the full final file path /*{{{*/
1240 std::string
pkgAcqBaseIndex::GetFinalFilename() const
1242 return GetFinalFileNameFromURI(RealURI
);
1245 // AcqIndex::AcqIndex - Constructor /*{{{*/
1246 // ---------------------------------------------------------------------
1247 /* The package file is added to the queue and a second class is
1248 instantiated to fetch the revision file */
1249 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1250 string URI
,string URIDesc
,string ShortDesc
,
1251 HashStringList
const &ExpectedHash
)
1252 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1256 AutoSelectCompression();
1257 Init(URI
, URIDesc
, ShortDesc
);
1259 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1260 std::clog
<< "New pkgIndex with TransactionManager "
1261 << TransactionManager
<< std::endl
;
1264 // AcqIndex::AcqIndex - Constructor /*{{{*/
1265 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1266 pkgAcqMetaBase
*TransactionManager
,
1267 IndexTarget
const *Target
,
1268 HashStringList
const &ExpectedHash
,
1269 indexRecords
*MetaIndexParser
)
1270 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1273 RealURI
= Target
->URI
;
1275 // autoselect the compression method
1276 AutoSelectCompression();
1277 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1279 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1280 std::clog
<< "New pkgIndex with TransactionManager "
1281 << TransactionManager
<< std::endl
;
1284 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1285 void pkgAcqIndex::AutoSelectCompression()
1287 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1288 CompressionExtensions
= "";
1289 if (ExpectedHashes
.usable())
1291 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1292 t
!= types
.end(); ++t
)
1294 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1295 if (*t
== "uncompressed" ||
1296 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1297 CompressionExtensions
.append(*t
).append(" ");
1302 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1303 CompressionExtensions
.append(*t
).append(" ");
1305 if (CompressionExtensions
.empty() == false)
1306 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1309 // AcqIndex::Init - defered Constructor /*{{{*/
1310 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1311 string
const &ShortDesc
)
1313 Stage
= STAGE_DOWNLOAD
;
1315 DestFile
= GetPartialFileNameFromURI(URI
);
1317 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1318 if (CurrentCompressionExtension
== "uncompressed")
1322 MetaKey
= string(Target
->MetaKey
);
1326 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1327 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1329 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1332 // load the filesize
1335 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1337 FileSize
= Record
->Size
;
1339 InitByHashIfNeeded(MetaKey
);
1342 Desc
.Description
= URIDesc
;
1344 Desc
.ShortDesc
= ShortDesc
;
1349 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1350 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1353 // - (maybe?) add support for by-hash into the sources.list as flag
1354 // - make apt-ftparchive generate the hashes (and expire?)
1355 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1356 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1357 _config
->FindB(HostKnob
, false) == true ||
1358 MetaIndexParser
->GetSupportsAcquireByHash())
1360 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1363 // FIXME: should we really use the best hash here? or a fixed one?
1364 const HashString
*TargetHash
= Record
->Hashes
.find("");
1365 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1366 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1367 Desc
.URI
= Desc
.URI
.replace(
1369 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1373 "Fetching ByHash requested but can not find record for %s",
1379 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1380 // ---------------------------------------------------------------------
1381 /* The only header we use is the last-modified header. */
1382 #if APT_PKG_ABI >= 413
1383 string
pkgAcqIndex::Custom600Headers() const
1385 string
pkgAcqIndex::Custom600Headers()
1388 string Final
= GetFinalFilename();
1390 string msg
= "\nIndex-File: true";
1392 if (stat(Final
.c_str(),&Buf
) == 0)
1393 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1395 if(Target
->IsOptional())
1396 msg
+= "\nFail-Ignore: true";
1401 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1402 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1404 Item::Failed(Message
,Cnf
);
1406 size_t const nextExt
= CompressionExtensions
.find(' ');
1407 if (nextExt
!= std::string::npos
)
1409 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1410 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1415 Item::Failed(Message
,Cnf
);
1417 if(Target
->IsOptional() && ExpectedHashes
.empty() && Stage
== STAGE_DOWNLOAD
)
1420 TransactionManager
->AbortTransaction();
1423 bool pkgAcqIndex::TransactionState(TransactionStates
const state
) /*{{{*/
1425 if (pkgAcquire::Item::TransactionState(state
) == false)
1430 case TransactionAbort
:
1431 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1433 // keep the compressed file, but drop the decompressed
1434 EraseFileName
.clear();
1435 if (PartialFile
.empty() == false && flExtension(PartialFile
) == "decomp")
1436 unlink(PartialFile
.c_str());
1439 case TransactionCommit
:
1440 if (EraseFileName
.empty() == false)
1441 unlink(EraseFileName
.c_str());
1447 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1448 std::string
pkgAcqIndex::GetFinalFilename() const
1450 std::string
const FinalFile
= GetFinalFileNameFromURI(RealURI
);
1451 return GetCompressedFileName(RealURI
, FinalFile
, CurrentCompressionExtension
);
1454 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1455 void pkgAcqIndex::ReverifyAfterIMS()
1457 // update destfile to *not* include the compression extension when doing
1458 // a reverify (as its uncompressed on disk already)
1459 DestFile
= GetCompressedFileName(RealURI
, GetPartialFileNameFromURI(RealURI
), CurrentCompressionExtension
);
1461 // copy FinalFile into partial/ so that we check the hash again
1462 string FinalFile
= GetFinalFilename();
1463 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1464 Desc
.URI
= "copy:" + FinalFile
;
1468 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1469 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1471 // FIXME: this can go away once we only ever download stuff that
1472 // has a valid hash and we never do GET based probing
1473 // FIXME2: this also leaks debian-isms into the code and should go therefore
1475 /* Always validate the index file for correctness (all indexes must
1476 * have a Package field) (LP: #346386) (Closes: #627642)
1478 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1479 // Only test for correctness if the content of the file is not empty
1484 pkgTagFile
tag(&fd
);
1486 // all our current indexes have a field 'Package' in each section
1487 if (_error
->PendingError() == true ||
1488 tag
.Step(sec
) == false ||
1489 sec
.Exists("Package") == false)
1495 // AcqIndex::Done - Finished a fetch /*{{{*/
1496 // ---------------------------------------------------------------------
1497 /* This goes through a number of states.. On the initial fetch the
1498 method could possibly return an alternate filename which points
1499 to the uncompressed version of the file. If this is so the file
1500 is copied into the partial directory. In all other cases the file
1501 is decompressed with a compressed uri. */
1502 void pkgAcqIndex::Done(string Message
,
1503 unsigned long long Size
,
1504 HashStringList
const &Hashes
,
1505 pkgAcquire::MethodConfig
*Cfg
)
1507 Item::Done(Message
,Size
,Hashes
,Cfg
);
1511 case STAGE_DOWNLOAD
:
1512 StageDownloadDone(Message
, Hashes
, Cfg
);
1514 case STAGE_DECOMPRESS_AND_VERIFY
:
1515 StageDecompressDone(Message
, Hashes
, Cfg
);
1520 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1521 void pkgAcqIndex::StageDownloadDone(string Message
,
1522 HashStringList
const &Hashes
,
1523 pkgAcquire::MethodConfig
*Cfg
)
1525 // First check if the calculcated Hash of the (compressed) downloaded
1526 // file matches the hash we have in the MetaIndexRecords for this file
1527 if(VerifyHashByMetaKey(Hashes
) == false)
1529 RenameOnError(HashSumMismatch
);
1530 Failed(Message
, Cfg
);
1536 // Handle the unzipd case
1537 string FileName
= LookupTag(Message
,"Alt-Filename");
1538 if (FileName
.empty() == false)
1540 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1542 DestFile
+= ".decomp";
1543 Desc
.URI
= "copy:" + FileName
;
1545 SetActiveSubprocess("copy");
1549 FileName
= LookupTag(Message
,"Filename");
1550 if (FileName
.empty() == true)
1553 ErrorText
= "Method gave a blank filename";
1556 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1557 // not the "DestFile" we set, in this case we uncompress from the local file
1558 if (FileName
!= DestFile
)
1561 EraseFileName
= FileName
;
1563 // we need to verify the file against the current Release file again
1564 // on if-modfied-since hit to avoid a stale attack against us
1565 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1567 // The files timestamp matches, reverify by copy into partial/
1573 // If we have compressed indexes enabled, queue for hash verification
1574 if (_config
->FindB("Acquire::GzipIndexes",false))
1576 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1578 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1579 Desc
.URI
= "copy:" + FileName
;
1581 SetActiveSubprocess("copy");
1585 // get the binary name for your used compression type
1587 if(CurrentCompressionExtension
== "uncompressed")
1588 decompProg
= "copy";
1590 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1591 if(decompProg
.empty() == true)
1593 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1597 // queue uri for the next stage
1598 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1599 DestFile
+= ".decomp";
1600 Desc
.URI
= decompProg
+ ":" + FileName
;
1602 SetActiveSubprocess(decompProg
);
1605 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1606 void pkgAcqIndex::StageDecompressDone(string Message
,
1607 HashStringList
const &Hashes
,
1608 pkgAcquire::MethodConfig
*Cfg
)
1610 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1613 RenameOnError(HashSumMismatch
);
1614 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1615 Failed(Message
, Cfg
);
1619 if(!ValidateFile(DestFile
))
1621 RenameOnError(InvalidFormat
);
1622 Failed(Message
, Cfg
);
1626 // Done, queue for rename on transaction finished
1627 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1632 // AcqMetaBase - Constructor /*{{{*/
1633 pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire
*Owner
,
1634 const std::vector
<IndexTarget
*>* IndexTargets
,
1635 indexRecords
* MetaIndexParser
,
1636 std::string
const &RealURI
,
1637 HashStringList
const &ExpectedHashes
,
1638 pkgAcqMetaBase
*TransactionManager
)
1639 : Item(Owner
, ExpectedHashes
, TransactionManager
),
1640 MetaIndexParser(MetaIndexParser
), LastMetaIndexParser(NULL
), IndexTargets(IndexTargets
),
1641 AuthPass(false), RealURI(RealURI
), IMSHit(false)
1645 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1646 void pkgAcqMetaBase::Add(Item
*I
)
1648 Transaction
.push_back(I
);
1651 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1652 void pkgAcqMetaBase::AbortTransaction()
1654 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1655 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1657 // ensure the toplevel is in error state too
1658 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1659 I
!= Transaction
.end(); ++I
)
1661 (*I
)->TransactionState(TransactionAbort
);
1663 Transaction
.clear();
1666 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1667 bool pkgAcqMetaBase::TransactionHasError()
1669 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1670 I
!= Transaction
.end(); ++I
)
1672 switch((*I
)->Status
) {
1673 case StatDone
: break;
1674 case StatIdle
: break;
1675 case StatAuthError
: return true;
1676 case StatError
: return true;
1677 case StatTransientNetworkError
: return true;
1678 case StatFetching
: break;
1684 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1685 void pkgAcqMetaBase::CommitTransaction()
1687 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1688 std::clog
<< "CommitTransaction: " << this << std::endl
;
1690 // move new files into place *and* remove files that are not
1691 // part of the transaction but are still on disk
1692 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1693 I
!= Transaction
.end(); ++I
)
1695 (*I
)->TransactionState(TransactionCommit
);
1697 Transaction
.clear();
1700 bool pkgAcqMetaBase::TransactionState(TransactionStates
const state
) /*{{{*/
1702 // Do not remove InRelease on IMSHit of Release.gpg [yes, this is very edgecasey]
1703 if (TransactionManager
->IMSHit
== false)
1704 return pkgAcquire::Item::TransactionState(state
);
1708 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1709 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1710 const std::string
&From
,
1711 const std::string
&To
)
1713 I
->PartialFile
= From
;
1717 // AcqMetaBase::TransactionStageRemoval - Stage a file for removal /*{{{*/
1718 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1719 const std::string
&FinalFile
)
1721 I
->PartialFile
= "";
1722 I
->DestFile
= FinalFile
;
1725 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1726 bool pkgAcqMetaBase::CheckStopAuthentication(pkgAcquire::Item
* const I
, const std::string
&Message
)
1728 // FIXME: this entire function can do now that we disallow going to
1729 // a unauthenticated state and can cleanly rollback
1731 string
const Final
= I
->GetFinalFilename();
1732 if(FileExists(Final
))
1734 I
->Status
= StatTransientNetworkError
;
1735 _error
->Warning(_("An error occurred during the signature "
1736 "verification. The repository is not updated "
1737 "and the previous index files will be used. "
1738 "GPG error: %s: %s\n"),
1739 Desc
.Description
.c_str(),
1740 LookupTag(Message
,"Message").c_str());
1741 RunScripts("APT::Update::Auth-Failure");
1743 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1744 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1745 _error
->Error(_("GPG error: %s: %s"),
1746 Desc
.Description
.c_str(),
1747 LookupTag(Message
,"Message").c_str());
1748 I
->Status
= StatError
;
1751 _error
->Warning(_("GPG error: %s: %s"),
1752 Desc
.Description
.c_str(),
1753 LookupTag(Message
,"Message").c_str());
1755 // gpgv method failed
1756 ReportMirrorFailure("GPGFailure");
1760 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1761 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1762 pkgAcqMetaBase
*TransactionManager
,
1763 string
const &URI
, string
const &URIDesc
,string
const &ShortDesc
,
1764 pkgAcqMetaIndex
* const MetaIndex
) :
1765 pkgAcquire::Item(Owner
, HashStringList(), TransactionManager
), MetaIndex(MetaIndex
),
1766 URIDesc(URIDesc
), RealURI(URI
)
1768 DestFile
= GetPartialFileNameFromURI(URI
);
1770 // remove any partial downloaded sig-file in partial/.
1771 // it may confuse proxies and is too small to warrant a
1772 // partial download anyway
1773 unlink(DestFile
.c_str());
1775 // set the TransactionManager
1776 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1777 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1778 << TransactionManager
<< std::endl
;
1781 Desc
.Description
= URIDesc
;
1783 Desc
.ShortDesc
= ShortDesc
;
1786 // If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
1787 // so we skip the download step and go instantly to verification
1788 if (TransactionManager
->IMSHit
== true && RealFileExists(GetFinalFilename()))
1792 PartialFile
= DestFile
= GetFinalFilename();
1793 MetaIndexFileSignature
= DestFile
;
1794 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1800 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1804 // pkgAcqMetaSig::GetFinalFilename - Return the full final file path /*{{{*/
1805 std::string
pkgAcqMetaSig::GetFinalFilename() const
1807 return GetFinalFileNameFromURI(RealURI
);
1810 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1811 // ---------------------------------------------------------------------
1812 /* The only header we use is the last-modified header. */
1813 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1814 HashStringList
const &Hashes
,
1815 pkgAcquire::MethodConfig
*Cfg
)
1817 if (MetaIndexFileSignature
.empty() == false)
1819 DestFile
= MetaIndexFileSignature
;
1820 MetaIndexFileSignature
.clear();
1822 Item::Done(Message
, Size
, Hashes
, Cfg
);
1824 if(MetaIndex
->AuthPass
== false)
1826 if(MetaIndex
->CheckDownloadDone(this, Message
, Hashes
) == true)
1828 // destfile will be modified to point to MetaIndexFile for the
1829 // gpgv method, so we need to save it here
1830 MetaIndexFileSignature
= DestFile
;
1831 MetaIndex
->QueueForSignatureVerify(this, MetaIndex
->DestFile
, DestFile
);
1835 else if(MetaIndex
->CheckAuthDone(Message
) == true)
1837 if (TransactionManager
->IMSHit
== false)
1839 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1840 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1845 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1847 Item::Failed(Message
,Cnf
);
1849 // check if we need to fail at this point
1850 if (MetaIndex
->AuthPass
== true && MetaIndex
->CheckStopAuthentication(this, Message
))
1853 string
const FinalRelease
= MetaIndex
->GetFinalFilename();
1854 string
const FinalReleasegpg
= GetFinalFilename();
1855 string
const FinalInRelease
= TransactionManager
->GetFinalFilename();
1857 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1859 std::string downgrade_msg
;
1860 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1861 MetaIndex
->URIDesc
.c_str());
1862 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1864 // meh, the users wants to take risks (we still mark the packages
1865 // from this repository as unauthenticated)
1866 _error
->Warning("%s", downgrade_msg
.c_str());
1867 _error
->Warning(_("This is normally not allowed, but the option "
1868 "Acquire::AllowDowngradeToInsecureRepositories was "
1869 "given to override it."));
1872 _error
->Error("%s", downgrade_msg
.c_str());
1873 if (TransactionManager
->IMSHit
== false)
1874 Rename(MetaIndex
->DestFile
, MetaIndex
->DestFile
+ ".FAILED");
1875 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1876 TransactionManager
->AbortTransaction();
1881 _error
->Warning(_("The data from '%s' is not signed. Packages "
1882 "from that repository can not be authenticated."),
1883 MetaIndex
->URIDesc
.c_str());
1885 // ensures that a Release.gpg file in the lists/ is removed by the transaction
1886 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1888 // only allow going further if the users explicitely wants it
1889 if(AllowInsecureRepositories(MetaIndex
->MetaIndexParser
, TransactionManager
, this) == true)
1891 if (RealFileExists(FinalReleasegpg
) || RealFileExists(FinalInRelease
))
1893 // open the last Release if we have it
1894 if (TransactionManager
->IMSHit
== false)
1896 MetaIndex
->LastMetaIndexParser
= new indexRecords
;
1897 _error
->PushToStack();
1898 if (RealFileExists(FinalInRelease
))
1899 MetaIndex
->LastMetaIndexParser
->Load(FinalInRelease
);
1901 MetaIndex
->LastMetaIndexParser
->Load(FinalRelease
);
1902 // its unlikely to happen, but if what we have is bad ignore it
1903 if (_error
->PendingError())
1905 delete MetaIndex
->LastMetaIndexParser
;
1906 MetaIndex
->LastMetaIndexParser
= NULL
;
1908 _error
->RevertToStack();
1912 // we parse the indexes here because at this point the user wanted
1913 // a repository that may potentially harm him
1914 MetaIndex
->MetaIndexParser
->Load(MetaIndex
->DestFile
);
1915 if (MetaIndex
->VerifyVendor(Message
) == false)
1916 /* expired Release files are still a problem you need extra force for */;
1918 MetaIndex
->QueueIndexes(true);
1920 TransactionManager
->TransactionStageCopy(MetaIndex
, MetaIndex
->DestFile
, MetaIndex
->GetFinalFilename());
1923 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1924 if (Cnf
->LocalOnly
== true ||
1925 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1932 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1933 pkgAcqMetaBase
*TransactionManager
,
1934 string URI
,string URIDesc
,string ShortDesc
,
1935 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1936 const vector
<IndexTarget
*>* IndexTargets
,
1937 indexRecords
* MetaIndexParser
) :
1938 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, URI
, HashStringList(),
1939 TransactionManager
),
1940 URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1941 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1942 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1944 if(TransactionManager
== NULL
)
1946 this->TransactionManager
= this;
1947 this->TransactionManager
->Add(this);
1950 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1951 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1952 << this->TransactionManager
<< std::endl
;
1955 Init(URIDesc
, ShortDesc
);
1958 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1959 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1961 DestFile
= GetPartialFileNameFromURI(RealURI
);
1964 Desc
.Description
= URIDesc
;
1966 Desc
.ShortDesc
= ShortDesc
;
1969 // we expect more item
1970 ExpectedAdditionalItems
= IndexTargets
->size();
1974 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1975 HashStringList
const &Hashes
,
1976 pkgAcquire::MethodConfig
*Cfg
)
1978 Item::Done(Message
,Size
,Hashes
,Cfg
);
1980 if(CheckDownloadDone(this, Message
, Hashes
))
1982 // we have a Release file, now download the Signature, all further
1983 // verify/queue for additional downloads will be done in the
1984 // pkgAcqMetaSig::Done() code
1985 new pkgAcqMetaSig(Owner
, TransactionManager
,
1986 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1987 MetaIndexSigShortDesc
, this);
1991 bool pkgAcqMetaBase::CheckAuthDone(string Message
) /*{{{*/
1993 // At this point, the gpgv method has succeeded, so there is a
1994 // valid signature from a key in the trusted keyring. We
1995 // perform additional verification of its contents, and use them
1996 // to verify the indexes we are about to download
1998 if (TransactionManager
->IMSHit
== false)
2000 // open the last (In)Release if we have it
2001 std::string
const FinalFile
= GetFinalFilename();
2002 std::string FinalRelease
;
2003 std::string FinalInRelease
;
2004 if (APT::String::Endswith(FinalFile
, "InRelease"))
2006 FinalInRelease
= FinalFile
;
2007 FinalRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("InRelease")) + "Release";
2011 FinalInRelease
= FinalFile
.substr(0, FinalFile
.length() - strlen("Release")) + "InRelease";
2012 FinalRelease
= FinalFile
;
2014 if (RealFileExists(FinalInRelease
) || RealFileExists(FinalRelease
))
2016 LastMetaIndexParser
= new indexRecords
;
2017 _error
->PushToStack();
2018 if (RealFileExists(FinalInRelease
))
2019 LastMetaIndexParser
->Load(FinalInRelease
);
2021 LastMetaIndexParser
->Load(FinalRelease
);
2022 // its unlikely to happen, but if what we have is bad ignore it
2023 if (_error
->PendingError())
2025 delete LastMetaIndexParser
;
2026 LastMetaIndexParser
= NULL
;
2028 _error
->RevertToStack();
2032 if (!MetaIndexParser
->Load(DestFile
))
2034 Status
= StatAuthError
;
2035 ErrorText
= MetaIndexParser
->ErrorText
;
2039 if (!VerifyVendor(Message
))
2041 Status
= StatAuthError
;
2045 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2046 std::cerr
<< "Signature verification succeeded: "
2047 << DestFile
<< std::endl
;
2049 // Download further indexes with verification
2055 // pkgAcqMetaBase::Custom600Headers - Get header for AcqMetaBase /*{{{*/
2056 // ---------------------------------------------------------------------
2057 #if APT_PKG_ABI >= 413
2058 string
pkgAcqMetaBase::Custom600Headers() const
2060 string
pkgAcqMetaBase::Custom600Headers()
2063 std::string Header
= "\nIndex-File: true";
2064 std::string MaximumSize
;
2065 strprintf(MaximumSize
, "\nMaximum-Size: %i",
2066 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
2067 Header
+= MaximumSize
;
2069 string
const FinalFile
= GetFinalFilename();
2072 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2073 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2078 // pkgAcqMetaBase::GetFinalFilename - Return the full final file path /*{{{*/
2079 std::string
pkgAcqMetaBase::GetFinalFilename() const
2081 return GetFinalFileNameFromURI(RealURI
);
2084 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
2085 void pkgAcqMetaBase::QueueForSignatureVerify(pkgAcquire::Item
* const I
, std::string
const &File
, std::string
const &Signature
)
2088 I
->Desc
.URI
= "gpgv:" + Signature
;
2091 I
->SetActiveSubprocess("gpgv");
2094 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
2095 bool pkgAcqMetaBase::CheckDownloadDone(pkgAcquire::Item
* const I
, const std::string
&Message
, HashStringList
const &Hashes
) const
2097 // We have just finished downloading a Release file (it is not
2100 string
const FileName
= LookupTag(Message
,"Filename");
2101 if (FileName
.empty() == true)
2103 I
->Status
= StatError
;
2104 I
->ErrorText
= "Method gave a blank filename";
2108 if (FileName
!= I
->DestFile
)
2111 I
->Desc
.URI
= "copy:" + FileName
;
2112 I
->QueueURI(I
->Desc
);
2116 // make sure to verify against the right file on I-M-S hit
2117 bool IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"), false);
2118 if (IMSHit
== false && Hashes
.usable())
2120 // detect IMS-Hits servers haven't detected by Hash comparison
2121 std::string
const FinalFile
= I
->GetFinalFilename();
2122 if (RealFileExists(FinalFile
) && Hashes
.VerifyFile(FinalFile
) == true)
2125 unlink(I
->DestFile
.c_str());
2131 // for simplicity, the transaction manager is always InRelease
2132 // even if it doesn't exist.
2133 if (TransactionManager
!= NULL
)
2134 TransactionManager
->IMSHit
= true;
2135 I
->PartialFile
= I
->DestFile
= I
->GetFinalFilename();
2138 // set Item to complete as the remaining work is all local (verify etc)
2144 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
2146 // at this point the real Items are loaded in the fetcher
2147 ExpectedAdditionalItems
= 0;
2149 vector
<struct IndexTarget
*>::const_iterator Target
;
2150 for (Target
= IndexTargets
->begin();
2151 Target
!= IndexTargets
->end();
2154 HashStringList ExpectedIndexHashes
;
2155 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
2157 // optional target that we do not have in the Release file are
2159 if (verify
== true && Record
== NULL
&& (*Target
)->IsOptional())
2162 // targets without a hash record are a error when verify is required
2163 if (verify
== true && Record
== NULL
)
2165 Status
= StatAuthError
;
2166 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2171 ExpectedIndexHashes
= Record
->Hashes
;
2173 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2175 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2176 << "Expected Hash:" << std::endl
;
2177 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2178 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2179 std::cerr
<< "For: " << ((Record
== NULL
) ? "<NULL>" : Record
->MetaKeyFilename
) << std::endl
;
2182 if (verify
== true && ExpectedIndexHashes
.empty() == true)
2184 Status
= StatAuthError
;
2185 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2189 /* Queue the Index file (Packages, Sources, Translation-$foo
2190 (either diff or full packages files, depending
2191 on the users option) - we also check if the PDiff Index file is listed
2192 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2193 instead, but passing the required info to it is to much hassle */
2194 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2195 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2196 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2198 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2202 bool pkgAcqMetaBase::VerifyVendor(string Message
) /*{{{*/
2204 string::size_type pos
;
2206 // check for missing sigs (that where not fatal because otherwise we had
2209 string msg
= _("There is no public key available for the "
2210 "following key IDs:\n");
2211 pos
= Message
.find("NO_PUBKEY ");
2212 if (pos
!= std::string::npos
)
2214 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2215 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2216 missingkeys
+= (Fingerprint
);
2218 if(!missingkeys
.empty())
2219 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2221 string Transformed
= MetaIndexParser
->GetExpectedDist();
2223 if (Transformed
== "../project/experimental")
2225 Transformed
= "experimental";
2228 pos
= Transformed
.rfind('/');
2229 if (pos
!= string::npos
)
2231 Transformed
= Transformed
.substr(0, pos
);
2234 if (Transformed
== ".")
2239 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2240 MetaIndexParser
->GetValidUntil() > 0) {
2241 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2242 if (invalid_since
> 0)
2246 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2247 // the time since then the file is invalid - formated in the same way as in
2248 // the download progress display (e.g. 7d 3h 42min 1s)
2249 _("Release file for %s is expired (invalid since %s). "
2250 "Updates for this repository will not be applied."),
2251 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2252 if (ErrorText
.empty())
2254 return _error
->Error("%s", errmsg
.c_str());
2258 /* Did we get a file older than what we have? This is a last minute IMS hit and doubles
2259 as a prevention of downgrading us to older (still valid) files */
2260 if (TransactionManager
->IMSHit
== false && LastMetaIndexParser
!= NULL
&&
2261 LastMetaIndexParser
->GetDate() > MetaIndexParser
->GetDate())
2263 TransactionManager
->IMSHit
= true;
2264 unlink(DestFile
.c_str());
2265 PartialFile
= DestFile
= GetFinalFilename();
2266 delete MetaIndexParser
;
2267 MetaIndexParser
= LastMetaIndexParser
;
2268 LastMetaIndexParser
= NULL
;
2271 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2273 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2274 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2275 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2278 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2280 // This might become fatal one day
2281 // Status = StatAuthError;
2282 // ErrorText = "Conflicting distribution; expected "
2283 // + MetaIndexParser->GetExpectedDist() + " but got "
2284 // + MetaIndexParser->GetDist();
2286 if (!Transformed
.empty())
2288 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2289 Desc
.Description
.c_str(),
2290 Transformed
.c_str(),
2291 MetaIndexParser
->GetDist().c_str());
2298 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2299 void pkgAcqMetaIndex::Failed(string Message
,
2300 pkgAcquire::MethodConfig
* Cnf
)
2302 pkgAcquire::Item::Failed(Message
, Cnf
);
2305 _error
->Warning(_("The repository '%s' does not have a Release file. "
2306 "This is deprecated, please contact the owner of the "
2307 "repository."), URIDesc
.c_str());
2309 // No Release file was present so fall
2310 // back to queueing Packages files without verification
2311 // only allow going further if the users explicitely wants it
2312 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2314 // Done, queue for rename on transaction finished
2315 if (FileExists(DestFile
))
2316 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2318 // queue without any kind of hashsum support
2319 QueueIndexes(false);
2323 void pkgAcqMetaIndex::Finished() /*{{{*/
2325 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2326 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2327 if(TransactionManager
!= NULL
&&
2328 TransactionManager
->TransactionHasError() == false)
2329 TransactionManager
->CommitTransaction();
2332 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2333 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2334 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2335 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2336 const vector
<IndexTarget
*>* IndexTargets
,
2337 indexRecords
* MetaIndexParser
) :
2338 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2339 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2340 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2342 // index targets + (worst case:) Release/Release.gpg
2343 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2346 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2350 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2351 #if APT_PKG_ABI >= 413
2352 string
pkgAcqMetaClearSig::Custom600Headers() const
2354 string
pkgAcqMetaClearSig::Custom600Headers()
2357 string Header
= pkgAcqMetaBase::Custom600Headers();
2358 Header
+= "\nFail-Ignore: true";
2362 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2363 class APT_HIDDEN DummyItem
: public pkgAcquire::Item
2367 virtual std::string
DescURI() {return URI
;};
2369 DummyItem(pkgAcquire
*Owner
, std::string
const &URI
) : pkgAcquire::Item(Owner
), URI(URI
)
2372 DestFile
= GetFinalFileNameFromURI(URI
);
2375 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2376 HashStringList
const &Hashes
,
2377 pkgAcquire::MethodConfig
*Cnf
)
2379 Item::Done(Message
, Size
, Hashes
, Cnf
);
2381 // if we expect a ClearTextSignature (InRelease), ensure that
2382 // this is what we get and if not fail to queue a
2383 // Release/Release.gpg, see #346386
2384 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2386 pkgAcquire::Item::Failed(Message
, Cnf
);
2387 RenameOnError(NotClearsigned
);
2388 TransactionManager
->AbortTransaction();
2392 if(AuthPass
== false)
2394 if(CheckDownloadDone(this, Message
, Hashes
) == true)
2395 QueueForSignatureVerify(this, DestFile
, DestFile
);
2398 else if(CheckAuthDone(Message
) == true)
2400 if (TransactionManager
->IMSHit
== false)
2401 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
2402 else if (RealFileExists(GetFinalFilename()) == false)
2404 // We got an InRelease file IMSHit, but we haven't one, which means
2405 // we had a valid Release/Release.gpg combo stepping in, which we have
2406 // to 'acquire' now to ensure list cleanup isn't removing them
2407 new DummyItem(Owner
, MetaIndexURI
);
2408 new DummyItem(Owner
, MetaSigURI
);
2413 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2415 Item::Failed(Message
, Cnf
);
2417 // we failed, we will not get additional items from this method
2418 ExpectedAdditionalItems
= 0;
2420 if (AuthPass
== false)
2422 // Queue the 'old' InRelease file for removal if we try Release.gpg
2423 // as otherwise the file will stay around and gives a false-auth
2424 // impression (CVE-2012-0214)
2425 TransactionManager
->TransactionStageRemoval(this, GetFinalFilename());
2428 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2429 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2430 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2431 IndexTargets
, MetaIndexParser
);
2435 if(CheckStopAuthentication(this, Message
))
2438 _error
->Warning(_("The data from '%s' is not signed. Packages "
2439 "from that repository can not be authenticated."),
2442 // No Release file was present, or verification failed, so fall
2443 // back to queueing Packages files without verification
2444 // only allow going further if the users explicitely wants it
2445 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2449 /* Always move the meta index, even if gpgv failed. This ensures
2450 * that PackageFile objects are correctly filled in */
2451 if (FileExists(DestFile
))
2453 string FinalFile
= GetFinalFilename();
2454 /* InRelease files become Release files, otherwise
2455 * they would be considered as trusted later on */
2456 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2458 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2461 // Done, queue for rename on transaction finished
2462 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2464 QueueIndexes(false);
2469 // AcqArchive::AcqArchive - Constructor /*{{{*/
2470 // ---------------------------------------------------------------------
2471 /* This just sets up the initial fetch environment and queues the first
2473 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2474 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2475 string
&StoreFilename
) :
2476 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2477 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2480 Retries
= _config
->FindI("Acquire::Retries",0);
2482 if (Version
.Arch() == 0)
2484 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2485 "This might mean you need to manually fix this package. "
2486 "(due to missing arch)"),
2487 Version
.ParentPkg().FullName().c_str());
2491 /* We need to find a filename to determine the extension. We make the
2492 assumption here that all the available sources for this version share
2493 the same extension.. */
2494 // Skip not source sources, they do not have file fields.
2495 for (; Vf
.end() == false; ++Vf
)
2497 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2502 // Does not really matter here.. we are going to fail out below
2503 if (Vf
.end() != true)
2505 // If this fails to get a file name we will bomb out below.
2506 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2507 if (_error
->PendingError() == true)
2510 // Generate the final file name as: package_version_arch.foo
2511 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2512 QuoteString(Version
.VerStr(),"_:") + '_' +
2513 QuoteString(Version
.Arch(),"_:.") +
2514 "." + flExtension(Parse
.FileName());
2517 // check if we have one trusted source for the package. if so, switch
2518 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2519 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2520 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2521 bool seenUntrusted
= false;
2522 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2524 pkgIndexFile
*Index
;
2525 if (Sources
->FindIndex(i
.File(),Index
) == false)
2528 if (debugAuth
== true)
2529 std::cerr
<< "Checking index: " << Index
->Describe()
2530 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2532 if (Index
->IsTrusted() == true)
2535 if (allowUnauth
== false)
2539 seenUntrusted
= true;
2542 // "allow-unauthenticated" restores apts old fetching behaviour
2543 // that means that e.g. unauthenticated file:// uris are higher
2544 // priority than authenticated http:// uris
2545 if (allowUnauth
== true && seenUntrusted
== true)
2549 if (QueueNext() == false && _error
->PendingError() == false)
2550 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2551 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2554 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2555 // ---------------------------------------------------------------------
2556 /* This queues the next available file version for download. It checks if
2557 the archive is already available in the cache and stashs the MD5 for
2559 bool pkgAcqArchive::QueueNext()
2561 for (; Vf
.end() == false; ++Vf
)
2563 // Ignore not source sources
2564 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2567 // Try to cross match against the source list
2568 pkgIndexFile
*Index
;
2569 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2572 // only try to get a trusted package from another source if that source
2574 if(Trusted
&& !Index
->IsTrusted())
2577 // Grab the text package record
2578 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2579 if (_error
->PendingError() == true)
2582 string PkgFile
= Parse
.FileName();
2583 ExpectedHashes
= Parse
.Hashes();
2585 if (PkgFile
.empty() == true)
2586 return _error
->Error(_("The package index files are corrupted. No Filename: "
2587 "field for package %s."),
2588 Version
.ParentPkg().Name());
2590 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2591 Desc
.Description
= Index
->ArchiveInfo(Version
);
2593 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2595 // See if we already have the file. (Legacy filenames)
2596 FileSize
= Version
->Size
;
2597 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2599 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2601 // Make sure the size matches
2602 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2607 StoreFilename
= DestFile
= FinalFile
;
2611 /* Hmm, we have a file and its size does not match, this means it is
2612 an old style mismatched arch */
2613 unlink(FinalFile
.c_str());
2616 // Check it again using the new style output filenames
2617 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2618 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2620 // Make sure the size matches
2621 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2626 StoreFilename
= DestFile
= FinalFile
;
2630 /* Hmm, we have a file and its size does not match, this shouldn't
2632 unlink(FinalFile
.c_str());
2635 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2637 // Check the destination file
2638 if (stat(DestFile
.c_str(),&Buf
) == 0)
2640 // Hmm, the partial file is too big, erase it
2641 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2642 unlink(DestFile
.c_str());
2644 PartialSize
= Buf
.st_size
;
2647 // Disables download of archives - useful if no real installation follows,
2648 // e.g. if we are just interested in proposed installation order
2649 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2654 StoreFilename
= DestFile
= FinalFile
;
2668 // AcqArchive::Done - Finished fetching /*{{{*/
2669 // ---------------------------------------------------------------------
2671 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2672 pkgAcquire::MethodConfig
*Cfg
)
2674 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2677 if (Size
!= Version
->Size
)
2679 RenameOnError(SizeMismatch
);
2683 // FIXME: could this empty() check impose *any* sort of security issue?
2684 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2686 RenameOnError(HashSumMismatch
);
2687 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2691 // Grab the output filename
2692 string FileName
= LookupTag(Message
,"Filename");
2693 if (FileName
.empty() == true)
2696 ErrorText
= "Method gave a blank filename";
2700 // Reference filename
2701 if (FileName
!= DestFile
)
2703 StoreFilename
= DestFile
= FileName
;
2709 // Done, move it into position
2710 string
const FinalFile
= GetFinalFilename();
2711 Rename(DestFile
,FinalFile
);
2712 StoreFilename
= DestFile
= FinalFile
;
2716 // Acquire::Item::GetFinalFilename - Return the full final file path /*{{{*/
2717 std::string
pkgAcqArchive::GetFinalFilename() const
2719 return _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2722 // AcqArchive::Failed - Failure handler /*{{{*/
2723 // ---------------------------------------------------------------------
2724 /* Here we try other sources */
2725 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2727 Item::Failed(Message
,Cnf
);
2729 /* We don't really want to retry on failed media swaps, this prevents
2730 that. An interesting observation is that permanent failures are not
2732 if (Cnf
->Removable
== true &&
2733 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2735 // Vf = Version.FileList();
2736 while (Vf
.end() == false) ++Vf
;
2737 StoreFilename
= string();
2742 if (QueueNext() == false)
2744 // This is the retry counter
2746 Cnf
->LocalOnly
== false &&
2747 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2750 Vf
= Version
.FileList();
2751 if (QueueNext() == true)
2755 StoreFilename
= string();
2760 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2761 // ---------------------------------------------------------------------
2762 #if APT_PKG_ABI >= 413
2763 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2765 APT_PURE
bool pkgAcqArchive::IsTrusted()
2771 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2772 // ---------------------------------------------------------------------
2774 void pkgAcqArchive::Finished()
2776 if (Status
== pkgAcquire::Item::StatDone
&&
2779 StoreFilename
= string();
2782 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2783 // ---------------------------------------------------------------------
2784 /* The file is added to the queue */
2785 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2786 unsigned long long Size
,string Dsc
,string ShortDesc
,
2787 const string
&DestDir
, const string
&DestFilename
,
2789 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2791 Retries
= _config
->FindI("Acquire::Retries",0);
2793 if(!DestFilename
.empty())
2794 DestFile
= DestFilename
;
2795 else if(!DestDir
.empty())
2796 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2798 DestFile
= flNotDir(URI
);
2802 Desc
.Description
= Dsc
;
2805 // Set the short description to the archive component
2806 Desc
.ShortDesc
= ShortDesc
;
2808 // Get the transfer sizes
2811 if (stat(DestFile
.c_str(),&Buf
) == 0)
2813 // Hmm, the partial file is too big, erase it
2814 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2815 unlink(DestFile
.c_str());
2817 PartialSize
= Buf
.st_size
;
2823 // AcqFile::Done - Item downloaded OK /*{{{*/
2824 // ---------------------------------------------------------------------
2826 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2827 pkgAcquire::MethodConfig
*Cnf
)
2829 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2832 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2834 RenameOnError(HashSumMismatch
);
2835 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2839 string FileName
= LookupTag(Message
,"Filename");
2840 if (FileName
.empty() == true)
2843 ErrorText
= "Method gave a blank filename";
2849 // The files timestamp matches
2850 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2853 // We have to copy it into place
2854 if (FileName
!= DestFile
)
2857 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2858 Cnf
->Removable
== true)
2860 Desc
.URI
= "copy:" + FileName
;
2865 // Erase the file if it is a symlink so we can overwrite it
2867 if (lstat(DestFile
.c_str(),&St
) == 0)
2869 if (S_ISLNK(St
.st_mode
) != 0)
2870 unlink(DestFile
.c_str());
2874 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2876 _error
->PushToStack();
2877 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
2878 std::stringstream msg
;
2879 _error
->DumpErrors(msg
);
2880 _error
->RevertToStack();
2881 ErrorText
= msg
.str();
2888 // AcqFile::Failed - Failure handler /*{{{*/
2889 // ---------------------------------------------------------------------
2890 /* Here we try other sources */
2891 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2893 Item::Failed(Message
,Cnf
);
2895 // This is the retry counter
2897 Cnf
->LocalOnly
== false &&
2898 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2908 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2909 // ---------------------------------------------------------------------
2910 /* The only header we use is the last-modified header. */
2911 #if APT_PKG_ABI >= 413
2912 string
pkgAcqFile::Custom600Headers() const
2914 string
pkgAcqFile::Custom600Headers()
2918 return "\nIndex-File: true";