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>
47 #include <sys/types.h>
56 static void printHashSumComparision(std::string
const &URI
, HashStringList
const &Expected
, HashStringList
const &Actual
) /*{{{*/
58 if (_config
->FindB("Debug::Acquire::HashSumMismatch", false) == false)
60 std::cerr
<< std::endl
<< URI
<< ":" << std::endl
<< " Expected Hash: " << std::endl
;
61 for (HashStringList::const_iterator hs
= Expected
.begin(); hs
!= Expected
.end(); ++hs
)
62 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
63 std::cerr
<< " Actual Hash: " << std::endl
;
64 for (HashStringList::const_iterator hs
= Actual
.begin(); hs
!= Actual
.end(); ++hs
)
65 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
68 static void changeOwnerAndPermissionOfFile(char const * const requester
, char const * const file
, char const * const user
, char const * const group
, mode_t
const mode
)
70 // ensure the file is owned by root and has good permissions
71 struct passwd
const * const pw
= getpwnam(user
);
72 struct group
const * const gr
= getgrnam(group
);
73 if (getuid() == 0) // if we aren't root, we can't chown, so don't try it
75 if (pw
!= NULL
&& gr
!= NULL
&& chown(file
, pw
->pw_uid
, gr
->gr_gid
) != 0)
76 _error
->WarningE(requester
, "chown to %s:%s of file %s failed", user
, group
, file
);
78 if (chmod(file
, mode
) != 0)
79 _error
->WarningE(requester
, "chmod 0%o of file %s failed", mode
, file
);
81 static std::string
preparePartialFile(std::string
const &file
)
83 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
87 static std::string
preparePartialFileFromURI(std::string
const &uri
)
89 return preparePartialFile(URItoFileName(uri
));
93 // Acquire::Item::Item - Constructor /*{{{*/
95 #pragma GCC diagnostic push
96 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
98 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
99 HashStringList
const &ExpectedHashes
,
100 pkgAcqMetaBase
*TransactionManager
)
101 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
102 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
103 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
107 if(TransactionManager
!= NULL
)
108 TransactionManager
->Add(this);
111 #pragma GCC diagnostic pop
114 // Acquire::Item::~Item - Destructor /*{{{*/
115 // ---------------------------------------------------------------------
117 pkgAcquire::Item::~Item()
122 // Acquire::Item::Failed - Item failed to download /*{{{*/
123 // ---------------------------------------------------------------------
124 /* We return to an idle state if there are still other queues that could
126 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
130 ErrorText
= LookupTag(Message
,"Message");
131 UsedMirror
= LookupTag(Message
,"UsedMirror");
132 if (QueueCounter
<= 1)
134 /* This indicates that the file is not available right now but might
135 be sometime later. If we do a retry cycle then this should be
137 if (Cnf
->LocalOnly
== true &&
138 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
149 // report mirror failure back to LP if we actually use a mirror
150 string FailReason
= LookupTag(Message
, "FailReason");
151 if(FailReason
.size() != 0)
152 ReportMirrorFailure(FailReason
);
154 ReportMirrorFailure(ErrorText
);
157 // Acquire::Item::Start - Item has begun to download /*{{{*/
158 // ---------------------------------------------------------------------
159 /* Stash status and the file size. Note that setting Complete means
160 sub-phases of the acquire process such as decompresion are operating */
161 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
163 Status
= StatFetching
;
164 if (FileSize
== 0 && Complete
== false)
168 // Acquire::Item::Done - Item downloaded OK /*{{{*/
169 // ---------------------------------------------------------------------
171 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
172 pkgAcquire::MethodConfig
* /*Cnf*/)
174 // We just downloaded something..
175 string FileName
= LookupTag(Message
,"Filename");
176 UsedMirror
= LookupTag(Message
,"UsedMirror");
177 if (Complete
== false && !Local
&& FileName
== DestFile
)
180 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
186 ErrorText
= string();
187 Owner
->Dequeue(this);
190 // Acquire::Item::Rename - Rename a file /*{{{*/
191 // ---------------------------------------------------------------------
192 /* This helper function is used by a lot of item methods as their final
194 bool pkgAcquire::Item::Rename(string From
,string To
)
196 if (rename(From
.c_str(),To
.c_str()) != 0)
199 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
200 From
.c_str(),To
.c_str());
209 void pkgAcquire::Item::QueueURI(ItemDesc
&Item
)
211 if (access(DestFile
.c_str(), R_OK
) == 0)
213 changeOwnerAndPermissionOfFile("preparePartialFile", DestFile
.c_str(), "_apt", "root", 0600);
214 std::cerr
<< "QUEUE ITEM: " << DestFile
<< std::endl
;
216 Owner
->Enqueue(Item
);
218 void pkgAcquire::Item::Dequeue()
220 Owner
->Dequeue(this);
223 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
225 if(FileExists(DestFile
))
226 Rename(DestFile
, DestFile
+ ".FAILED");
230 case HashSumMismatch
:
231 ErrorText
= _("Hash Sum mismatch");
232 Status
= StatAuthError
;
233 ReportMirrorFailure("HashChecksumFailure");
236 ErrorText
= _("Size mismatch");
237 Status
= StatAuthError
;
238 ReportMirrorFailure("SizeFailure");
241 ErrorText
= _("Invalid file format");
243 // do not report as usually its not the mirrors fault, but Portal/Proxy
246 ErrorText
= _("Signature error");
250 ErrorText
= _("Does not start with a cleartext signature");
257 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
259 ActiveSubprocess
= subprocess
;
261 #pragma GCC diagnostic push
262 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
264 Mode
= ActiveSubprocess
.c_str();
266 #pragma GCC diagnostic pop
270 // Acquire::Item::ReportMirrorFailure /*{{{*/
271 // ---------------------------------------------------------------------
272 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
274 // we only act if a mirror was used at all
275 if(UsedMirror
.empty())
278 std::cerr
<< "\nReportMirrorFailure: "
280 << " Uri: " << DescURI()
282 << FailCode
<< std::endl
;
284 const char *Args
[40];
286 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
287 "/usr/lib/apt/apt-report-mirror-failure");
288 if(!FileExists(report
))
290 Args
[i
++] = report
.c_str();
291 Args
[i
++] = UsedMirror
.c_str();
292 Args
[i
++] = DescURI().c_str();
293 Args
[i
++] = FailCode
.c_str();
295 pid_t pid
= ExecFork();
298 _error
->Error("ReportMirrorFailure Fork failed");
303 execvp(Args
[0], (char**)Args
);
304 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
307 if(!ExecWait(pid
, "report-mirror-failure"))
309 _error
->Warning("Couldn't report problem to '%s'",
310 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
314 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
315 // ---------------------------------------------------------------------
316 /* Get the DiffIndex file first and see if there are patches available
317 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
318 * patches. If anything goes wrong in that process, it will fall back to
319 * the original packages file
321 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
322 pkgAcqMetaBase
*TransactionManager
,
323 IndexTarget
const * const Target
,
324 HashStringList
const &ExpectedHashes
,
325 indexRecords
*MetaIndexParser
)
326 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
327 MetaIndexParser
), PackagesFileReadyInPartial(false)
330 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
332 RealURI
= Target
->URI
;
334 Desc
.Description
= Target
->Description
+ "/DiffIndex";
335 Desc
.ShortDesc
= Target
->ShortDesc
;
336 Desc
.URI
= Target
->URI
+ ".diff/Index";
338 DestFile
= preparePartialFileFromURI(Desc
.URI
);
341 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
343 // look for the current package file
344 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
345 CurrentPackagesFile
+= URItoFileName(RealURI
);
347 // FIXME: this file:/ check is a hack to prevent fetching
348 // from local sources. this is really silly, and
349 // should be fixed cleanly as soon as possible
350 if(!FileExists(CurrentPackagesFile
) ||
351 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
353 // we don't have a pkg file or we don't want to queue
355 std::clog
<< "No index file, local or canceld by user" << std::endl
;
361 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
362 << CurrentPackagesFile
<< std::endl
;
368 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
369 // ---------------------------------------------------------------------
370 /* The only header we use is the last-modified header. */
371 string
pkgAcqDiffIndex::Custom600Headers() const
373 string Final
= _config
->FindDir("Dir::State::lists");
374 Final
+= URItoFileName(Desc
.URI
);
377 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
380 if (stat(Final
.c_str(),&Buf
) != 0)
381 return "\nIndex-File: true";
383 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
386 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
389 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
394 vector
<DiffInfo
> available_patches
;
396 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
398 if (_error
->PendingError() == true)
401 if(TF
.Step(Tags
) == true)
407 string
const tmp
= Tags
.FindS("SHA1-Current");
408 std::stringstream
ss(tmp
);
409 ss
>> ServerSha1
>> size
;
410 unsigned long const ServerSize
= atol(size
.c_str());
412 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
415 string
const local_sha1
= SHA1
.Result();
417 if(local_sha1
== ServerSha1
)
419 // we have the same sha1 as the server so we are done here
421 std::clog
<< "Package file is up-to-date" << std::endl
;
422 // ensure we have no leftovers from previous runs
423 std::string Partial
= _config
->FindDir("Dir::State::lists");
424 Partial
+= "partial/" + URItoFileName(RealURI
);
425 unlink(Partial
.c_str());
426 // list cleanup needs to know that this file as well as the already
427 // present index is ours, so we create an empty diff to save it for us
428 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
429 ExpectedHashes
, MetaIndexParser
,
430 ServerSha1
, available_patches
);
436 std::clog
<< "SHA1-Current: " << ServerSha1
<< " and we start at "<< fd
.Name() << " " << fd
.Size() << " " << local_sha1
<< std::endl
;
438 // check the historie and see what patches we need
439 string
const history
= Tags
.FindS("SHA1-History");
440 std::stringstream
hist(history
);
441 while(hist
>> d
.sha1
>> size
>> d
.file
)
443 // read until the first match is found
444 // from that point on, we probably need all diffs
445 if(d
.sha1
== local_sha1
)
447 else if (found
== false)
451 std::clog
<< "Need to get diff: " << d
.file
<< std::endl
;
452 available_patches
.push_back(d
);
455 if (available_patches
.empty() == false)
457 // patching with too many files is rather slow compared to a fast download
458 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
459 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
462 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
463 << ") so fallback to complete download" << std::endl
;
467 // see if the patches are too big
468 found
= false; // it was true and it will be true again at the end
469 d
= *available_patches
.begin();
470 string
const firstPatch
= d
.file
;
471 unsigned long patchesSize
= 0;
472 std::stringstream
patches(Tags
.FindS("SHA1-Patches"));
473 while(patches
>> d
.sha1
>> size
>> d
.file
)
475 if (firstPatch
== d
.file
)
477 else if (found
== false)
480 patchesSize
+= atol(size
.c_str());
482 unsigned long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
483 if (sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
486 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
487 << ") so fallback to complete download" << std::endl
;
493 // we have something, queue the next diff
496 // FIXME: make this use the method
497 PackagesFileReadyInPartial
= true;
498 std::string
const Partial
= preparePartialFileFromURI(RealURI
);
500 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
501 FileFd
To(Partial
, FileFd::WriteEmpty
);
502 if(CopyFile(From
, To
) == false)
503 return _error
->Errno("CopyFile", "failed to copy");
506 std::cerr
<< "Done copying " << CurrentPackagesFile
511 string::size_type
const last_space
= Description
.rfind(" ");
512 if(last_space
!= string::npos
)
513 Description
.erase(last_space
, Description
.size()-last_space
);
515 /* decide if we should download patches one by one or in one go:
516 The first is good if the server merges patches, but many don't so client
517 based merging can be attempt in which case the second is better.
518 "bad things" will happen if patches are merged on the server,
519 but client side merging is attempt as well */
520 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
521 if (pdiff_merge
== true)
523 // reprepro adds this flag if it has merged patches on the server
524 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
525 pdiff_merge
= (precedence
!= "merged");
528 if (pdiff_merge
== false)
530 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
532 ServerSha1
, available_patches
);
536 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
537 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
538 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
,
543 available_patches
[i
],
554 // Nothing found, report and return false
555 // Failing here is ok, if we return false later, the full
556 // IndexFile is queued
558 std::clog
<< "Can't find a patch in the index file" << std::endl
;
562 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
565 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
566 << "Falling back to normal index file acquire" << std::endl
;
568 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
575 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
576 pkgAcquire::MethodConfig
*Cnf
)
579 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
581 Item::Done(Message
, Size
, Hashes
, Cnf
);
583 // verify the index target
584 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
586 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
587 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
588 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
590 RenameOnError(HashSumMismatch
);
591 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
592 Failed(Message
, Cnf
);
598 if(!ParseDiffIndex(DestFile
))
599 return Failed("", NULL
);
601 // queue for final move
603 FinalFile
= _config
->FindDir("Dir::State::lists")+URItoFileName(RealURI
);
604 FinalFile
+= string(".IndexDiff");
605 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
613 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
614 // ---------------------------------------------------------------------
615 /* The package diff is added to the queue. one object is constructed
616 * for each diff and the index
618 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
619 pkgAcqMetaBase
*TransactionManager
,
620 struct IndexTarget
const * const Target
,
621 HashStringList
const &ExpectedHashes
,
622 indexRecords
*MetaIndexParser
,
624 vector
<DiffInfo
> diffs
)
625 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
626 available_patches(diffs
), ServerSha1(ServerSha1
)
628 DestFile
= preparePartialFileFromURI(Target
->URI
);
630 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
632 RealURI
= Target
->URI
;
634 Description
= Target
->Description
;
635 Desc
.ShortDesc
= Target
->ShortDesc
;
637 if(available_patches
.empty() == true)
639 // we are done (yeah!), check hashes against the final file
640 DestFile
= _config
->FindDir("Dir::State::lists");
641 DestFile
+= URItoFileName(Target
->URI
);
647 State
= StateFetchDiff
;
652 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
655 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
656 << "Falling back to normal index file acquire" << std::endl
;
657 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
661 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
662 void pkgAcqIndexDiffs::Finish(bool allDone
)
665 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
667 << Desc
.URI
<< std::endl
;
669 // we restore the original name, this is required, otherwise
670 // the file will be cleaned
673 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
675 RenameOnError(HashSumMismatch
);
681 PartialFile
= preparePartialFileFromURI(RealURI
);
683 DestFile
= _config
->FindDir("Dir::State::lists");
684 DestFile
+= URItoFileName(RealURI
);
686 // this happens if we have a up-to-date indexfile
687 if(!FileExists(PartialFile
))
688 PartialFile
= DestFile
;
690 TransactionManager
->TransactionStageCopy(this, PartialFile
, DestFile
);
692 // this is for the "real" finish
697 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
702 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
709 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
711 // calc sha1 of the just patched file
712 std::string
const FinalFile
= preparePartialFileFromURI(RealURI
);
714 if(!FileExists(FinalFile
))
716 Failed("No FinalFile " + FinalFile
+ " available", NULL
);
720 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
723 string local_sha1
= string(SHA1
.Result());
725 std::clog
<< "QueueNextDiff: "
726 << FinalFile
<< " (" << local_sha1
<< ")"<<std::endl
;
729 // final file reached before all patches are applied
730 if(local_sha1
== ServerSha1
)
736 // remove all patches until the next matching patch is found
737 // this requires the Index file to be ordered
738 for(vector
<DiffInfo
>::iterator I
=available_patches
.begin();
739 available_patches
.empty() == false &&
740 I
!= available_patches
.end() &&
741 I
->sha1
!= local_sha1
;
744 available_patches
.erase(I
);
747 // error checking and falling back if no patch was found
748 if(available_patches
.empty() == true)
750 Failed("No patches available", NULL
);
754 // queue the right diff
755 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
756 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
757 DestFile
= preparePartialFileFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
760 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
767 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
768 pkgAcquire::MethodConfig
*Cnf
)
771 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
773 Item::Done(Message
, Size
, Hashes
, Cnf
);
775 // FIXME: verify this download too before feeding it to rred
776 std::string
const FinalFile
= preparePartialFileFromURI(RealURI
);
778 // success in downloading a diff, enter ApplyDiff state
779 if(State
== StateFetchDiff
)
782 // rred excepts the patch as $FinalFile.ed
783 Rename(DestFile
,FinalFile
+".ed");
786 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
788 State
= StateApplyDiff
;
790 Desc
.URI
= "rred:" + FinalFile
;
792 SetActiveSubprocess("rred");
797 // success in download/apply a diff, queue next (if needed)
798 if(State
== StateApplyDiff
)
800 // remove the just applied patch
801 available_patches
.erase(available_patches
.begin());
802 unlink((FinalFile
+ ".ed").c_str());
807 std::clog
<< "Moving patched file in place: " << std::endl
808 << DestFile
<< " -> " << FinalFile
<< std::endl
;
810 Rename(DestFile
,FinalFile
);
811 chmod(FinalFile
.c_str(),0644);
813 // see if there is more to download
814 if(available_patches
.empty() == false) {
815 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
816 ExpectedHashes
, MetaIndexParser
,
817 ServerSha1
, available_patches
);
821 DestFile
= FinalFile
;
826 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
827 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
828 pkgAcqMetaBase
*TransactionManager
,
829 struct IndexTarget
const * const Target
,
830 HashStringList
const &ExpectedHashes
,
831 indexRecords
*MetaIndexParser
,
832 DiffInfo
const &patch
,
833 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
834 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
835 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
837 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
839 RealURI
= Target
->URI
;
841 Description
= Target
->Description
;
842 Desc
.ShortDesc
= Target
->ShortDesc
;
844 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
845 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
847 DestFile
= preparePartialFileFromURI(RealURI
+ ".diff/" + patch
.file
);
850 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
855 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
858 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
863 // check if we are the first to fail, otherwise we are done here
864 State
= StateDoneDiff
;
865 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
866 I
!= allPatches
->end(); ++I
)
867 if ((*I
)->State
== StateErrorDiff
)
870 // first failure means we should fallback
871 State
= StateErrorDiff
;
872 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
873 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
876 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
877 pkgAcquire::MethodConfig
*Cnf
)
880 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
882 Item::Done(Message
,Size
,Hashes
,Cnf
);
884 // FIXME: verify download before feeding it to rred
885 string
const FinalFile
= preparePartialFileFromURI(RealURI
);
887 if (State
== StateFetchDiff
)
889 // rred expects the patch as $FinalFile.ed.$patchname.gz
890 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
892 // check if this is the last completed diff
893 State
= StateDoneDiff
;
894 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
895 I
!= allPatches
->end(); ++I
)
896 if ((*I
)->State
!= StateDoneDiff
)
899 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
903 // this is the last completed diff, so we are ready to apply now
904 State
= StateApplyDiff
;
907 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
910 Desc
.URI
= "rred:" + FinalFile
;
912 SetActiveSubprocess("rred");
915 // success in download/apply all diffs, clean up
916 else if (State
== StateApplyDiff
)
918 // see if we really got the expected file
919 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
921 RenameOnError(HashSumMismatch
);
926 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
927 FinalFile
+= URItoFileName(RealURI
);
929 // move the result into place
931 std::clog
<< "Queue patched file in place: " << std::endl
932 << DestFile
<< " -> " << FinalFile
<< std::endl
;
934 // queue for copy by the transaction manager
935 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
937 // ensure the ed's are gone regardless of list-cleanup
938 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
939 I
!= allPatches
->end(); ++I
)
941 std::string
const PartialFile
= preparePartialFileFromURI(RealURI
);
942 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
943 std::cerr
<< patch
<< std::endl
;
944 unlink(patch
.c_str());
950 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
954 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
955 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
957 if(MetaKey
!= "" && Hashes
.usable())
959 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
960 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
962 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
969 // AcqIndex::AcqIndex - Constructor /*{{{*/
970 // ---------------------------------------------------------------------
971 /* The package file is added to the queue and a second class is
972 instantiated to fetch the revision file */
973 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
974 string URI
,string URIDesc
,string ShortDesc
,
975 HashStringList
const &ExpectedHash
)
976 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
980 AutoSelectCompression();
981 Init(URI
, URIDesc
, ShortDesc
);
983 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
984 std::clog
<< "New pkgIndex with TransactionManager "
985 << TransactionManager
<< std::endl
;
988 // AcqIndex::AcqIndex - Constructor /*{{{*/
989 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
990 pkgAcqMetaBase
*TransactionManager
,
991 IndexTarget
const *Target
,
992 HashStringList
const &ExpectedHash
,
993 indexRecords
*MetaIndexParser
)
994 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
997 RealURI
= Target
->URI
;
999 // autoselect the compression method
1000 AutoSelectCompression();
1001 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1003 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1004 std::clog
<< "New pkgIndex with TransactionManager "
1005 << TransactionManager
<< std::endl
;
1008 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1009 void pkgAcqIndex::AutoSelectCompression()
1011 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1012 CompressionExtensions
= "";
1013 if (ExpectedHashes
.usable())
1015 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1016 t
!= types
.end(); ++t
)
1018 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1019 if (*t
== "uncompressed" ||
1020 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1021 CompressionExtensions
.append(*t
).append(" ");
1026 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1027 CompressionExtensions
.append(*t
).append(" ");
1029 if (CompressionExtensions
.empty() == false)
1030 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1033 // AcqIndex::Init - defered Constructor /*{{{*/
1034 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1035 string
const &ShortDesc
)
1037 Stage
= STAGE_DOWNLOAD
;
1039 DestFile
= preparePartialFileFromURI(URI
);
1041 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1042 if (CurrentCompressionExtension
== "uncompressed")
1046 MetaKey
= string(Target
->MetaKey
);
1050 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1051 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1053 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1056 // load the filesize
1059 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1061 FileSize
= Record
->Size
;
1063 InitByHashIfNeeded(MetaKey
);
1066 Desc
.Description
= URIDesc
;
1068 Desc
.ShortDesc
= ShortDesc
;
1073 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1074 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1077 // - (maybe?) add support for by-hash into the sources.list as flag
1078 // - make apt-ftparchive generate the hashes (and expire?)
1079 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1080 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1081 _config
->FindB(HostKnob
, false) == true ||
1082 MetaIndexParser
->GetSupportsAcquireByHash())
1084 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1087 // FIXME: should we really use the best hash here? or a fixed one?
1088 const HashString
*TargetHash
= Record
->Hashes
.find("");
1089 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1090 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1091 Desc
.URI
= Desc
.URI
.replace(
1093 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1097 "Fetching ByHash requested but can not find record for %s",
1103 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1104 // ---------------------------------------------------------------------
1105 /* The only header we use is the last-modified header. */
1106 string
pkgAcqIndex::Custom600Headers() const
1108 string Final
= GetFinalFilename();
1110 string msg
= "\nIndex-File: true";
1112 if (stat(Final
.c_str(),&Buf
) == 0)
1113 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1118 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1119 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1121 size_t const nextExt
= CompressionExtensions
.find(' ');
1122 if (nextExt
!= std::string::npos
)
1124 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1125 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1129 // on decompression failure, remove bad versions in partial/
1130 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1132 unlink(EraseFileName
.c_str());
1135 Item::Failed(Message
,Cnf
);
1137 /// cancel the entire transaction
1138 TransactionManager
->AbortTransaction();
1141 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1142 std::string
pkgAcqIndex::GetFinalFilename() const
1144 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1145 FinalFile
+= URItoFileName(RealURI
);
1146 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1147 FinalFile
+= '.' + CurrentCompressionExtension
;
1151 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1152 void pkgAcqIndex::ReverifyAfterIMS()
1154 // update destfile to *not* include the compression extension when doing
1155 // a reverify (as its uncompressed on disk already)
1156 DestFile
= preparePartialFileFromURI(RealURI
);
1158 // adjust DestFile if its compressed on disk
1159 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1160 DestFile
+= '.' + CurrentCompressionExtension
;
1162 // copy FinalFile into partial/ so that we check the hash again
1163 string FinalFile
= GetFinalFilename();
1164 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1165 Desc
.URI
= "copy:" + FinalFile
;
1169 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1170 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1172 // FIXME: this can go away once we only ever download stuff that
1173 // has a valid hash and we never do GET based probing
1174 // FIXME2: this also leaks debian-isms into the code and should go therefore
1176 /* Always validate the index file for correctness (all indexes must
1177 * have a Package field) (LP: #346386) (Closes: #627642)
1179 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1180 // Only test for correctness if the content of the file is not empty
1185 pkgTagFile
tag(&fd
);
1187 // all our current indexes have a field 'Package' in each section
1188 if (_error
->PendingError() == true ||
1189 tag
.Step(sec
) == false ||
1190 sec
.Exists("Package") == false)
1196 // AcqIndex::Done - Finished a fetch /*{{{*/
1197 // ---------------------------------------------------------------------
1198 /* This goes through a number of states.. On the initial fetch the
1199 method could possibly return an alternate filename which points
1200 to the uncompressed version of the file. If this is so the file
1201 is copied into the partial directory. In all other cases the file
1202 is decompressed with a compressed uri. */
1203 void pkgAcqIndex::Done(string Message
,
1204 unsigned long long Size
,
1205 HashStringList
const &Hashes
,
1206 pkgAcquire::MethodConfig
*Cfg
)
1208 Item::Done(Message
,Size
,Hashes
,Cfg
);
1212 case STAGE_DOWNLOAD
:
1213 StageDownloadDone(Message
, Hashes
, Cfg
);
1215 case STAGE_DECOMPRESS_AND_VERIFY
:
1216 StageDecompressDone(Message
, Hashes
, Cfg
);
1221 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1222 void pkgAcqIndex::StageDownloadDone(string Message
,
1223 HashStringList
const &Hashes
,
1224 pkgAcquire::MethodConfig
*Cfg
)
1226 // First check if the calculcated Hash of the (compressed) downloaded
1227 // file matches the hash we have in the MetaIndexRecords for this file
1228 if(VerifyHashByMetaKey(Hashes
) == false)
1230 RenameOnError(HashSumMismatch
);
1231 Failed(Message
, Cfg
);
1237 // Handle the unzipd case
1238 string FileName
= LookupTag(Message
,"Alt-Filename");
1239 if (FileName
.empty() == false)
1241 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1243 DestFile
+= ".decomp";
1244 Desc
.URI
= "copy:" + FileName
;
1246 SetActiveSubprocess("copy");
1250 FileName
= LookupTag(Message
,"Filename");
1251 if (FileName
.empty() == true)
1254 ErrorText
= "Method gave a blank filename";
1257 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1258 // not the "DestFile" we set, in this case we uncompress from the local file
1259 if (FileName
!= DestFile
)
1262 EraseFileName
= FileName
;
1264 // we need to verify the file against the current Release file again
1265 // on if-modfied-since hit to avoid a stale attack against us
1266 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1268 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1269 // file when its doing the indexcopy
1270 if (RealURI
.substr(0,6) == "cdrom:")
1273 // The files timestamp matches, reverify by copy into partial/
1279 // If we have compressed indexes enabled, queue for hash verification
1280 if (_config
->FindB("Acquire::GzipIndexes",false))
1282 DestFile
= preparePartialFileFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1284 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1285 Desc
.URI
= "copy:" + FileName
;
1291 // get the binary name for your used compression type
1293 if(CurrentCompressionExtension
== "uncompressed")
1294 decompProg
= "copy";
1296 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1297 if(decompProg
.empty() == true)
1299 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1303 // queue uri for the next stage
1304 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1305 DestFile
+= ".decomp";
1306 Desc
.URI
= decompProg
+ ":" + FileName
;
1309 SetActiveSubprocess(decompProg
);
1312 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1313 void pkgAcqIndex::StageDecompressDone(string Message
,
1314 HashStringList
const &Hashes
,
1315 pkgAcquire::MethodConfig
*Cfg
)
1317 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1320 RenameOnError(HashSumMismatch
);
1321 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1322 Failed(Message
, Cfg
);
1326 if(!ValidateFile(DestFile
))
1328 RenameOnError(InvalidFormat
);
1329 Failed(Message
, Cfg
);
1333 // remove the compressed version of the file
1334 unlink(EraseFileName
.c_str());
1336 // Done, queue for rename on transaction finished
1337 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1342 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1343 // ---------------------------------------------------------------------
1344 /* The Translation file is added to the queue */
1345 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1346 string URI
,string URIDesc
,string ShortDesc
)
1347 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1350 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1351 pkgAcqMetaBase
*TransactionManager
,
1352 IndexTarget
const * const Target
,
1353 HashStringList
const &ExpectedHashes
,
1354 indexRecords
*MetaIndexParser
)
1355 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1357 // load the filesize
1358 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1360 FileSize
= Record
->Size
;
1363 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1364 string
pkgAcqIndexTrans::Custom600Headers() const
1366 string Final
= GetFinalFilename();
1369 if (stat(Final
.c_str(),&Buf
) != 0)
1370 return "\nFail-Ignore: true\nIndex-File: true";
1371 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1374 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1375 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1377 size_t const nextExt
= CompressionExtensions
.find(' ');
1378 if (nextExt
!= std::string::npos
)
1380 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1381 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1386 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1387 if (Cnf
->LocalOnly
== true ||
1388 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1397 Item::Failed(Message
,Cnf
);
1400 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1401 void pkgAcqMetaBase::Add(Item
*I
)
1403 Transaction
.push_back(I
);
1406 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1407 void pkgAcqMetaBase::AbortTransaction()
1409 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1410 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1412 // ensure the toplevel is in error state too
1413 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1414 I
!= Transaction
.end(); ++I
)
1416 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1417 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1418 // the transaction will abort, so stop anything that is idle
1419 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1420 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1422 // kill files in partial
1423 std::string
const PartialFile
= preparePartialFile(flNotDir((*I
)->DestFile
));
1424 if(FileExists(PartialFile
))
1425 Rename(PartialFile
, PartialFile
+ ".FAILED");
1429 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1430 bool pkgAcqMetaBase::TransactionHasError()
1432 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1433 I
!= Transaction
.end(); ++I
)
1434 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1435 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1441 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1442 void pkgAcqMetaBase::CommitTransaction()
1444 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1445 std::clog
<< "CommitTransaction: " << this << std::endl
;
1447 // move new files into place *and* remove files that are not
1448 // part of the transaction but are still on disk
1449 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1450 I
!= Transaction
.end(); ++I
)
1452 if((*I
)->PartialFile
!= "")
1454 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1455 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1456 << (*I
)->DescURI() << std::endl
;
1458 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1459 changeOwnerAndPermissionOfFile("CommitTransaction", (*I
)->DestFile
.c_str(), "root", "root", 0644);
1462 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1468 unlink((*I
)->DestFile
.c_str());
1470 // mark that this transaction is finished
1471 (*I
)->TransactionManager
= 0;
1475 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1476 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1477 const std::string
&From
,
1478 const std::string
&To
)
1480 I
->PartialFile
= From
;
1484 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1485 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1486 const std::string
&FinalFile
)
1488 I
->PartialFile
= "";
1489 I
->DestFile
= FinalFile
;
1492 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1493 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&RealURI
,
1494 const std::string
&Message
)
1496 // FIXME: this entire function can do now that we disallow going to
1497 // a unauthenticated state and can cleanly rollback
1499 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1501 if(FileExists(Final
))
1503 Status
= StatTransientNetworkError
;
1504 _error
->Warning(_("An error occurred during the signature "
1505 "verification. The repository is not updated "
1506 "and the previous index files will be used. "
1507 "GPG error: %s: %s\n"),
1508 Desc
.Description
.c_str(),
1509 LookupTag(Message
,"Message").c_str());
1510 RunScripts("APT::Update::Auth-Failure");
1512 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1513 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1514 _error
->Error(_("GPG error: %s: %s"),
1515 Desc
.Description
.c_str(),
1516 LookupTag(Message
,"Message").c_str());
1520 _error
->Warning(_("GPG error: %s: %s"),
1521 Desc
.Description
.c_str(),
1522 LookupTag(Message
,"Message").c_str());
1524 // gpgv method failed
1525 ReportMirrorFailure("GPGFailure");
1529 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1530 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1531 pkgAcqMetaBase
*TransactionManager
,
1532 string URI
,string URIDesc
,string ShortDesc
,
1533 string MetaIndexFile
,
1534 const vector
<IndexTarget
*>* IndexTargets
,
1535 indexRecords
* MetaIndexParser
) :
1536 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1537 HashStringList(), TransactionManager
),
1538 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1539 ShortDesc(ShortDesc
)
1541 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1542 DestFile
+= URItoFileName(RealURI
);
1544 // remove any partial downloaded sig-file in partial/.
1545 // it may confuse proxies and is too small to warrant a
1546 // partial download anyway
1547 unlink(DestFile
.c_str());
1549 // set the TransactionManager
1550 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1551 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1552 << TransactionManager
<< std::endl
;
1555 Desc
.Description
= URIDesc
;
1557 Desc
.ShortDesc
= ShortDesc
;
1563 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1567 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1568 // ---------------------------------------------------------------------
1569 string
pkgAcqMetaSig::Custom600Headers() const
1571 string FinalFile
= _config
->FindDir("Dir::State::lists");
1572 FinalFile
+= URItoFileName(RealURI
);
1575 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1576 return "\nIndex-File: true";
1578 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1581 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1582 // ---------------------------------------------------------------------
1583 /* The only header we use is the last-modified header. */
1584 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1585 HashStringList
const &Hashes
,
1586 pkgAcquire::MethodConfig
*Cfg
)
1588 Item::Done(Message
, Size
, Hashes
, Cfg
);
1590 if(AuthPass
== false)
1592 if(CheckDownloadDone(Message
, RealURI
) == true)
1594 // destfile will be modified to point to MetaIndexFile for the
1595 // gpgv method, so we need to save it here
1596 MetaIndexFileSignature
= DestFile
;
1597 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1603 if(CheckAuthDone(Message
, RealURI
) == true)
1605 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1606 FinalFile
+= URItoFileName(RealURI
);
1607 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1612 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1614 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1616 // check if we need to fail at this point
1617 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1620 // FIXME: meh, this is not really elegant
1621 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1623 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1625 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1627 std::string downgrade_msg
;
1628 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1630 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1632 // meh, the users wants to take risks (we still mark the packages
1633 // from this repository as unauthenticated)
1634 _error
->Warning("%s", downgrade_msg
.c_str());
1635 _error
->Warning(_("This is normally not allowed, but the option "
1636 "Acquire::AllowDowngradeToInsecureRepositories was "
1637 "given to override it."));
1640 _error
->Error("%s", downgrade_msg
.c_str());
1641 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1642 Status
= pkgAcquire::Item::StatError
;
1643 TransactionManager
->AbortTransaction();
1648 // this ensures that any file in the lists/ dir is removed by the
1650 DestFile
= preparePartialFileFromURI(RealURI
);
1651 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1653 // only allow going further if the users explicitely wants it
1654 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
1656 // we parse the indexes here because at this point the user wanted
1657 // a repository that may potentially harm him
1658 MetaIndexParser
->Load(MetaIndexFile
);
1663 _error
->Warning("Use --allow-insecure-repositories to force the update");
1666 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1667 if (Cnf
->LocalOnly
== true ||
1668 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1676 Item::Failed(Message
,Cnf
);
1679 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1680 pkgAcqMetaBase
*TransactionManager
,
1681 string URI
,string URIDesc
,string ShortDesc
,
1682 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1683 const vector
<IndexTarget
*>* IndexTargets
,
1684 indexRecords
* MetaIndexParser
) :
1685 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1686 TransactionManager
),
1687 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1688 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1689 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1691 if(TransactionManager
== NULL
)
1693 this->TransactionManager
= this;
1694 this->TransactionManager
->Add(this);
1697 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1698 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1699 << this->TransactionManager
<< std::endl
;
1702 Init(URIDesc
, ShortDesc
);
1705 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1706 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1708 DestFile
= preparePartialFileFromURI(RealURI
);
1711 Desc
.Description
= URIDesc
;
1713 Desc
.ShortDesc
= ShortDesc
;
1716 // we expect more item
1717 ExpectedAdditionalItems
= IndexTargets
->size();
1721 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1722 // ---------------------------------------------------------------------
1723 string
pkgAcqMetaIndex::Custom600Headers() const
1725 string Final
= _config
->FindDir("Dir::State::lists");
1726 Final
+= URItoFileName(RealURI
);
1729 if (stat(Final
.c_str(),&Buf
) != 0)
1730 return "\nIndex-File: true";
1732 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1735 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1736 HashStringList
const &Hashes
,
1737 pkgAcquire::MethodConfig
*Cfg
)
1739 Item::Done(Message
,Size
,Hashes
,Cfg
);
1741 if(CheckDownloadDone(Message
, RealURI
))
1743 // we have a Release file, now download the Signature, all further
1744 // verify/queue for additional downloads will be done in the
1745 // pkgAcqMetaSig::Done() code
1746 std::string MetaIndexFile
= DestFile
;
1747 new pkgAcqMetaSig(Owner
, TransactionManager
,
1748 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1749 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1752 string FinalFile
= _config
->FindDir("Dir::State::lists");
1753 FinalFile
+= URItoFileName(RealURI
);
1754 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1758 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1760 // At this point, the gpgv method has succeeded, so there is a
1761 // valid signature from a key in the trusted keyring. We
1762 // perform additional verification of its contents, and use them
1763 // to verify the indexes we are about to download
1765 if (!MetaIndexParser
->Load(DestFile
))
1767 Status
= StatAuthError
;
1768 ErrorText
= MetaIndexParser
->ErrorText
;
1772 if (!VerifyVendor(Message
, RealURI
))
1777 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1778 std::cerr
<< "Signature verification succeeded: "
1779 << DestFile
<< std::endl
;
1781 // Download further indexes with verification
1783 // it would be really nice if we could simply do
1784 // if (IMSHit == false) QueueIndexes(true)
1785 // and skip the download if the Release file has not changed
1786 // - but right now the list cleaner will needs to be tricked
1787 // to not delete all our packages/source indexes in this case
1793 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1794 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1795 const std::string
&MetaIndexFileSignature
)
1798 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1799 DestFile
= MetaIndexFile
;
1801 SetActiveSubprocess("gpgv");
1804 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1805 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1806 const std::string
&RealURI
)
1808 // We have just finished downloading a Release file (it is not
1811 string FileName
= LookupTag(Message
,"Filename");
1812 if (FileName
.empty() == true)
1815 ErrorText
= "Method gave a blank filename";
1819 if (FileName
!= DestFile
)
1822 Desc
.URI
= "copy:" + FileName
;
1827 // make sure to verify against the right file on I-M-S hit
1828 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1831 string FinalFile
= _config
->FindDir("Dir::State::lists");
1832 FinalFile
+= URItoFileName(RealURI
);
1833 DestFile
= FinalFile
;
1836 // set Item to complete as the remaining work is all local (verify etc)
1842 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1844 bool transInRelease
= false;
1846 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1847 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1848 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1849 if (k
->find("Translation-") != std::string::npos
)
1851 transInRelease
= true;
1856 // at this point the real Items are loaded in the fetcher
1857 ExpectedAdditionalItems
= 0;
1858 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1859 Target
!= IndexTargets
->end();
1862 HashStringList ExpectedIndexHashes
;
1863 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1864 bool compressedAvailable
= false;
1867 if ((*Target
)->IsOptional() == true)
1869 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1870 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1871 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1873 compressedAvailable
= true;
1877 else if (verify
== true)
1879 Status
= StatAuthError
;
1880 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
1886 ExpectedIndexHashes
= Record
->Hashes
;
1887 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1889 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
1890 << "Expected Hash:" << std::endl
;
1891 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
1892 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
1893 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
1895 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
1897 Status
= StatAuthError
;
1898 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
1903 if ((*Target
)->IsOptional() == true)
1905 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
1907 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
1908 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
1909 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1911 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1916 /* Queue Packages file (either diff or full packages files, depending
1917 on the users option) - we also check if the PDiff Index file is listed
1918 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
1919 instead, but passing the required info to it is to much hassle */
1920 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
1921 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
1922 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1924 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
1928 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
1930 string::size_type pos
;
1932 // check for missing sigs (that where not fatal because otherwise we had
1935 string msg
= _("There is no public key available for the "
1936 "following key IDs:\n");
1937 pos
= Message
.find("NO_PUBKEY ");
1938 if (pos
!= std::string::npos
)
1940 string::size_type start
= pos
+strlen("NO_PUBKEY ");
1941 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
1942 missingkeys
+= (Fingerprint
);
1944 if(!missingkeys
.empty())
1945 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
1947 string Transformed
= MetaIndexParser
->GetExpectedDist();
1949 if (Transformed
== "../project/experimental")
1951 Transformed
= "experimental";
1954 pos
= Transformed
.rfind('/');
1955 if (pos
!= string::npos
)
1957 Transformed
= Transformed
.substr(0, pos
);
1960 if (Transformed
== ".")
1965 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
1966 MetaIndexParser
->GetValidUntil() > 0) {
1967 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
1968 if (invalid_since
> 0)
1969 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
1970 // the time since then the file is invalid - formated in the same way as in
1971 // the download progress display (e.g. 7d 3h 42min 1s)
1972 return _error
->Error(
1973 _("Release file for %s is expired (invalid since %s). "
1974 "Updates for this repository will not be applied."),
1975 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
1978 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1980 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
1981 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
1982 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
1985 if (MetaIndexParser
->CheckDist(Transformed
) == false)
1987 // This might become fatal one day
1988 // Status = StatAuthError;
1989 // ErrorText = "Conflicting distribution; expected "
1990 // + MetaIndexParser->GetExpectedDist() + " but got "
1991 // + MetaIndexParser->GetDist();
1993 if (!Transformed
.empty())
1995 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
1996 Desc
.Description
.c_str(),
1997 Transformed
.c_str(),
1998 MetaIndexParser
->GetDist().c_str());
2005 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2006 void pkgAcqMetaIndex::Failed(string
/*Message*/,
2007 pkgAcquire::MethodConfig
* /*Cnf*/)
2009 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2011 _error
->Warning(_("The repository '%s' does not have a Release file. "
2012 "This is deprecated, please contact the owner of the "
2013 "repository."), URIDesc
.c_str());
2015 // No Release file was present so fall
2016 // back to queueing Packages files without verification
2017 // only allow going further if the users explicitely wants it
2018 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2020 // Done, queue for rename on transaction finished
2021 if (FileExists(DestFile
))
2022 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2024 // queue without any kind of hashsum support
2025 QueueIndexes(false);
2027 // warn if the repository is unsinged
2028 _error
->Warning("Use --allow-insecure-repositories to force the update");
2029 TransactionManager
->AbortTransaction();
2035 void pkgAcqMetaIndex::Finished() /*{{{*/
2037 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2038 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2039 if(TransactionManager
!= NULL
&&
2040 TransactionManager
->TransactionHasError() == false)
2041 TransactionManager
->CommitTransaction();
2044 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2045 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2046 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2047 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2048 const vector
<IndexTarget
*>* IndexTargets
,
2049 indexRecords
* MetaIndexParser
) :
2050 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2051 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2052 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2054 // index targets + (worst case:) Release/Release.gpg
2055 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2059 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2063 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2064 // ---------------------------------------------------------------------
2065 string
pkgAcqMetaClearSig::Custom600Headers() const
2067 string Final
= _config
->FindDir("Dir::State::lists");
2068 Final
+= URItoFileName(RealURI
);
2071 if (stat(Final
.c_str(),&Buf
) != 0)
2073 if (stat(Final
.c_str(),&Buf
) != 0)
2074 return "\nIndex-File: true\nFail-Ignore: true\n";
2077 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2080 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2081 // ---------------------------------------------------------------------
2082 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long /*Size*/,
2083 HashStringList
const &/*Hashes*/,
2084 pkgAcquire::MethodConfig
*Cnf
)
2086 // if we expect a ClearTextSignature (InRelase), ensure that
2087 // this is what we get and if not fail to queue a
2088 // Release/Release.gpg, see #346386
2089 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2091 pkgAcquire::Item::Failed(Message
, Cnf
);
2092 RenameOnError(NotClearsigned
);
2093 TransactionManager
->AbortTransaction();
2097 if(AuthPass
== false)
2099 if(CheckDownloadDone(Message
, RealURI
) == true)
2100 QueueForSignatureVerify(DestFile
, DestFile
);
2105 if(CheckAuthDone(Message
, RealURI
) == true)
2107 string FinalFile
= _config
->FindDir("Dir::State::lists");
2108 FinalFile
+= URItoFileName(RealURI
);
2110 // queue for copy in place
2111 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2116 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2118 // we failed, we will not get additional items from this method
2119 ExpectedAdditionalItems
= 0;
2121 if (AuthPass
== false)
2123 // Queue the 'old' InRelease file for removal if we try Release.gpg
2124 // as otherwise the file will stay around and gives a false-auth
2125 // impression (CVE-2012-0214)
2126 string FinalFile
= _config
->FindDir("Dir::State::lists");
2127 FinalFile
.append(URItoFileName(RealURI
));
2128 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2130 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2131 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2132 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2133 IndexTargets
, MetaIndexParser
);
2134 if (Cnf
->LocalOnly
== true ||
2135 StringToBool(LookupTag(Message
, "Transient-Failure"), false) == false)
2140 if(CheckStopAuthentication(RealURI
, Message
))
2143 _error
->Warning(_("The data from '%s' is not signed. Packages "
2144 "from that repository can not be authenticated."),
2147 // No Release file was present, or verification failed, so fall
2148 // back to queueing Packages files without verification
2149 // only allow going further if the users explicitely wants it
2150 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2152 /* Always move the meta index, even if gpgv failed. This ensures
2153 * that PackageFile objects are correctly filled in */
2154 if (FileExists(DestFile
))
2156 string FinalFile
= _config
->FindDir("Dir::State::lists");
2157 FinalFile
+= URItoFileName(RealURI
);
2158 /* InRelease files become Release files, otherwise
2159 * they would be considered as trusted later on */
2160 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2162 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2166 // Done, queue for rename on transaction finished
2167 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2169 QueueIndexes(false);
2171 // warn if the repository is unsinged
2172 _error
->Warning("Use --allow-insecure-repositories to force the update");
2173 TransactionManager
->AbortTransaction();
2180 // AcqArchive::AcqArchive - Constructor /*{{{*/
2181 // ---------------------------------------------------------------------
2182 /* This just sets up the initial fetch environment and queues the first
2184 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2185 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2186 string
&StoreFilename
) :
2187 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2188 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2191 Retries
= _config
->FindI("Acquire::Retries",0);
2193 if (Version
.Arch() == 0)
2195 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2196 "This might mean you need to manually fix this package. "
2197 "(due to missing arch)"),
2198 Version
.ParentPkg().FullName().c_str());
2202 /* We need to find a filename to determine the extension. We make the
2203 assumption here that all the available sources for this version share
2204 the same extension.. */
2205 // Skip not source sources, they do not have file fields.
2206 for (; Vf
.end() == false; ++Vf
)
2208 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2213 // Does not really matter here.. we are going to fail out below
2214 if (Vf
.end() != true)
2216 // If this fails to get a file name we will bomb out below.
2217 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2218 if (_error
->PendingError() == true)
2221 // Generate the final file name as: package_version_arch.foo
2222 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2223 QuoteString(Version
.VerStr(),"_:") + '_' +
2224 QuoteString(Version
.Arch(),"_:.") +
2225 "." + flExtension(Parse
.FileName());
2228 // check if we have one trusted source for the package. if so, switch
2229 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2230 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2231 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2232 bool seenUntrusted
= false;
2233 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2235 pkgIndexFile
*Index
;
2236 if (Sources
->FindIndex(i
.File(),Index
) == false)
2239 if (debugAuth
== true)
2240 std::cerr
<< "Checking index: " << Index
->Describe()
2241 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2243 if (Index
->IsTrusted() == true)
2246 if (allowUnauth
== false)
2250 seenUntrusted
= true;
2253 // "allow-unauthenticated" restores apts old fetching behaviour
2254 // that means that e.g. unauthenticated file:// uris are higher
2255 // priority than authenticated http:// uris
2256 if (allowUnauth
== true && seenUntrusted
== true)
2260 if (QueueNext() == false && _error
->PendingError() == false)
2261 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2262 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2265 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2266 // ---------------------------------------------------------------------
2267 /* This queues the next available file version for download. It checks if
2268 the archive is already available in the cache and stashs the MD5 for
2270 bool pkgAcqArchive::QueueNext()
2272 for (; Vf
.end() == false; ++Vf
)
2274 // Ignore not source sources
2275 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2278 // Try to cross match against the source list
2279 pkgIndexFile
*Index
;
2280 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2283 // only try to get a trusted package from another source if that source
2285 if(Trusted
&& !Index
->IsTrusted())
2288 // Grab the text package record
2289 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2290 if (_error
->PendingError() == true)
2293 string PkgFile
= Parse
.FileName();
2294 ExpectedHashes
= Parse
.Hashes();
2296 if (PkgFile
.empty() == true)
2297 return _error
->Error(_("The package index files are corrupted. No Filename: "
2298 "field for package %s."),
2299 Version
.ParentPkg().Name());
2301 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2302 Desc
.Description
= Index
->ArchiveInfo(Version
);
2304 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2306 // See if we already have the file. (Legacy filenames)
2307 FileSize
= Version
->Size
;
2308 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2310 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2312 // Make sure the size matches
2313 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2318 StoreFilename
= DestFile
= FinalFile
;
2322 /* Hmm, we have a file and its size does not match, this means it is
2323 an old style mismatched arch */
2324 unlink(FinalFile
.c_str());
2327 // Check it again using the new style output filenames
2328 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2329 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2331 // Make sure the size matches
2332 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2337 StoreFilename
= DestFile
= FinalFile
;
2341 /* Hmm, we have a file and its size does not match, this shouldn't
2343 unlink(FinalFile
.c_str());
2346 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2348 // Check the destination file
2349 if (stat(DestFile
.c_str(),&Buf
) == 0)
2351 // Hmm, the partial file is too big, erase it
2352 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2353 unlink(DestFile
.c_str());
2356 PartialSize
= Buf
.st_size
;
2357 changeOwnerAndPermissionOfFile("pkgAcqArchive::QueueNext", FinalFile
.c_str(), "_apt", "root", 0600);
2361 // Disables download of archives - useful if no real installation follows,
2362 // e.g. if we are just interested in proposed installation order
2363 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2368 StoreFilename
= DestFile
= FinalFile
;
2382 // AcqArchive::Done - Finished fetching /*{{{*/
2383 // ---------------------------------------------------------------------
2385 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2386 pkgAcquire::MethodConfig
*Cfg
)
2388 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2391 if (Size
!= Version
->Size
)
2393 RenameOnError(SizeMismatch
);
2397 // FIXME: could this empty() check impose *any* sort of security issue?
2398 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2400 RenameOnError(HashSumMismatch
);
2401 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2405 // Grab the output filename
2406 string FileName
= LookupTag(Message
,"Filename");
2407 if (FileName
.empty() == true)
2410 ErrorText
= "Method gave a blank filename";
2414 // Reference filename
2415 if (FileName
!= DestFile
)
2417 StoreFilename
= DestFile
= FileName
;
2423 // Done, move it into position
2424 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2425 FinalFile
+= flNotDir(StoreFilename
);
2426 Rename(DestFile
,FinalFile
);
2427 changeOwnerAndPermissionOfFile("pkgAcqArchive::Done", FinalFile
.c_str(), "root", "root", 0644);
2428 StoreFilename
= DestFile
= FinalFile
;
2432 // AcqArchive::Failed - Failure handler /*{{{*/
2433 // ---------------------------------------------------------------------
2434 /* Here we try other sources */
2435 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2437 ErrorText
= LookupTag(Message
,"Message");
2439 /* We don't really want to retry on failed media swaps, this prevents
2440 that. An interesting observation is that permanent failures are not
2442 if (Cnf
->Removable
== true &&
2443 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2445 // Vf = Version.FileList();
2446 while (Vf
.end() == false) ++Vf
;
2447 StoreFilename
= string();
2448 Item::Failed(Message
,Cnf
);
2452 if (QueueNext() == false)
2454 // This is the retry counter
2456 Cnf
->LocalOnly
== false &&
2457 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2460 Vf
= Version
.FileList();
2461 if (QueueNext() == true)
2465 StoreFilename
= string();
2466 Item::Failed(Message
,Cnf
);
2470 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2471 // ---------------------------------------------------------------------
2472 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2477 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2478 // ---------------------------------------------------------------------
2480 void pkgAcqArchive::Finished()
2482 if (Status
== pkgAcquire::Item::StatDone
&&
2485 StoreFilename
= string();
2488 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2489 // ---------------------------------------------------------------------
2490 /* The file is added to the queue */
2491 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2492 unsigned long long Size
,string Dsc
,string ShortDesc
,
2493 const string
&DestDir
, const string
&DestFilename
,
2495 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2497 Retries
= _config
->FindI("Acquire::Retries",0);
2499 if(!DestFilename
.empty())
2500 DestFile
= DestFilename
;
2501 else if(!DestDir
.empty())
2502 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2504 DestFile
= flNotDir(URI
);
2508 Desc
.Description
= Dsc
;
2511 // Set the short description to the archive component
2512 Desc
.ShortDesc
= ShortDesc
;
2514 // Get the transfer sizes
2517 if (stat(DestFile
.c_str(),&Buf
) == 0)
2519 // Hmm, the partial file is too big, erase it
2520 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2521 unlink(DestFile
.c_str());
2524 PartialSize
= Buf
.st_size
;
2525 changeOwnerAndPermissionOfFile("pkgAcqFile", DestFile
.c_str(), "_apt", "root", 0600);
2532 // AcqFile::Done - Item downloaded OK /*{{{*/
2533 // ---------------------------------------------------------------------
2535 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2536 pkgAcquire::MethodConfig
*Cnf
)
2538 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2541 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2543 RenameOnError(HashSumMismatch
);
2544 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2548 string FileName
= LookupTag(Message
,"Filename");
2549 if (FileName
.empty() == true)
2552 ErrorText
= "Method gave a blank filename";
2558 // The files timestamp matches
2559 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2562 // We have to copy it into place
2563 if (FileName
!= DestFile
)
2566 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2567 Cnf
->Removable
== true)
2569 Desc
.URI
= "copy:" + FileName
;
2574 // Erase the file if it is a symlink so we can overwrite it
2576 if (lstat(DestFile
.c_str(),&St
) == 0)
2578 if (S_ISLNK(St
.st_mode
) != 0)
2579 unlink(DestFile
.c_str());
2583 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2585 ErrorText
= "Link to " + DestFile
+ " failure ";
2592 // AcqFile::Failed - Failure handler /*{{{*/
2593 // ---------------------------------------------------------------------
2594 /* Here we try other sources */
2595 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2597 ErrorText
= LookupTag(Message
,"Message");
2599 // This is the retry counter
2601 Cnf
->LocalOnly
== false &&
2602 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2609 Item::Failed(Message
,Cnf
);
2612 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2613 // ---------------------------------------------------------------------
2614 /* The only header we use is the last-modified header. */
2615 string
pkgAcqFile::Custom600Headers() const
2618 return "\nIndex-File: true";