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
;
66 // Acquire::Item::Item - Constructor /*{{{*/
67 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
68 HashStringList
const &ExpectedHashes
,
69 pkgAcqMetaBase
*TransactionManager
)
70 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
71 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
72 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
76 if(TransactionManager
!= NULL
)
77 TransactionManager
->Add(this);
80 // Acquire::Item::~Item - Destructor /*{{{*/
81 // ---------------------------------------------------------------------
83 pkgAcquire::Item::~Item()
88 // Acquire::Item::Failed - Item failed to download /*{{{*/
89 // ---------------------------------------------------------------------
90 /* We return to an idle state if there are still other queues that could
92 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
96 ErrorText
= LookupTag(Message
,"Message");
97 UsedMirror
= LookupTag(Message
,"UsedMirror");
98 if (QueueCounter
<= 1)
100 /* This indicates that the file is not available right now but might
101 be sometime later. If we do a retry cycle then this should be
103 if (Cnf
->LocalOnly
== true &&
104 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
115 // report mirror failure back to LP if we actually use a mirror
116 string FailReason
= LookupTag(Message
, "FailReason");
117 if(FailReason
.size() != 0)
118 ReportMirrorFailure(FailReason
);
120 ReportMirrorFailure(ErrorText
);
123 // Acquire::Item::Start - Item has begun to download /*{{{*/
124 // ---------------------------------------------------------------------
125 /* Stash status and the file size. Note that setting Complete means
126 sub-phases of the acquire process such as decompresion are operating */
127 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
129 Status
= StatFetching
;
130 if (FileSize
== 0 && Complete
== false)
134 // Acquire::Item::Done - Item downloaded OK /*{{{*/
135 // ---------------------------------------------------------------------
137 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
138 pkgAcquire::MethodConfig
* /*Cnf*/)
140 // We just downloaded something..
141 string FileName
= LookupTag(Message
,"Filename");
142 UsedMirror
= LookupTag(Message
,"UsedMirror");
143 if (Complete
== false && !Local
&& FileName
== DestFile
)
146 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
152 ErrorText
= string();
153 Owner
->Dequeue(this);
156 // Acquire::Item::Rename - Rename a file /*{{{*/
157 // ---------------------------------------------------------------------
158 /* This helper function is used by a lot of item methods as their final
160 void pkgAcquire::Item::Rename(string From
,string To
)
162 if (rename(From
.c_str(),To
.c_str()) != 0)
165 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
166 From
.c_str(),To
.c_str());
172 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
174 if(FileExists(DestFile
))
175 Rename(DestFile
, DestFile
+ ".FAILED");
179 case HashSumMismatch
:
180 ErrorText
= _("Hash Sum mismatch");
181 Status
= StatAuthError
;
182 ReportMirrorFailure("HashChecksumFailure");
185 ErrorText
= _("Size mismatch");
186 Status
= StatAuthError
;
187 ReportMirrorFailure("SizeFailure");
190 ErrorText
= _("Invalid file format");
192 // do not report as usually its not the mirrors fault, but Portal/Proxy
198 // Acquire::Item::ReportMirrorFailure /*{{{*/
199 // ---------------------------------------------------------------------
200 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
202 // we only act if a mirror was used at all
203 if(UsedMirror
.empty())
206 std::cerr
<< "\nReportMirrorFailure: "
208 << " Uri: " << DescURI()
210 << FailCode
<< std::endl
;
212 const char *Args
[40];
214 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
215 "/usr/lib/apt/apt-report-mirror-failure");
216 if(!FileExists(report
))
218 Args
[i
++] = report
.c_str();
219 Args
[i
++] = UsedMirror
.c_str();
220 Args
[i
++] = DescURI().c_str();
221 Args
[i
++] = FailCode
.c_str();
223 pid_t pid
= ExecFork();
226 _error
->Error("ReportMirrorFailure Fork failed");
231 execvp(Args
[0], (char**)Args
);
232 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
235 if(!ExecWait(pid
, "report-mirror-failure"))
237 _error
->Warning("Couldn't report problem to '%s'",
238 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
242 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
243 // ---------------------------------------------------------------------
244 /* Get the DiffIndex file first and see if there are patches available
245 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
246 * patches. If anything goes wrong in that process, it will fall back to
247 * the original packages file
249 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
250 pkgAcqMetaBase
*TransactionManager
,
251 IndexTarget
const * const Target
,
252 HashStringList
const &ExpectedHashes
,
253 indexRecords
*MetaIndexParser
)
254 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
258 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
260 RealURI
= Target
->URI
;
262 Desc
.Description
= Target
->Description
+ "/DiffIndex";
263 Desc
.ShortDesc
= Target
->ShortDesc
;
264 Desc
.URI
= Target
->URI
+ ".diff/Index";
266 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
267 DestFile
+= URItoFileName(Desc
.URI
);
270 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
272 // look for the current package file
273 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
274 CurrentPackagesFile
+= URItoFileName(RealURI
);
276 // FIXME: this file:/ check is a hack to prevent fetching
277 // from local sources. this is really silly, and
278 // should be fixed cleanly as soon as possible
279 if(!FileExists(CurrentPackagesFile
) ||
280 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
282 // we don't have a pkg file or we don't want to queue
284 std::clog
<< "No index file, local or canceld by user" << std::endl
;
290 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
291 << CurrentPackagesFile
<< std::endl
;
297 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
298 // ---------------------------------------------------------------------
299 /* The only header we use is the last-modified header. */
300 string
pkgAcqDiffIndex::Custom600Headers() const
302 string Final
= _config
->FindDir("Dir::State::lists");
303 Final
+= URItoFileName(Desc
.URI
);
306 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
309 if (stat(Final
.c_str(),&Buf
) != 0)
310 return "\nIndex-File: true";
312 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
315 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
318 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
323 vector
<DiffInfo
> available_patches
;
325 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
327 if (_error
->PendingError() == true)
330 if(TF
.Step(Tags
) == true)
336 string
const tmp
= Tags
.FindS("SHA1-Current");
337 std::stringstream
ss(tmp
);
338 ss
>> ServerSha1
>> size
;
339 unsigned long const ServerSize
= atol(size
.c_str());
341 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
344 string
const local_sha1
= SHA1
.Result();
346 if(local_sha1
== ServerSha1
)
348 // we have the same sha1 as the server so we are done here
350 std::clog
<< "Package file is up-to-date" << std::endl
;
351 // list cleanup needs to know that this file as well as the already
352 // present index is ours, so we create an empty diff to save it for us
353 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
354 ExpectedHashes
, MetaIndexParser
,
355 ServerSha1
, available_patches
);
361 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
363 // check the historie and see what patches we need
364 string
const history
= Tags
.FindS("SHA1-History");
365 std::stringstream
hist(history
);
366 while(hist
>> d
.sha1
>> size
>> d
.file
)
368 // read until the first match is found
369 // from that point on, we probably need all diffs
370 if(d
.sha1
== local_sha1
)
372 else if (found
== false)
376 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
377 available_patches
.push_back(d
);
380 if (available_patches
.empty() == false)
382 // patching with too many files is rather slow compared to a fast download
383 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
384 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
387 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
388 << ") so fallback to complete download" << std::endl
;
392 // see if the patches are too big
393 found
= false; // it was true and it will be true again at the end
394 d
= *available_patches
.begin();
395 string
const firstPatch
= d
.file
;
396 unsigned long patchesSize
= 0;
397 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
398 while(patches
>> d
.sha1
>> size
>> d
.file
)
400 if (firstPatch
== d
.file
)
402 else if (found
== false)
405 patchesSize
+= atol(size
.c_str());
407 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
408 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
411 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
412 << ") so fallback to complete download" << std::endl
;
418 // we have something, queue the next diff
422 string::size_type
const last_space
= Description
.rfind(" ");
423 if(last_space
!= string::npos
)
424 Description
.erase(last_space
, Description
.size()-last_space
);
426 /* decide if we should download patches one by one or in one go:
427 The first is good if the server merges patches, but many don't so client
428 based merging can be attempt in which case the second is better.
429 "bad things" will happen if patches are merged on the server,
430 but client side merging is attempt as well */
431 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
432 if (pdiff_merge
== true)
434 // reprepro adds this flag if it has merged patches on the server
435 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
436 pdiff_merge
= (precedence
!= "merged");
439 if (pdiff_merge
== false)
441 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
443 ServerSha1
, available_patches
);
447 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
448 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
449 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
,
454 available_patches
[i
],
465 // Nothing found, report and return false
466 // Failing here is ok, if we return false later, the full
467 // IndexFile is queued
469 std::clog
<< "Can't find a patch in the index file" << std::endl
;
473 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
476 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
477 << "Falling back to normal index file acquire" << std::endl
;
479 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
486 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
487 pkgAcquire::MethodConfig
*Cnf
)
490 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
492 Item::Done(Message
, Size
, Hashes
, Cnf
);
495 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
497 // success in downloading the index
499 FinalFile
+= string(".IndexDiff");
501 std::clog
<< "Renaming: " << DestFile
<< " -> " << FinalFile
503 Rename(DestFile
,FinalFile
);
504 chmod(FinalFile
.c_str(),0644);
505 DestFile
= FinalFile
;
507 if(!ParseDiffIndex(DestFile
))
508 return Failed("", NULL
);
516 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
517 // ---------------------------------------------------------------------
518 /* The package diff is added to the queue. one object is constructed
519 * for each diff and the index
521 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
522 pkgAcqMetaBase
*TransactionManager
,
523 struct IndexTarget
const * const Target
,
524 HashStringList
const &ExpectedHashes
,
525 indexRecords
*MetaIndexParser
,
527 vector
<DiffInfo
> diffs
)
528 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
529 available_patches(diffs
), ServerSha1(ServerSha1
)
532 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
533 DestFile
+= URItoFileName(Target
->URI
);
535 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
537 RealURI
= Target
->URI
;
539 Description
= Target
->Description
;
540 Desc
.ShortDesc
= Target
->ShortDesc
;
542 if(available_patches
.empty() == true)
544 // we are done (yeah!)
550 State
= StateFetchDiff
;
555 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
558 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
559 << "Falling back to normal index file acquire" << std::endl
;
560 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
564 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
565 void pkgAcqIndexDiffs::Finish(bool allDone
)
568 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
570 << Desc
.URI
<< std::endl
;
572 // we restore the original name, this is required, otherwise
573 // the file will be cleaned
576 DestFile
= _config
->FindDir("Dir::State::lists");
577 DestFile
+= URItoFileName(RealURI
);
579 // FIXME: we want the rred stuff to use the real transactional update
580 // this is just a workaround
581 PartialFile
= DestFile
;
583 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
585 RenameOnError(HashSumMismatch
);
590 // this is for the "real" finish
595 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
600 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
607 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
610 // calc sha1 of the just patched file
611 string FinalFile
= _config
->FindDir("Dir::State::lists");
612 FinalFile
+= URItoFileName(RealURI
);
614 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
617 string local_sha1
= string(SHA1
.Result());
619 std::clog
<< "QueueNextDiff: "
620 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
622 // final file reached before all patches are applied
623 if(local_sha1
== ServerSha1
)
629 // remove all patches until the next matching patch is found
630 // this requires the Index file to be ordered
631 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
632 available_patches
.empty() == false &&
633 I
!= available_patches
.end() &&
634 I
->sha1
!= local_sha1
;
637 available_patches
.erase(I
);
640 // error checking and falling back if no patch was found
641 if(available_patches
.empty() == true)
647 // queue the right diff
648 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
649 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
650 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
651 DestFile
+= URItoFileName(RealURI
+ ".diff/" + available_patches
[0].file
);
654 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
661 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
662 pkgAcquire::MethodConfig
*Cnf
)
665 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
667 Item::Done(Message
, Size
, Hashes
, Cnf
);
670 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
672 // success in downloading a diff, enter ApplyDiff state
673 if(State
== StateFetchDiff
)
676 // rred excepts the patch as $FinalFile.ed
677 Rename(DestFile
,FinalFile
+".ed");
680 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
682 State
= StateApplyDiff
;
684 Desc
.URI
= "rred:" + FinalFile
;
691 // success in download/apply a diff, queue next (if needed)
692 if(State
== StateApplyDiff
)
694 // remove the just applied patch
695 available_patches
.erase(available_patches
.begin());
696 unlink((FinalFile
+ ".ed").c_str());
701 std::clog
<< "Moving patched file in place: " << std::endl
702 << DestFile
<< " -> " << FinalFile
<< std::endl
;
704 Rename(DestFile
,FinalFile
);
705 chmod(FinalFile
.c_str(),0644);
707 // see if there is more to download
708 if(available_patches
.empty() == false) {
709 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
710 ExpectedHashes
, MetaIndexParser
,
711 ServerSha1
, available_patches
);
718 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
719 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
720 pkgAcqMetaBase
*TransactionManager
,
721 struct IndexTarget
const * const Target
,
722 HashStringList
const &ExpectedHashes
,
723 indexRecords
*MetaIndexParser
,
724 DiffInfo
const &patch
,
725 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
726 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
727 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
730 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
731 DestFile
+= URItoFileName(Target
->URI
);
733 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
735 RealURI
= Target
->URI
;
737 Description
= Target
->Description
;
738 Desc
.ShortDesc
= Target
->ShortDesc
;
740 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
741 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
742 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
743 DestFile
+= URItoFileName(RealURI
+ ".diff/" + patch
.file
);
746 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
751 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
754 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
759 // check if we are the first to fail, otherwise we are done here
760 State
= StateDoneDiff
;
761 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
762 I
!= allPatches
->end(); ++I
)
763 if ((*I
)->State
== StateErrorDiff
)
766 // first failure means we should fallback
767 State
= StateErrorDiff
;
768 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
769 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
772 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
773 pkgAcquire::MethodConfig
*Cnf
)
776 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
778 Item::Done(Message
,Size
,Hashes
,Cnf
);
780 string
const FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
782 if (State
== StateFetchDiff
)
784 // rred expects the patch as $FinalFile.ed.$patchname.gz
785 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
787 // check if this is the last completed diff
788 State
= StateDoneDiff
;
789 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
790 I
!= allPatches
->end(); ++I
)
791 if ((*I
)->State
!= StateDoneDiff
)
794 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
798 // this is the last completed diff, so we are ready to apply now
799 State
= StateApplyDiff
;
802 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
805 Desc
.URI
= "rred:" + FinalFile
;
810 // success in download/apply all diffs, clean up
811 else if (State
== StateApplyDiff
)
813 // see if we really got the expected file
814 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
816 RenameOnError(HashSumMismatch
);
820 // move the result into place
822 std::clog
<< "Moving patched file in place: " << std::endl
823 << DestFile
<< " -> " << FinalFile
<< std::endl
;
824 Rename(DestFile
, FinalFile
);
825 chmod(FinalFile
.c_str(), 0644);
827 // otherwise lists cleanup will eat the file
828 DestFile
= FinalFile
;
829 // FIXME: make the merged rred code really transactional
830 PartialFile
= FinalFile
;
832 // ensure the ed's are gone regardless of list-cleanup
833 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
834 I
!= allPatches
->end(); ++I
)
836 std::string patch
= FinalFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
837 unlink(patch
.c_str());
843 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
847 // AcqIndex::AcqIndex - Constructor /*{{{*/
848 // ---------------------------------------------------------------------
849 /* The package file is added to the queue and a second class is
850 instantiated to fetch the revision file */
851 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
852 string URI
,string URIDesc
,string ShortDesc
,
853 HashStringList
const &ExpectedHash
)
854 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
), RealURI(URI
)
856 AutoSelectCompression();
857 Init(URI
, URIDesc
, ShortDesc
);
859 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
860 std::clog
<< "New pkgIndex with TransactionManager "
861 << TransactionManager
<< std::endl
;
864 // AcqIndex::AcqIndex - Constructor /*{{{*/
865 // ---------------------------------------------------------------------
866 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
867 pkgAcqMetaBase
*TransactionManager
,
868 IndexTarget
const *Target
,
869 HashStringList
const &ExpectedHash
,
870 indexRecords
*MetaIndexParser
)
871 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
872 MetaIndexParser
), RealURI(Target
->URI
)
874 // autoselect the compression method
875 AutoSelectCompression();
876 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
878 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
879 std::clog
<< "New pkgIndex with TransactionManager "
880 << TransactionManager
<< std::endl
;
883 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
884 // ---------------------------------------------------------------------
885 void pkgAcqIndex::AutoSelectCompression()
887 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
888 CompressionExtension
= "";
889 if (ExpectedHashes
.usable())
891 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
892 if (*t
== "uncompressed" || MetaIndexParser
->Exists(string(Target
->MetaKey
).append(".").append(*t
)) == true)
893 CompressionExtension
.append(*t
).append(" ");
897 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
898 CompressionExtension
.append(*t
).append(" ");
900 if (CompressionExtension
.empty() == false)
901 CompressionExtension
.erase(CompressionExtension
.end()-1);
903 // AcqIndex::Init - defered Constructor /*{{{*/
904 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
) {
905 Decompression
= false;
908 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
909 DestFile
+= URItoFileName(URI
);
911 std::string
const comprExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
912 if (comprExt
== "uncompressed")
916 MetaKey
= string(Target
->MetaKey
);
920 Desc
.URI
= URI
+ '.' + comprExt
;
922 MetaKey
= string(Target
->MetaKey
) + '.' + comprExt
;
928 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
930 FileSize
= Record
->Size
;
932 InitByHashIfNeeded(MetaKey
);
935 Desc
.Description
= URIDesc
;
937 Desc
.ShortDesc
= ShortDesc
;
942 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
943 // ---------------------------------------------------------------------
945 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
948 // - (maybe?) add support for by-hash into the sources.list as flag
949 // - make apt-ftparchive generate the hashes (and expire?)
950 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
951 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
952 _config
->FindB(HostKnob
, false) == true ||
953 MetaIndexParser
->GetSupportsAcquireByHash())
955 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
958 // FIXME: should we really use the best hash here? or a fixed one?
959 const HashString
*TargetHash
= Record
->Hashes
.find("");
960 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
961 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
962 Desc
.URI
= Desc
.URI
.replace(
964 Desc
.URI
.substr(trailing_slash
+1).size()+1,
968 "Fetching ByHash requested but can not find record for %s",
974 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
975 // ---------------------------------------------------------------------
976 /* The only header we use is the last-modified header. */
977 string
pkgAcqIndex::Custom600Headers() const
979 string Final
= _config
->FindDir("Dir::State::lists");
980 Final
+= URItoFileName(RealURI
);
981 if (_config
->FindB("Acquire::GzipIndexes",false))
984 string msg
= "\nIndex-File: true";
985 // FIXME: this really should use "IndexTarget::IsOptional()" but that
986 // seems to be difficult without breaking ABI
987 if (ShortDesc().find("Translation") != 0)
988 msg
+= "\nFail-Ignore: true";
990 if (stat(Final
.c_str(),&Buf
) == 0)
991 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
996 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
997 // ---------------------------------------------------------------------
999 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
1001 size_t const nextExt
= CompressionExtension
.find(' ');
1002 if (nextExt
!= std::string::npos
)
1004 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1005 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1009 // on decompression failure, remove bad versions in partial/
1010 if (Decompression
&& Erase
) {
1011 string s
= _config
->FindDir("Dir::State::lists") + "partial/";
1012 s
.append(URItoFileName(RealURI
));
1016 Item::Failed(Message
,Cnf
);
1018 /// cancel the entire transaction
1019 TransactionManager
->AbortTransaction();
1022 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1023 // ---------------------------------------------------------------------
1025 std::string
pkgAcqIndex::GetFinalFilename(std::string
const &URI
,
1026 std::string
const &compExt
)
1028 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1029 FinalFile
+= URItoFileName(URI
);
1030 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1035 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1036 // ---------------------------------------------------------------------
1038 void pkgAcqIndex::ReverifyAfterIMS()
1040 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1041 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz")
1044 // copy FinalFile into partial/ so that we check the hash again
1045 string FinalFile
= GetFinalFilename(RealURI
, compExt
);
1046 Decompression
= true;
1047 Desc
.URI
= "copy:" + FinalFile
;
1051 // AcqIndex::Done - Finished a fetch /*{{{*/
1052 // ---------------------------------------------------------------------
1053 /* This goes through a number of states.. On the initial fetch the
1054 method could possibly return an alternate filename which points
1055 to the uncompressed version of the file. If this is so the file
1056 is copied into the partial directory. In all other cases the file
1057 is decompressed with a compressed uri. */
1058 void pkgAcqIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
,
1059 pkgAcquire::MethodConfig
*Cfg
)
1061 Item::Done(Message
,Size
,Hashes
,Cfg
);
1062 std::string
const compExt
= CompressionExtension
.substr(0, CompressionExtension
.find(' '));
1064 if (Decompression
== true)
1066 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1069 RenameOnError(HashSumMismatch
);
1070 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1071 Failed(Message
, Cfg
);
1075 // FIXME: this can go away once we only ever download stuff that
1076 // has a valid hash and we never do GET based probing
1078 /* Always verify the index file for correctness (all indexes must
1079 * have a Package field) (LP: #346386) (Closes: #627642)
1081 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Extension
);
1082 // Only test for correctness if the content of the file is not empty
1087 pkgTagFile
tag(&fd
);
1089 // all our current indexes have a field 'Package' in each section
1090 if (_error
->PendingError() == true || tag
.Step(sec
) == false || sec
.Exists("Package") == false)
1092 RenameOnError(InvalidFormat
);
1093 Failed(Message
, Cfg
);
1098 // FIXME: can we void the "Erase" bool here as its very non-local?
1099 std::string CompressedFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1100 CompressedFile
+= URItoFileName(RealURI
);
1102 // Remove the compressed version.
1104 unlink(CompressedFile
.c_str());
1106 // Done, queue for rename on transaction finished
1107 PartialFile
= DestFile
;
1108 DestFile
= GetFinalFilename(RealURI
, compExt
);
1113 // FIXME: use the same method to find
1114 // check the compressed hash too
1115 if(MetaKey
!= "" && Hashes
.size() > 0)
1117 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1118 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1120 RenameOnError(HashSumMismatch
);
1121 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1122 Failed(Message
, Cfg
);
1130 // Handle the unzipd case
1131 string FileName
= LookupTag(Message
,"Alt-Filename");
1132 if (FileName
.empty() == false)
1134 Decompression
= true;
1136 DestFile
+= ".decomp";
1137 Desc
.URI
= "copy:" + FileName
;
1143 FileName
= LookupTag(Message
,"Filename");
1144 if (FileName
.empty() == true)
1147 ErrorText
= "Method gave a blank filename";
1150 if (FileName
== DestFile
)
1155 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1156 // file when its doing the indexcopy
1157 if (RealURI
.substr(0,6) == "cdrom:" &&
1158 StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1161 // The files timestamp matches, for non-local URLs reverify the local
1162 // file, for local file, uncompress again to ensure the hashsum is still
1163 // matching the Release file
1164 if (!Local
&& StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1171 // If we enable compressed indexes, queue for hash verification
1172 if (_config
->FindB("Acquire::GzipIndexes",false) && compExt
== "gz" && !Local
)
1174 DestFile
= _config
->FindDir("Dir::State::lists");
1175 DestFile
+= URItoFileName(RealURI
) + ".gz";
1177 Decompression
= true;
1178 Desc
.URI
= "copy:" + FileName
;
1184 // get the binary name for your used compression type
1185 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(compExt
),"");
1186 if(decompProg
.empty() == false);
1187 else if(compExt
== "uncompressed")
1188 decompProg
= "copy";
1190 _error
->Error("Unsupported extension: %s", compExt
.c_str());
1194 Decompression
= true;
1195 DestFile
+= ".decomp";
1196 Desc
.URI
= decompProg
+ ":" + FileName
;
1199 // FIXME: this points to a c++ string that goes out of scope
1200 Mode
= decompProg
.c_str();
1203 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1204 // ---------------------------------------------------------------------
1205 /* The Translation file is added to the queue */
1206 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1207 string URI
,string URIDesc
,string ShortDesc
)
1208 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1212 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1213 pkgAcqMetaBase
*TransactionManager
,
1214 IndexTarget
const * const Target
,
1215 HashStringList
const &ExpectedHashes
,
1216 indexRecords
*MetaIndexParser
)
1217 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1219 // load the filesize
1220 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1222 FileSize
= Record
->Size
;
1225 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1226 // ---------------------------------------------------------------------
1227 string
pkgAcqIndexTrans::Custom600Headers() const
1229 string Final
= _config
->FindDir("Dir::State::lists");
1230 Final
+= URItoFileName(RealURI
);
1232 if (_config
->FindB("Acquire::GzipIndexes",false))
1236 if (stat(Final
.c_str(),&Buf
) != 0)
1237 return "\nFail-Ignore: true\nIndex-File: true";
1238 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1241 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1242 // ---------------------------------------------------------------------
1244 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1246 size_t const nextExt
= CompressionExtension
.find(' ');
1247 if (nextExt
!= std::string::npos
)
1249 CompressionExtension
= CompressionExtension
.substr(nextExt
+1);
1250 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1255 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1256 if (Cnf
->LocalOnly
== true ||
1257 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1266 Item::Failed(Message
,Cnf
);
1270 void pkgAcqMetaBase::Add(Item
*I
)
1272 Transaction
.push_back(I
);
1275 void pkgAcqMetaBase::AbortTransaction()
1277 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1278 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1280 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1281 I
!= Transaction
.end(); ++I
)
1283 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1284 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1285 // the transaction will abort, so stop anything that is idle
1286 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1287 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1291 bool pkgAcqMetaBase::TransactionHasError()
1293 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1294 I
!= Transaction
.end(); ++I
)
1295 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1296 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1301 // Acquire::CommitTransaction - Commit a transaction /*{{{*/
1302 void pkgAcqMetaBase::CommitTransaction()
1304 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1305 std::clog
<< "CommitTransaction: " << this << std::endl
;
1307 // move new files into place *and* remove files that are not
1308 // part of the transaction but are still on disk
1309 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1310 I
!= Transaction
.end(); ++I
)
1312 if((*I
)->PartialFile
!= "")
1314 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1316 << (*I
)->PartialFile
<< " -> "
1317 << (*I
)->DestFile
<< std::endl
;
1318 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1319 chmod((*I
)->DestFile
.c_str(),0644);
1321 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1323 << (*I
)->DestFile
<< std::endl
;
1324 unlink((*I
)->DestFile
.c_str());
1326 // mark that this transaction is finished
1327 (*I
)->TransactionManager
= 0;
1332 bool pkgAcqMetaBase::GenerateAuthWarning(const std::string
&RealURI
,
1333 const std::string
&Message
)
1335 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1337 if(FileExists(Final
))
1339 Status
= StatTransientNetworkError
;
1340 _error
->Warning(_("An error occurred during the signature "
1341 "verification. The repository is not updated "
1342 "and the previous index files will be used. "
1343 "GPG error: %s: %s\n"),
1344 Desc
.Description
.c_str(),
1345 LookupTag(Message
,"Message").c_str());
1346 RunScripts("APT::Update::Auth-Failure");
1348 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1349 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1350 _error
->Error(_("GPG error: %s: %s"),
1351 Desc
.Description
.c_str(),
1352 LookupTag(Message
,"Message").c_str());
1356 _error
->Warning(_("GPG error: %s: %s"),
1357 Desc
.Description
.c_str(),
1358 LookupTag(Message
,"Message").c_str());
1360 // gpgv method failed
1361 ReportMirrorFailure("GPGFailure");
1367 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
, /*{{{*/
1368 pkgAcqMetaBase
*TransactionManager
,
1369 string URI
,string URIDesc
,string ShortDesc
,
1370 string MetaIndexFile
,
1371 const vector
<IndexTarget
*>* IndexTargets
,
1372 indexRecords
* MetaIndexParser
) :
1373 pkgAcqMetaBase(Owner
, HashStringList(), TransactionManager
), RealURI(URI
),
1374 MetaIndexParser(MetaIndexParser
), MetaIndexFile(MetaIndexFile
),
1375 IndexTargets(IndexTargets
), AuthPass(false), IMSHit(false)
1377 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1378 DestFile
+= URItoFileName(URI
);
1380 // remove any partial downloaded sig-file in partial/.
1381 // it may confuse proxies and is too small to warrant a
1382 // partial download anyway
1383 unlink(DestFile
.c_str());
1385 // set the TransactionManager
1386 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1387 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1388 << TransactionManager
<< std::endl
;
1391 Desc
.Description
= URIDesc
;
1393 Desc
.ShortDesc
= ShortDesc
;
1399 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1403 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1404 // ---------------------------------------------------------------------
1405 /* The only header we use is the last-modified header. */
1406 string
pkgAcqMetaSig::Custom600Headers() const
1408 string FinalFile
= _config
->FindDir("Dir::State::lists");
1409 FinalFile
+= URItoFileName(RealURI
);
1412 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1413 return "\nIndex-File: true";
1415 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1418 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
,
1419 pkgAcquire::MethodConfig
*Cfg
)
1421 Item::Done(Message
, Size
, Hashes
, Cfg
);
1423 string FileName
= LookupTag(Message
,"Filename");
1424 if (FileName
.empty() == true)
1427 ErrorText
= "Method gave a blank filename";
1431 if (FileName
!= DestFile
)
1433 // We have to copy it into place
1435 Desc
.URI
= "copy:" + FileName
;
1440 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1443 // adjust paths if its a ims-hit
1446 string FinalFile
= _config
->FindDir("Dir::State::lists");
1447 FinalFile
+= URItoFileName(RealURI
);
1449 DestFile
= PartialFile
= FinalFile
;
1453 if(AuthPass
== false)
1456 Desc
.URI
= "gpgv:" + DestFile
;
1457 DestFile
= MetaIndexFile
;
1462 // queue to copy the file in place if it was not a ims hit, on ims
1463 // hit the file is already at the right place
1466 PartialFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1467 PartialFile
+= URItoFileName(RealURI
);
1469 DestFile
= _config
->FindDir("Dir::State::lists");
1470 DestFile
+= URItoFileName(RealURI
);
1477 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1479 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1481 // this ensures that any file in the lists/ dir is removed by the
1483 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1484 DestFile
+= URItoFileName(RealURI
);
1487 // FIXME: duplicated code from pkgAcqMetaIndex
1488 if (AuthPass
== true)
1490 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
1495 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1496 if (Cnf
->LocalOnly
== true ||
1497 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1505 Item::Failed(Message
,Cnf
);
1508 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1509 pkgAcqMetaBase
*TransactionManager
,
1510 string URI
,string URIDesc
,string ShortDesc
,
1511 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1512 const vector
<IndexTarget
*>* IndexTargets
,
1513 indexRecords
* MetaIndexParser
) :
1514 pkgAcqMetaBase(Owner
, HashStringList(), TransactionManager
), RealURI(URI
), IndexTargets(IndexTargets
),
1515 MetaIndexParser(MetaIndexParser
), AuthPass(false), IMSHit(false),
1516 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1517 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1519 if(TransactionManager
== NULL
)
1521 this->TransactionManager
= this;
1522 this->TransactionManager
->Add(this);
1525 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1526 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1527 << this->TransactionManager
<< std::endl
;
1530 Init(URIDesc
, ShortDesc
);
1533 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1534 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1536 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1537 DestFile
+= URItoFileName(RealURI
);
1540 Desc
.Description
= URIDesc
;
1542 Desc
.ShortDesc
= ShortDesc
;
1545 // we expect more item
1546 ExpectedAdditionalItems
= IndexTargets
->size();
1549 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1550 // ---------------------------------------------------------------------
1551 /* The only header we use is the last-modified header. */
1552 string
pkgAcqMetaIndex::Custom600Headers() const
1554 string Final
= _config
->FindDir("Dir::State::lists");
1555 Final
+= URItoFileName(RealURI
);
1558 if (stat(Final
.c_str(),&Buf
) != 0)
1559 return "\nIndex-File: true";
1561 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1564 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1565 pkgAcquire::MethodConfig
*Cfg
)
1567 Item::Done(Message
,Size
,Hashes
,Cfg
);
1569 // MetaIndexes are done in two passes: one to download the
1570 // metaindex with an appropriate method, and a second to verify it
1571 // with the gpgv method
1573 if (AuthPass
== true)
1577 // all cool, move Release file into place
1582 RetrievalDone(Message
);
1584 // Still more retrieving to do
1589 // load indexes, the signature will downloaded afterwards
1590 MetaIndexParser
->Load(DestFile
);
1595 // There was a signature file, so pass it to gpgv for
1597 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1598 std::cerr
<< "Metaindex acquired, queueing gpg verification ("
1599 << SigFile
<< "," << DestFile
<< ")\n";
1601 Desc
.URI
= "gpgv:" + SigFile
;
1608 if (Complete
== true)
1610 string FinalFile
= _config
->FindDir("Dir::State::lists");
1611 FinalFile
+= URItoFileName(RealURI
);
1612 if (SigFile
== DestFile
)
1613 SigFile
= FinalFile
;
1614 // queue for copy in place
1615 PartialFile
= DestFile
;
1616 DestFile
= FinalFile
;
1620 void pkgAcqMetaIndex::RetrievalDone(string Message
) /*{{{*/
1622 // We have just finished downloading a Release file (it is not
1625 string FileName
= LookupTag(Message
,"Filename");
1626 if (FileName
.empty() == true)
1629 ErrorText
= "Method gave a blank filename";
1633 if (FileName
!= DestFile
)
1636 Desc
.URI
= "copy:" + FileName
;
1641 // make sure to verify against the right file on I-M-S hit
1642 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1645 string FinalFile
= _config
->FindDir("Dir::State::lists");
1646 FinalFile
+= URItoFileName(RealURI
);
1647 if (SigFile
== DestFile
)
1649 SigFile
= FinalFile
;
1651 // constructor of pkgAcqMetaClearSig moved it out of the way,
1652 // now move it back in on IMS hit for the 'old' file
1653 string
const OldClearSig
= DestFile
+ ".reverify";
1654 if (RealFileExists(OldClearSig
) == true)
1655 Rename(OldClearSig
, FinalFile
);
1658 DestFile
= FinalFile
;
1661 // queue a signature
1662 if(SigFile
!= DestFile
)
1663 new pkgAcqMetaSig(Owner
, TransactionManager
,
1664 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1665 MetaIndexSigShortDesc
, DestFile
, IndexTargets
,
1671 void pkgAcqMetaIndex::AuthDone(string Message
) /*{{{*/
1673 // At this point, the gpgv method has succeeded, so there is a
1674 // valid signature from a key in the trusted keyring. We
1675 // perform additional verification of its contents, and use them
1676 // to verify the indexes we are about to download
1678 if (!MetaIndexParser
->Load(DestFile
))
1680 Status
= StatAuthError
;
1681 ErrorText
= MetaIndexParser
->ErrorText
;
1685 if (!VerifyVendor(Message
))
1690 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1691 std::cerr
<< "Signature verification succeeded: "
1692 << DestFile
<< std::endl
;
1694 // do not trust any previously unverified content that we may have
1695 string LastGoodSigFile
= _config
->FindDir("Dir::State::lists").append("partial/").append(URItoFileName(RealURI
));
1696 if (DestFile
!= SigFile
)
1697 LastGoodSigFile
.append(".gpg");
1698 LastGoodSigFile
.append(".reverify");
1699 if(IMSHit
== false && RealFileExists(LastGoodSigFile
) == false)
1701 for (vector
<struct IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1702 Target
!= IndexTargets
->end();
1705 // remove old indexes
1706 std::string index
= _config
->FindDir("Dir::State::lists") +
1707 URItoFileName((*Target
)->URI
);
1708 unlink(index
.c_str());
1709 // and also old gzipindexes
1711 unlink(index
.c_str());
1716 // Download further indexes with verification
1720 // is it a clearsigned MetaIndex file?
1721 if (DestFile
== SigFile
)
1724 // Done, move signature file into position
1725 string VerifiedSigFile
= _config
->FindDir("Dir::State::lists") +
1726 URItoFileName(RealURI
) + ".gpg";
1727 Rename(SigFile
,VerifiedSigFile
);
1728 chmod(VerifiedSigFile
.c_str(),0644);
1732 void pkgAcqMetaIndex::QueueIndexes(bool verify
) /*{{{*/
1734 bool transInRelease
= false;
1736 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1737 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1738 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1739 if (k
->find("Translation-") != std::string::npos
)
1741 transInRelease
= true;
1746 // at this point the real Items are loaded in the fetcher
1747 ExpectedAdditionalItems
= 0;
1748 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1749 Target
!= IndexTargets
->end();
1752 HashStringList ExpectedIndexHashes
;
1753 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1754 bool compressedAvailable
= false;
1757 if ((*Target
)->IsOptional() == true)
1759 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1760 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1761 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1763 compressedAvailable
= true;
1767 else if (verify
== true)
1769 Status
= StatAuthError
;
1770 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1776 ExpectedIndexHashes
= Record
->Hashes
;
1777 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1779 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1780 << "Expected Hash:" << std::endl
;
1781 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1782 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1783 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1785 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1787 Status
= StatAuthError
;
1788 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1793 if ((*Target
)->IsOptional() == true)
1795 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1797 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1798 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1799 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1801 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1806 /* Queue Packages file (either diff or full packages files, depending
1807 on the users option) - we also check if the PDiff Index file is listed
1808 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1809 instead, but passing the required info to it is to much hassle */
1810 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1811 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1812 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1814 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1818 bool pkgAcqMetaIndex::VerifyVendor(string Message
) /*{{{*/
1820 string::size_type pos
;
1822 // check for missing sigs (that where not fatal because otherwise we had
1825 string msg
= _("There is no public key available for the "
1826 "following key IDs:\n");
1827 pos
= Message
.find("NO_PUBKEY ");
1828 if (pos
!= std::string::npos
)
1830 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1831 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1832 missingkeys
+= (Fingerprint
);
1834 if(!missingkeys
.empty())
1835 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1837 string Transformed
= MetaIndexParser
->GetExpectedDist();
1839 if (Transformed
== "../project/experimental")
1841 Transformed
= "experimental";
1844 pos
= Transformed
.rfind('/');
1845 if (pos
!= string::npos
)
1847 Transformed
= Transformed
.substr(0, pos
);
1850 if (Transformed
== ".")
1855 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1856 MetaIndexParser
->GetValidUntil() > 0) {
1857 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1858 if (invalid_since
> 0)
1859 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1860 // the time since then the file is invalid - formated in the same way as in
1861 // the download progress display (e.g. 7d 3h 42min 1s)
1862 return _error
->Error(
1863 _("Release file for %s is expired (invalid since %s). "
1864 "Updates for this repository will not be applied."),
1865 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1868 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1870 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1871 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1872 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1875 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1877 // This might become fatal one day
1878 // Status = StatAuthError;
1879 // ErrorText = "Conflicting distribution; expected "
1880 // + MetaIndexParser->GetExpectedDist() + " but got "
1881 // + MetaIndexParser->GetDist();
1883 if (!Transformed
.empty())
1885 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1886 Desc
.Description
.c_str(),
1887 Transformed
.c_str(),
1888 MetaIndexParser
->GetDist().c_str());
1895 // pkgAcqMetaIndex::Failed - no Release file present or no signature file present /*{{{*/
1896 // ---------------------------------------------------------------------
1898 void pkgAcqMetaIndex::Failed(string Message
,
1899 pkgAcquire::MethodConfig
* /*Cnf*/)
1901 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1903 if (AuthPass
== true)
1905 bool Stop
= GenerateAuthWarning(RealURI
, Message
);
1910 /* Always move the meta index, even if gpgv failed. This ensures
1911 * that PackageFile objects are correctly filled in */
1912 if (FileExists(DestFile
)) {
1913 string FinalFile
= _config
->FindDir("Dir::State::lists");
1914 FinalFile
+= URItoFileName(RealURI
);
1915 /* InRelease files become Release files, otherwise
1916 * they would be considered as trusted later on */
1917 if (SigFile
== DestFile
) {
1918 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
1920 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
1922 SigFile
= FinalFile
;
1925 // Done, queue for rename on transaction finished
1926 PartialFile
= DestFile
;
1927 DestFile
= FinalFile
;
1930 // No Release file was present, or verification failed, so fall
1931 // back to queueing Packages files without verification
1932 QueueIndexes(false);
1936 void pkgAcqMetaIndex::Finished()
1938 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1939 std::clog
<< "Finished: " << DestFile
<<std::endl
;
1940 if(TransactionManager
!= NULL
&&
1941 TransactionManager
->TransactionHasError() == false)
1942 TransactionManager
->CommitTransaction();
1946 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
1947 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
1948 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
1949 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
1950 const vector
<IndexTarget
*>* IndexTargets
,
1951 indexRecords
* MetaIndexParser
) :
1952 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
1953 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
1954 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
1958 // index targets + (worst case:) Release/Release.gpg
1959 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
1962 // keep the old InRelease around in case of transistent network errors
1963 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1964 if (RealFileExists(Final
) == true)
1966 string
const LastGoodSig
= DestFile
+ ".reverify";
1967 Rename(Final
,LastGoodSig
);
1972 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
1975 // if the file was never queued undo file-changes done in the constructor
1976 if (QueueCounter
== 1 && Status
== StatIdle
&& FileSize
== 0 && Complete
== false)
1978 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1979 string
const LastGoodSig
= DestFile
+ ".reverify";
1980 if (RealFileExists(Final
) == false && RealFileExists(LastGoodSig
) == true)
1981 Rename(LastGoodSig
, Final
);
1986 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
1987 // ---------------------------------------------------------------------
1988 // FIXME: this can go away once the InRelease file is used widely
1989 string
pkgAcqMetaClearSig::Custom600Headers() const
1991 string Final
= _config
->FindDir("Dir::State::lists");
1992 Final
+= URItoFileName(RealURI
);
1995 if (stat(Final
.c_str(),&Buf
) != 0)
1997 if (stat(Final
.c_str(),&Buf
) != 0)
1998 return "\nIndex-File: true\nFail-Ignore: true\n";
2001 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2004 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2005 // ---------------------------------------------------------------------
2006 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2007 HashStringList
const &Hashes
,
2008 pkgAcquire::MethodConfig
*Cnf
)
2010 // if we expect a ClearTextSignature (InRelase), ensure that
2011 // this is what we get and if not fail to queue a
2012 // Release/Release.gpg, see #346386
2013 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2015 pkgAcquire::Item::Failed(Message
, Cnf
);
2016 ErrorText
= _("Does not start with a cleartext signature");
2019 pkgAcqMetaIndex::Done(Message
, Size
, Hashes
, Cnf
);
2022 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2024 // we failed, we will not get additional items from this method
2025 ExpectedAdditionalItems
= 0;
2027 if (AuthPass
== false)
2029 // Queue the 'old' InRelease file for removal if we try Release.gpg
2030 // as otherwise the file will stay around and gives a false-auth
2031 // impression (CVE-2012-0214)
2032 string FinalFile
= _config
->FindDir("Dir::State::lists");
2033 FinalFile
.append(URItoFileName(RealURI
));
2035 DestFile
= FinalFile
;
2037 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2038 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2039 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2040 IndexTargets
, MetaIndexParser
);
2041 if (Cnf
->LocalOnly
== true ||
2042 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2046 pkgAcqMetaIndex::Failed(Message
, Cnf
);
2049 // AcqArchive::AcqArchive - Constructor /*{{{*/
2050 // ---------------------------------------------------------------------
2051 /* This just sets up the initial fetch environment and queues the first
2053 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2054 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2055 string
&StoreFilename
) :
2056 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2057 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2060 Retries
= _config
->FindI("Acquire::Retries",0);
2062 if (Version
.Arch() == 0)
2064 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2065 "This might mean you need to manually fix this package. "
2066 "(due to missing arch)"),
2067 Version
.ParentPkg().FullName().c_str());
2071 /* We need to find a filename to determine the extension. We make the
2072 assumption here that all the available sources for this version share
2073 the same extension.. */
2074 // Skip not source sources, they do not have file fields.
2075 for (; Vf
.end() == false; ++Vf
)
2077 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2082 // Does not really matter here.. we are going to fail out below
2083 if (Vf
.end() != true)
2085 // If this fails to get a file name we will bomb out below.
2086 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2087 if (_error
->PendingError() == true)
2090 // Generate the final file name as: package_version_arch.foo
2091 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2092 QuoteString(Version
.VerStr(),"_:") + '_' +
2093 QuoteString(Version
.Arch(),"_:.") +
2094 "." + flExtension(Parse
.FileName());
2097 // check if we have one trusted source for the package. if so, switch
2098 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2099 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2100 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2101 bool seenUntrusted
= false;
2102 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2104 pkgIndexFile
*Index
;
2105 if (Sources
->FindIndex(i
.File(),Index
) == false)
2108 if (debugAuth
== true)
2109 std::cerr
<< "Checking index: " << Index
->Describe()
2110 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2112 if (Index
->IsTrusted() == true)
2115 if (allowUnauth
== false)
2119 seenUntrusted
= true;
2122 // "allow-unauthenticated" restores apts old fetching behaviour
2123 // that means that e.g. unauthenticated file:// uris are higher
2124 // priority than authenticated http:// uris
2125 if (allowUnauth
== true && seenUntrusted
== true)
2129 if (QueueNext() == false && _error
->PendingError() == false)
2130 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2131 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2134 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2135 // ---------------------------------------------------------------------
2136 /* This queues the next available file version for download. It checks if
2137 the archive is already available in the cache and stashs the MD5 for
2139 bool pkgAcqArchive::QueueNext()
2141 for (; Vf
.end() == false; ++Vf
)
2143 // Ignore not source sources
2144 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2147 // Try to cross match against the source list
2148 pkgIndexFile
*Index
;
2149 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2152 // only try to get a trusted package from another source if that source
2154 if(Trusted
&& !Index
->IsTrusted())
2157 // Grab the text package record
2158 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2159 if (_error
->PendingError() == true)
2162 string PkgFile
= Parse
.FileName();
2163 ExpectedHashes
= Parse
.Hashes();
2165 if (PkgFile
.empty() == true)
2166 return _error
->Error(_("The package index files are corrupted. No Filename: "
2167 "field for package %s."),
2168 Version
.ParentPkg().Name());
2170 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2171 Desc
.Description
= Index
->ArchiveInfo(Version
);
2173 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2175 // See if we already have the file. (Legacy filenames)
2176 FileSize
= Version
->Size
;
2177 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2179 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2181 // Make sure the size matches
2182 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2187 StoreFilename
= DestFile
= FinalFile
;
2191 /* Hmm, we have a file and its size does not match, this means it is
2192 an old style mismatched arch */
2193 unlink(FinalFile
.c_str());
2196 // Check it again using the new style output filenames
2197 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2198 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2200 // Make sure the size matches
2201 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2206 StoreFilename
= DestFile
= FinalFile
;
2210 /* Hmm, we have a file and its size does not match, this shouldn't
2212 unlink(FinalFile
.c_str());
2215 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2217 // Check the destination file
2218 if (stat(DestFile
.c_str(),&Buf
) == 0)
2220 // Hmm, the partial file is too big, erase it
2221 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2222 unlink(DestFile
.c_str());
2224 PartialSize
= Buf
.st_size
;
2227 // Disables download of archives - useful if no real installation follows,
2228 // e.g. if we are just interested in proposed installation order
2229 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2234 StoreFilename
= DestFile
= FinalFile
;
2248 // AcqArchive::Done - Finished fetching /*{{{*/
2249 // ---------------------------------------------------------------------
2251 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2252 pkgAcquire::MethodConfig
*Cfg
)
2254 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2257 if (Size
!= Version
->Size
)
2259 RenameOnError(SizeMismatch
);
2263 // FIXME: could this empty() check impose *any* sort of security issue?
2264 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2266 RenameOnError(HashSumMismatch
);
2267 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2271 // Grab the output filename
2272 string FileName
= LookupTag(Message
,"Filename");
2273 if (FileName
.empty() == true)
2276 ErrorText
= "Method gave a blank filename";
2282 // Reference filename
2283 if (FileName
!= DestFile
)
2285 StoreFilename
= DestFile
= FileName
;
2290 // Done, move it into position
2291 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2292 FinalFile
+= flNotDir(StoreFilename
);
2293 Rename(DestFile
,FinalFile
);
2295 StoreFilename
= DestFile
= FinalFile
;
2299 // AcqArchive::Failed - Failure handler /*{{{*/
2300 // ---------------------------------------------------------------------
2301 /* Here we try other sources */
2302 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2304 ErrorText
= LookupTag(Message
,"Message");
2306 /* We don't really want to retry on failed media swaps, this prevents
2307 that. An interesting observation is that permanent failures are not
2309 if (Cnf
->Removable
== true &&
2310 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2312 // Vf = Version.FileList();
2313 while (Vf
.end() == false) ++Vf
;
2314 StoreFilename
= string();
2315 Item::Failed(Message
,Cnf
);
2319 if (QueueNext() == false)
2321 // This is the retry counter
2323 Cnf
->LocalOnly
== false &&
2324 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2327 Vf
= Version
.FileList();
2328 if (QueueNext() == true)
2332 StoreFilename
= string();
2333 Item::Failed(Message
,Cnf
);
2337 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2338 // ---------------------------------------------------------------------
2339 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2344 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2345 // ---------------------------------------------------------------------
2347 void pkgAcqArchive::Finished()
2349 if (Status
== pkgAcquire::Item::StatDone
&&
2352 StoreFilename
= string();
2355 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2356 // ---------------------------------------------------------------------
2357 /* The file is added to the queue */
2358 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2359 unsigned long long Size
,string Dsc
,string ShortDesc
,
2360 const string
&DestDir
, const string
&DestFilename
,
2362 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2364 Retries
= _config
->FindI("Acquire::Retries",0);
2366 if(!DestFilename
.empty())
2367 DestFile
= DestFilename
;
2368 else if(!DestDir
.empty())
2369 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2371 DestFile
= flNotDir(URI
);
2375 Desc
.Description
= Dsc
;
2378 // Set the short description to the archive component
2379 Desc
.ShortDesc
= ShortDesc
;
2381 // Get the transfer sizes
2384 if (stat(DestFile
.c_str(),&Buf
) == 0)
2386 // Hmm, the partial file is too big, erase it
2387 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2388 unlink(DestFile
.c_str());
2390 PartialSize
= Buf
.st_size
;
2396 // AcqFile::Done - Item downloaded OK /*{{{*/
2397 // ---------------------------------------------------------------------
2399 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2400 pkgAcquire::MethodConfig
*Cnf
)
2402 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2405 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2407 RenameOnError(HashSumMismatch
);
2408 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2412 string FileName
= LookupTag(Message
,"Filename");
2413 if (FileName
.empty() == true)
2416 ErrorText
= "Method gave a blank filename";
2422 // The files timestamp matches
2423 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2426 // We have to copy it into place
2427 if (FileName
!= DestFile
)
2430 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2431 Cnf
->Removable
== true)
2433 Desc
.URI
= "copy:" + FileName
;
2438 // Erase the file if it is a symlink so we can overwrite it
2440 if (lstat(DestFile
.c_str(),&St
) == 0)
2442 if (S_ISLNK(St
.st_mode
) != 0)
2443 unlink(DestFile
.c_str());
2447 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2449 ErrorText
= "Link to " + DestFile
+ " failure ";
2456 // AcqFile::Failed - Failure handler /*{{{*/
2457 // ---------------------------------------------------------------------
2458 /* Here we try other sources */
2459 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2461 ErrorText
= LookupTag(Message
,"Message");
2463 // This is the retry counter
2465 Cnf
->LocalOnly
== false &&
2466 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2473 Item::Failed(Message
,Cnf
);
2476 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2477 // ---------------------------------------------------------------------
2478 /* The only header we use is the last-modified header. */
2479 string
pkgAcqFile::Custom600Headers() const
2482 return "\nIndex-File: true";