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
GetPartialFileName(std::string
const &file
)
83 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
87 static std::string
GetPartialFileNameFromURI(std::string
const &uri
)
89 return GetPartialFileName(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
)
129 ErrorText
= LookupTag(Message
,"Message");
130 UsedMirror
= LookupTag(Message
,"UsedMirror");
131 if (QueueCounter
<= 1)
133 /* This indicates that the file is not available right now but might
134 be sometime later. If we do a retry cycle then this should be
136 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
137 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
151 // report mirror failure back to LP if we actually use a mirror
152 string FailReason
= LookupTag(Message
, "FailReason");
153 if(FailReason
.size() != 0)
154 ReportMirrorFailure(FailReason
);
156 ReportMirrorFailure(ErrorText
);
159 // Acquire::Item::Start - Item has begun to download /*{{{*/
160 // ---------------------------------------------------------------------
161 /* Stash status and the file size. Note that setting Complete means
162 sub-phases of the acquire process such as decompresion are operating */
163 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
165 Status
= StatFetching
;
166 if (FileSize
== 0 && Complete
== false)
170 // Acquire::Item::Done - Item downloaded OK /*{{{*/
171 // ---------------------------------------------------------------------
173 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
174 pkgAcquire::MethodConfig
* /*Cnf*/)
176 // We just downloaded something..
177 string FileName
= LookupTag(Message
,"Filename");
178 UsedMirror
= LookupTag(Message
,"UsedMirror");
179 if (Complete
== false && !Local
&& FileName
== DestFile
)
182 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
188 ErrorText
= string();
189 Owner
->Dequeue(this);
192 // Acquire::Item::Rename - Rename a file /*{{{*/
193 // ---------------------------------------------------------------------
194 /* This helper function is used by a lot of item methods as their final
196 bool pkgAcquire::Item::Rename(string From
,string To
)
198 if (rename(From
.c_str(),To
.c_str()) != 0)
201 snprintf(S
,sizeof(S
),_("rename failed, %s (%s -> %s)."),strerror(errno
),
202 From
.c_str(),To
.c_str());
211 void pkgAcquire::Item::QueueURI(ItemDesc
&Item
)
213 if (RealFileExists(DestFile
))
214 ChangeOwnerAndPermissionOfFile("GetPartialFileName", DestFile
.c_str(), "_apt", "root", 0600);
215 Owner
->Enqueue(Item
);
217 void pkgAcquire::Item::Dequeue()
219 Owner
->Dequeue(this);
222 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
224 if(FileExists(DestFile
))
225 Rename(DestFile
, DestFile
+ ".FAILED");
229 case HashSumMismatch
:
230 ErrorText
= _("Hash Sum mismatch");
231 Status
= StatAuthError
;
232 ReportMirrorFailure("HashChecksumFailure");
235 ErrorText
= _("Size mismatch");
236 Status
= StatAuthError
;
237 ReportMirrorFailure("SizeFailure");
240 ErrorText
= _("Invalid file format");
242 // do not report as usually its not the mirrors fault, but Portal/Proxy
245 ErrorText
= _("Signature error");
249 ErrorText
= _("Does not start with a cleartext signature");
256 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
258 ActiveSubprocess
= subprocess
;
260 #pragma GCC diagnostic push
261 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
263 Mode
= ActiveSubprocess
.c_str();
265 #pragma GCC diagnostic pop
269 // Acquire::Item::ReportMirrorFailure /*{{{*/
270 // ---------------------------------------------------------------------
271 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
273 // we only act if a mirror was used at all
274 if(UsedMirror
.empty())
277 std::cerr
<< "\nReportMirrorFailure: "
279 << " Uri: " << DescURI()
281 << FailCode
<< std::endl
;
283 const char *Args
[40];
285 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
286 "/usr/lib/apt/apt-report-mirror-failure");
287 if(!FileExists(report
))
289 Args
[i
++] = report
.c_str();
290 Args
[i
++] = UsedMirror
.c_str();
291 Args
[i
++] = DescURI().c_str();
292 Args
[i
++] = FailCode
.c_str();
294 pid_t pid
= ExecFork();
297 _error
->Error("ReportMirrorFailure Fork failed");
302 execvp(Args
[0], (char**)Args
);
303 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
306 if(!ExecWait(pid
, "report-mirror-failure"))
308 _error
->Warning("Couldn't report problem to '%s'",
309 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
313 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
314 // ---------------------------------------------------------------------
315 /* Get the DiffIndex file first and see if there are patches available
316 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
317 * patches. If anything goes wrong in that process, it will fall back to
318 * the original packages file
320 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
321 pkgAcqMetaBase
*TransactionManager
,
322 IndexTarget
const * const Target
,
323 HashStringList
const &ExpectedHashes
,
324 indexRecords
*MetaIndexParser
)
325 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
326 MetaIndexParser
), PackagesFileReadyInPartial(false)
329 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
331 RealURI
= Target
->URI
;
333 Desc
.Description
= Target
->Description
+ ".diff/Index";
334 Desc
.ShortDesc
= Target
->ShortDesc
;
335 Desc
.URI
= Target
->URI
+ ".diff/Index";
337 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
340 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
342 // look for the current package file
343 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
344 CurrentPackagesFile
+= URItoFileName(RealURI
);
346 // FIXME: this file:/ check is a hack to prevent fetching
347 // from local sources. this is really silly, and
348 // should be fixed cleanly as soon as possible
349 if(!FileExists(CurrentPackagesFile
) ||
350 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
352 // we don't have a pkg file or we don't want to queue
353 Failed("No index file, local or canceld by user", NULL
);
358 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
359 << CurrentPackagesFile
<< std::endl
;
365 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
366 // ---------------------------------------------------------------------
367 /* The only header we use is the last-modified header. */
368 string
pkgAcqDiffIndex::Custom600Headers() const
370 string Final
= _config
->FindDir("Dir::State::lists");
371 Final
+= URItoFileName(Desc
.URI
);
374 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
377 if (stat(Final
.c_str(),&Buf
) != 0)
378 return "\nIndex-File: true";
380 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
383 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
385 // failing here is fine: our caller will take care of trying to
386 // get the complete file if patching fails
388 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
391 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
393 if (_error
->PendingError() == true)
397 if(unlikely(TF
.Step(Tags
) == false))
400 HashStringList ServerHashes
;
401 unsigned long long ServerSize
= 0;
403 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
405 std::string tagname
= *type
;
406 tagname
.append("-Current");
407 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
408 if (tmp
.empty() == true)
412 unsigned long long size
;
413 std::stringstream
ss(tmp
);
415 if (unlikely(hash
.empty() == true))
417 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
419 ServerHashes
.push_back(HashString(*type
, hash
));
423 if (ServerHashes
.usable() == false)
426 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
430 if (ServerHashes
!= HashSums())
434 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
435 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, HashSums());
440 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
442 // we have the same sha1 as the server so we are done here
444 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
446 // list cleanup needs to know that this file as well as the already
447 // present index is ours, so we create an empty diff to save it for us
448 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
449 ExpectedHashes
, MetaIndexParser
);
453 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
454 Hashes LocalHashesCalc
;
455 LocalHashesCalc
.AddFD(fd
);
456 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
459 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
460 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
462 // parse all of (provided) history
463 vector
<DiffInfo
> available_patches
;
464 bool firstAcceptedHashes
= true;
465 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
467 if (LocalHashes
.find(*type
) == NULL
)
470 std::string tagname
= *type
;
471 tagname
.append("-History");
472 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
473 if (tmp
.empty() == true)
476 string hash
, filename
;
477 unsigned long long size
;
478 std::stringstream
ss(tmp
);
480 while (ss
>> hash
>> size
>> filename
)
482 if (unlikely(hash
.empty() == true || filename
.empty() == true))
485 // see if we have a record for this file already
486 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
487 for (; cur
!= available_patches
.end(); ++cur
)
489 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
491 cur
->result_hashes
.push_back(HashString(*type
, hash
));
494 if (cur
!= available_patches
.end())
496 if (firstAcceptedHashes
== true)
499 next
.file
= filename
;
500 next
.result_hashes
.push_back(HashString(*type
, hash
));
501 next
.result_size
= size
;
503 available_patches
.push_back(next
);
508 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
509 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
513 firstAcceptedHashes
= false;
516 if (unlikely(available_patches
.empty() == true))
519 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
520 << "Couldn't find any patches for the patch series." << std::endl
;
524 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
526 if (LocalHashes
.find(*type
) == NULL
)
529 std::string tagname
= *type
;
530 tagname
.append("-Patches");
531 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
532 if (tmp
.empty() == true)
535 string hash
, filename
;
536 unsigned long long size
;
537 std::stringstream
ss(tmp
);
539 while (ss
>> hash
>> size
>> filename
)
541 if (unlikely(hash
.empty() == true || filename
.empty() == true))
544 // see if we have a record for this file already
545 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
546 for (; cur
!= available_patches
.end(); ++cur
)
548 if (cur
->file
!= filename
)
550 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
552 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
553 cur
->patch_size
= size
;
556 if (cur
!= available_patches
.end())
559 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
560 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
565 bool foundStart
= false;
566 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
567 cur
!= available_patches
.end(); ++cur
)
569 if (LocalHashes
!= cur
->result_hashes
)
572 available_patches
.erase(available_patches
.begin(), cur
);
577 if (foundStart
== false || unlikely(available_patches
.empty() == true))
580 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
581 << "Couldn't find the start of the patch series." << std::endl
;
585 // patching with too many files is rather slow compared to a fast download
586 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
587 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
590 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
591 << ") so fallback to complete download" << std::endl
;
595 // calculate the size of all patches we have to get
596 // note that all sizes are uncompressed, while we download compressed files
597 unsigned long long patchesSize
= 0;
598 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
599 cur
!= available_patches
.end(); ++cur
)
600 patchesSize
+= cur
->patch_size
;
601 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
602 if (false && sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
605 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
606 << ") so fallback to complete download" << std::endl
;
610 // FIXME: make this use the method
611 PackagesFileReadyInPartial
= true;
612 std::string
const Partial
= GetPartialFileNameFromURI(RealURI
);
614 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
615 FileFd
To(Partial
, FileFd::WriteEmpty
);
616 if(CopyFile(From
, To
) == false)
617 return _error
->Errno("CopyFile", "failed to copy");
620 std::cerr
<< "Done copying " << CurrentPackagesFile
624 // we have something, queue the diffs
625 string::size_type
const last_space
= Description
.rfind(" ");
626 if(last_space
!= string::npos
)
627 Description
.erase(last_space
, Description
.size()-last_space
);
629 /* decide if we should download patches one by one or in one go:
630 The first is good if the server merges patches, but many don't so client
631 based merging can be attempt in which case the second is better.
632 "bad things" will happen if patches are merged on the server,
633 but client side merging is attempt as well */
634 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
635 if (pdiff_merge
== true)
637 // reprepro adds this flag if it has merged patches on the server
638 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
639 pdiff_merge
= (precedence
!= "merged");
642 if (pdiff_merge
== false)
644 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
645 MetaIndexParser
, available_patches
);
649 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
650 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
651 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
655 available_patches
[i
],
665 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
668 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
669 << "Falling back to normal index file acquire" << std::endl
;
671 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
673 Item::Failed(Message
,Cnf
);
677 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
678 pkgAcquire::MethodConfig
*Cnf
)
681 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
683 Item::Done(Message
, Size
, Hashes
, Cnf
);
685 // verify the index target
686 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
688 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
689 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
690 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
692 RenameOnError(HashSumMismatch
);
693 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
694 Failed(Message
, Cnf
);
701 FinalFile
= _config
->FindDir("Dir::State::lists");
702 FinalFile
+= URItoFileName(Desc
.URI
);
704 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
705 DestFile
= FinalFile
;
707 if(!ParseDiffIndex(DestFile
))
708 return Failed("Message: Couldn't parse pdiff index", Cnf
);
710 // queue for final move
711 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
719 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
720 // ---------------------------------------------------------------------
721 /* The package diff is added to the queue. one object is constructed
722 * for each diff and the index
724 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
725 pkgAcqMetaBase
*TransactionManager
,
726 struct IndexTarget
const * const Target
,
727 HashStringList
const &ExpectedHashes
,
728 indexRecords
*MetaIndexParser
,
729 vector
<DiffInfo
> diffs
)
730 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
731 available_patches(diffs
)
733 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
735 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
737 RealURI
= Target
->URI
;
739 Description
= Target
->Description
;
740 Desc
.ShortDesc
= Target
->ShortDesc
;
742 if(available_patches
.empty() == true)
744 // we are done (yeah!), check hashes against the final file
745 DestFile
= _config
->FindDir("Dir::State::lists");
746 DestFile
+= URItoFileName(Target
->URI
);
752 State
= StateFetchDiff
;
757 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
760 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
761 << "Falling back to normal index file acquire" << std::endl
;
762 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
766 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
767 void pkgAcqIndexDiffs::Finish(bool allDone
)
770 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
772 << Desc
.URI
<< std::endl
;
774 // we restore the original name, this is required, otherwise
775 // the file will be cleaned
778 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
780 RenameOnError(HashSumMismatch
);
786 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
787 FinalFile
+= URItoFileName(RealURI
);
788 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
790 // this is for the "real" finish
795 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
800 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
807 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
809 // calc sha1 of the just patched file
810 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
812 if(!FileExists(FinalFile
))
814 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
818 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
819 Hashes LocalHashesCalc
;
820 LocalHashesCalc
.AddFD(fd
);
821 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
824 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
826 if (unlikely(LocalHashes
.usable() == false || ExpectedHashes
.usable() == false))
828 Failed("Local/Expected hashes are not usable", NULL
);
833 // final file reached before all patches are applied
834 if(LocalHashes
== ExpectedHashes
)
840 // remove all patches until the next matching patch is found
841 // this requires the Index file to be ordered
842 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
843 available_patches
.empty() == false &&
844 I
!= available_patches
.end() &&
845 I
->result_hashes
!= LocalHashes
;
848 available_patches
.erase(I
);
851 // error checking and falling back if no patch was found
852 if(available_patches
.empty() == true)
854 Failed("No patches left to reach target", NULL
);
858 // queue the right diff
859 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
860 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
861 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
864 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
871 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
872 pkgAcquire::MethodConfig
*Cnf
)
875 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
877 Item::Done(Message
, Size
, Hashes
, Cnf
);
879 // FIXME: verify this download too before feeding it to rred
880 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
882 // success in downloading a diff, enter ApplyDiff state
883 if(State
== StateFetchDiff
)
885 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
886 class Hashes LocalHashesCalc
;
887 LocalHashesCalc
.AddFD(fd
);
888 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
890 if (fd
.Size() != available_patches
[0].patch_size
||
891 available_patches
[0].patch_hashes
!= LocalHashes
)
893 Failed("Patch has Size/Hashsum mismatch", NULL
);
897 // rred excepts the patch as $FinalFile.ed
898 Rename(DestFile
,FinalFile
+".ed");
901 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
903 State
= StateApplyDiff
;
905 Desc
.URI
= "rred:" + FinalFile
;
907 SetActiveSubprocess("rred");
912 // success in download/apply a diff, queue next (if needed)
913 if(State
== StateApplyDiff
)
915 // remove the just applied patch
916 available_patches
.erase(available_patches
.begin());
917 unlink((FinalFile
+ ".ed").c_str());
922 std::clog
<< "Moving patched file in place: " << std::endl
923 << DestFile
<< " -> " << FinalFile
<< std::endl
;
925 Rename(DestFile
,FinalFile
);
926 chmod(FinalFile
.c_str(),0644);
928 // see if there is more to download
929 if(available_patches
.empty() == false) {
930 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
931 ExpectedHashes
, MetaIndexParser
,
936 DestFile
= FinalFile
;
941 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
942 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
943 pkgAcqMetaBase
*TransactionManager
,
944 struct IndexTarget
const * const Target
,
945 HashStringList
const &ExpectedHashes
,
946 indexRecords
*MetaIndexParser
,
947 DiffInfo
const &patch
,
948 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
949 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
950 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
952 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
954 RealURI
= Target
->URI
;
956 Description
= Target
->Description
;
957 Desc
.ShortDesc
= Target
->ShortDesc
;
959 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
960 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
962 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + patch
.file
);
965 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
970 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
973 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
975 Item::Failed(Message
,Cnf
);
978 // check if we are the first to fail, otherwise we are done here
979 State
= StateDoneDiff
;
980 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
981 I
!= allPatches
->end(); ++I
)
982 if ((*I
)->State
== StateErrorDiff
)
985 // first failure means we should fallback
986 State
= StateErrorDiff
;
987 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
988 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
991 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
992 pkgAcquire::MethodConfig
*Cnf
)
995 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
997 Item::Done(Message
,Size
,Hashes
,Cnf
);
999 // FIXME: verify download before feeding it to rred
1000 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1002 if (State
== StateFetchDiff
)
1004 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1005 class Hashes LocalHashesCalc
;
1006 LocalHashesCalc
.AddFD(fd
);
1007 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1009 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1011 Failed("Patch has Size/Hashsum mismatch", NULL
);
1015 // rred expects the patch as $FinalFile.ed.$patchname.gz
1016 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1018 // check if this is the last completed diff
1019 State
= StateDoneDiff
;
1020 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1021 I
!= allPatches
->end(); ++I
)
1022 if ((*I
)->State
!= StateDoneDiff
)
1025 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1029 // this is the last completed diff, so we are ready to apply now
1030 State
= StateApplyDiff
;
1033 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1036 Desc
.URI
= "rred:" + FinalFile
;
1038 SetActiveSubprocess("rred");
1041 // success in download/apply all diffs, clean up
1042 else if (State
== StateApplyDiff
)
1044 // see if we really got the expected file
1045 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
1047 RenameOnError(HashSumMismatch
);
1052 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1053 FinalFile
+= URItoFileName(RealURI
);
1055 // move the result into place
1057 std::clog
<< "Queue patched file in place: " << std::endl
1058 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1060 // queue for copy by the transaction manager
1061 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1063 // ensure the ed's are gone regardless of list-cleanup
1064 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1065 I
!= allPatches
->end(); ++I
)
1067 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1068 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1069 std::cerr
<< patch
<< std::endl
;
1070 unlink(patch
.c_str());
1076 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1080 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1081 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1083 if(MetaKey
!= "" && Hashes
.usable())
1085 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1086 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1088 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1095 // AcqIndex::AcqIndex - Constructor /*{{{*/
1096 // ---------------------------------------------------------------------
1097 /* The package file is added to the queue and a second class is
1098 instantiated to fetch the revision file */
1099 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1100 string URI
,string URIDesc
,string ShortDesc
,
1101 HashStringList
const &ExpectedHash
)
1102 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1106 AutoSelectCompression();
1107 Init(URI
, URIDesc
, ShortDesc
);
1109 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1110 std::clog
<< "New pkgIndex with TransactionManager "
1111 << TransactionManager
<< std::endl
;
1114 // AcqIndex::AcqIndex - Constructor /*{{{*/
1115 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1116 pkgAcqMetaBase
*TransactionManager
,
1117 IndexTarget
const *Target
,
1118 HashStringList
const &ExpectedHash
,
1119 indexRecords
*MetaIndexParser
)
1120 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1123 RealURI
= Target
->URI
;
1125 // autoselect the compression method
1126 AutoSelectCompression();
1127 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1129 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1130 std::clog
<< "New pkgIndex with TransactionManager "
1131 << TransactionManager
<< std::endl
;
1134 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1135 void pkgAcqIndex::AutoSelectCompression()
1137 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1138 CompressionExtensions
= "";
1139 if (ExpectedHashes
.usable())
1141 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1142 t
!= types
.end(); ++t
)
1144 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1145 if (*t
== "uncompressed" ||
1146 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1147 CompressionExtensions
.append(*t
).append(" ");
1152 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1153 CompressionExtensions
.append(*t
).append(" ");
1155 if (CompressionExtensions
.empty() == false)
1156 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1159 // AcqIndex::Init - defered Constructor /*{{{*/
1160 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1161 string
const &ShortDesc
)
1163 Stage
= STAGE_DOWNLOAD
;
1165 DestFile
= GetPartialFileNameFromURI(URI
);
1167 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1168 if (CurrentCompressionExtension
== "uncompressed")
1172 MetaKey
= string(Target
->MetaKey
);
1176 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1177 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1179 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1182 // load the filesize
1185 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1187 FileSize
= Record
->Size
;
1189 InitByHashIfNeeded(MetaKey
);
1192 Desc
.Description
= URIDesc
;
1194 Desc
.ShortDesc
= ShortDesc
;
1199 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1200 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1203 // - (maybe?) add support for by-hash into the sources.list as flag
1204 // - make apt-ftparchive generate the hashes (and expire?)
1205 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1206 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1207 _config
->FindB(HostKnob
, false) == true ||
1208 MetaIndexParser
->GetSupportsAcquireByHash())
1210 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1213 // FIXME: should we really use the best hash here? or a fixed one?
1214 const HashString
*TargetHash
= Record
->Hashes
.find("");
1215 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1216 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1217 Desc
.URI
= Desc
.URI
.replace(
1219 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1223 "Fetching ByHash requested but can not find record for %s",
1229 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1230 // ---------------------------------------------------------------------
1231 /* The only header we use is the last-modified header. */
1232 string
pkgAcqIndex::Custom600Headers() const
1234 string Final
= GetFinalFilename();
1236 string msg
= "\nIndex-File: true";
1238 if (stat(Final
.c_str(),&Buf
) == 0)
1239 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1244 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1245 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1247 size_t const nextExt
= CompressionExtensions
.find(' ');
1248 if (nextExt
!= std::string::npos
)
1250 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1251 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1255 // on decompression failure, remove bad versions in partial/
1256 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1258 unlink(EraseFileName
.c_str());
1261 Item::Failed(Message
,Cnf
);
1263 /// cancel the entire transaction
1264 TransactionManager
->AbortTransaction();
1267 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1268 std::string
pkgAcqIndex::GetFinalFilename() const
1270 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1271 FinalFile
+= URItoFileName(RealURI
);
1272 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1273 FinalFile
+= '.' + CurrentCompressionExtension
;
1277 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1278 void pkgAcqIndex::ReverifyAfterIMS()
1280 // update destfile to *not* include the compression extension when doing
1281 // a reverify (as its uncompressed on disk already)
1282 DestFile
= GetPartialFileNameFromURI(RealURI
);
1284 // adjust DestFile if its compressed on disk
1285 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
1286 DestFile
+= '.' + CurrentCompressionExtension
;
1288 // copy FinalFile into partial/ so that we check the hash again
1289 string FinalFile
= GetFinalFilename();
1290 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1291 Desc
.URI
= "copy:" + FinalFile
;
1295 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1296 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1298 // FIXME: this can go away once we only ever download stuff that
1299 // has a valid hash and we never do GET based probing
1300 // FIXME2: this also leaks debian-isms into the code and should go therefore
1302 /* Always validate the index file for correctness (all indexes must
1303 * have a Package field) (LP: #346386) (Closes: #627642)
1305 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1306 // Only test for correctness if the content of the file is not empty
1311 pkgTagFile
tag(&fd
);
1313 // all our current indexes have a field 'Package' in each section
1314 if (_error
->PendingError() == true ||
1315 tag
.Step(sec
) == false ||
1316 sec
.Exists("Package") == false)
1322 // AcqIndex::Done - Finished a fetch /*{{{*/
1323 // ---------------------------------------------------------------------
1324 /* This goes through a number of states.. On the initial fetch the
1325 method could possibly return an alternate filename which points
1326 to the uncompressed version of the file. If this is so the file
1327 is copied into the partial directory. In all other cases the file
1328 is decompressed with a compressed uri. */
1329 void pkgAcqIndex::Done(string Message
,
1330 unsigned long long Size
,
1331 HashStringList
const &Hashes
,
1332 pkgAcquire::MethodConfig
*Cfg
)
1334 Item::Done(Message
,Size
,Hashes
,Cfg
);
1338 case STAGE_DOWNLOAD
:
1339 StageDownloadDone(Message
, Hashes
, Cfg
);
1341 case STAGE_DECOMPRESS_AND_VERIFY
:
1342 StageDecompressDone(Message
, Hashes
, Cfg
);
1347 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1348 void pkgAcqIndex::StageDownloadDone(string Message
,
1349 HashStringList
const &Hashes
,
1350 pkgAcquire::MethodConfig
*Cfg
)
1352 // First check if the calculcated Hash of the (compressed) downloaded
1353 // file matches the hash we have in the MetaIndexRecords for this file
1354 if(VerifyHashByMetaKey(Hashes
) == false)
1356 RenameOnError(HashSumMismatch
);
1357 Failed(Message
, Cfg
);
1363 // Handle the unzipd case
1364 string FileName
= LookupTag(Message
,"Alt-Filename");
1365 if (FileName
.empty() == false)
1367 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1369 DestFile
+= ".decomp";
1370 Desc
.URI
= "copy:" + FileName
;
1372 SetActiveSubprocess("copy");
1376 FileName
= LookupTag(Message
,"Filename");
1377 if (FileName
.empty() == true)
1380 ErrorText
= "Method gave a blank filename";
1383 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1384 // not the "DestFile" we set, in this case we uncompress from the local file
1385 if (FileName
!= DestFile
)
1388 EraseFileName
= FileName
;
1390 // we need to verify the file against the current Release file again
1391 // on if-modfied-since hit to avoid a stale attack against us
1392 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1394 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
1395 // file when its doing the indexcopy
1396 if (RealURI
.substr(0,6) == "cdrom:")
1399 // The files timestamp matches, reverify by copy into partial/
1405 // If we have compressed indexes enabled, queue for hash verification
1406 if (_config
->FindB("Acquire::GzipIndexes",false))
1408 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1410 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1411 Desc
.URI
= "copy:" + FileName
;
1413 SetActiveSubprocess("copy");
1417 // get the binary name for your used compression type
1419 if(CurrentCompressionExtension
== "uncompressed")
1420 decompProg
= "copy";
1422 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1423 if(decompProg
.empty() == true)
1425 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1429 // queue uri for the next stage
1430 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1431 DestFile
+= ".decomp";
1432 Desc
.URI
= decompProg
+ ":" + FileName
;
1434 SetActiveSubprocess(decompProg
);
1437 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1438 void pkgAcqIndex::StageDecompressDone(string Message
,
1439 HashStringList
const &Hashes
,
1440 pkgAcquire::MethodConfig
*Cfg
)
1442 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1445 RenameOnError(HashSumMismatch
);
1446 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1447 Failed(Message
, Cfg
);
1451 if(!ValidateFile(DestFile
))
1453 RenameOnError(InvalidFormat
);
1454 Failed(Message
, Cfg
);
1458 // remove the compressed version of the file
1459 unlink(EraseFileName
.c_str());
1461 // Done, queue for rename on transaction finished
1462 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1467 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1468 // ---------------------------------------------------------------------
1469 /* The Translation file is added to the queue */
1470 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1471 string URI
,string URIDesc
,string ShortDesc
)
1472 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1475 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1476 pkgAcqMetaBase
*TransactionManager
,
1477 IndexTarget
const * const Target
,
1478 HashStringList
const &ExpectedHashes
,
1479 indexRecords
*MetaIndexParser
)
1480 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1482 // load the filesize
1483 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(string(Target
->MetaKey
));
1485 FileSize
= Record
->Size
;
1488 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1489 string
pkgAcqIndexTrans::Custom600Headers() const
1491 string Final
= GetFinalFilename();
1494 if (stat(Final
.c_str(),&Buf
) != 0)
1495 return "\nFail-Ignore: true\nIndex-File: true";
1496 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1499 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1500 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1502 size_t const nextExt
= CompressionExtensions
.find(' ');
1503 if (nextExt
!= std::string::npos
)
1505 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1506 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1511 Item::Failed(Message
,Cnf
);
1513 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1514 if (Cnf
->LocalOnly
== true ||
1515 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1522 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1523 void pkgAcqMetaBase::Add(Item
*I
)
1525 Transaction
.push_back(I
);
1528 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1529 void pkgAcqMetaBase::AbortTransaction()
1531 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1532 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1534 // ensure the toplevel is in error state too
1535 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1536 I
!= Transaction
.end(); ++I
)
1538 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1539 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1540 // the transaction will abort, so stop anything that is idle
1541 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1542 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1544 // kill files in partial
1545 std::string
const PartialFile
= GetPartialFileName(flNotDir((*I
)->DestFile
));
1546 if(FileExists(PartialFile
))
1547 Rename(PartialFile
, PartialFile
+ ".FAILED");
1551 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1552 bool pkgAcqMetaBase::TransactionHasError()
1554 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1555 I
!= Transaction
.end(); ++I
)
1556 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1557 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1563 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1564 void pkgAcqMetaBase::CommitTransaction()
1566 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1567 std::clog
<< "CommitTransaction: " << this << std::endl
;
1569 // move new files into place *and* remove files that are not
1570 // part of the transaction but are still on disk
1571 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1572 I
!= Transaction
.end(); ++I
)
1574 if((*I
)->PartialFile
!= "")
1576 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1577 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1578 << (*I
)->DescURI() << std::endl
;
1580 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1581 ChangeOwnerAndPermissionOfFile("CommitTransaction", (*I
)->DestFile
.c_str(), "root", "root", 0644);
1584 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1590 unlink((*I
)->DestFile
.c_str());
1592 // mark that this transaction is finished
1593 (*I
)->TransactionManager
= 0;
1597 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1598 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1599 const std::string
&From
,
1600 const std::string
&To
)
1602 I
->PartialFile
= From
;
1606 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1607 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1608 const std::string
&FinalFile
)
1610 I
->PartialFile
= "";
1611 I
->DestFile
= FinalFile
;
1614 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1615 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&RealURI
,
1616 const std::string
&Message
)
1618 // FIXME: this entire function can do now that we disallow going to
1619 // a unauthenticated state and can cleanly rollback
1621 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1623 if(FileExists(Final
))
1625 Status
= StatTransientNetworkError
;
1626 _error
->Warning(_("An error occurred during the signature "
1627 "verification. The repository is not updated "
1628 "and the previous index files will be used. "
1629 "GPG error: %s: %s\n"),
1630 Desc
.Description
.c_str(),
1631 LookupTag(Message
,"Message").c_str());
1632 RunScripts("APT::Update::Auth-Failure");
1634 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1635 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1636 _error
->Error(_("GPG error: %s: %s"),
1637 Desc
.Description
.c_str(),
1638 LookupTag(Message
,"Message").c_str());
1642 _error
->Warning(_("GPG error: %s: %s"),
1643 Desc
.Description
.c_str(),
1644 LookupTag(Message
,"Message").c_str());
1646 // gpgv method failed
1647 ReportMirrorFailure("GPGFailure");
1651 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1652 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1653 pkgAcqMetaBase
*TransactionManager
,
1654 string URI
,string URIDesc
,string ShortDesc
,
1655 string MetaIndexFile
,
1656 const vector
<IndexTarget
*>* IndexTargets
,
1657 indexRecords
* MetaIndexParser
) :
1658 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1659 HashStringList(), TransactionManager
),
1660 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1661 ShortDesc(ShortDesc
)
1663 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1664 DestFile
+= URItoFileName(RealURI
);
1666 // remove any partial downloaded sig-file in partial/.
1667 // it may confuse proxies and is too small to warrant a
1668 // partial download anyway
1669 unlink(DestFile
.c_str());
1671 // set the TransactionManager
1672 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1673 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1674 << TransactionManager
<< std::endl
;
1677 Desc
.Description
= URIDesc
;
1679 Desc
.ShortDesc
= ShortDesc
;
1685 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1689 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1690 // ---------------------------------------------------------------------
1691 string
pkgAcqMetaSig::Custom600Headers() const
1693 std::string Header
= GetCustom600Headers(RealURI
);
1697 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1698 // ---------------------------------------------------------------------
1699 /* The only header we use is the last-modified header. */
1700 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1701 HashStringList
const &Hashes
,
1702 pkgAcquire::MethodConfig
*Cfg
)
1704 Item::Done(Message
, Size
, Hashes
, Cfg
);
1706 if(AuthPass
== false)
1708 if(CheckDownloadDone(Message
, RealURI
) == true)
1710 // destfile will be modified to point to MetaIndexFile for the
1711 // gpgv method, so we need to save it here
1712 MetaIndexFileSignature
= DestFile
;
1713 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1719 if(CheckAuthDone(Message
, RealURI
) == true)
1721 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1722 FinalFile
+= URItoFileName(RealURI
);
1723 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1728 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1730 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1732 // check if we need to fail at this point
1733 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1736 // FIXME: meh, this is not really elegant
1737 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1739 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1741 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1743 std::string downgrade_msg
;
1744 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1746 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1748 // meh, the users wants to take risks (we still mark the packages
1749 // from this repository as unauthenticated)
1750 _error
->Warning("%s", downgrade_msg
.c_str());
1751 _error
->Warning(_("This is normally not allowed, but the option "
1752 "Acquire::AllowDowngradeToInsecureRepositories was "
1753 "given to override it."));
1756 _error
->Error("%s", downgrade_msg
.c_str());
1757 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1758 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1759 TransactionManager
->AbortTransaction();
1764 // this ensures that any file in the lists/ dir is removed by the
1766 DestFile
= GetPartialFileNameFromURI(RealURI
);
1767 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1769 // only allow going further if the users explicitely wants it
1770 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
1772 // we parse the indexes here because at this point the user wanted
1773 // a repository that may potentially harm him
1774 MetaIndexParser
->Load(MetaIndexFile
);
1779 _error
->Warning("Use --allow-insecure-repositories to force the update");
1782 Item::Failed(Message
,Cnf
);
1784 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1785 if (Cnf
->LocalOnly
== true ||
1786 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1793 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1794 pkgAcqMetaBase
*TransactionManager
,
1795 string URI
,string URIDesc
,string ShortDesc
,
1796 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1797 const vector
<IndexTarget
*>* IndexTargets
,
1798 indexRecords
* MetaIndexParser
) :
1799 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1800 TransactionManager
),
1801 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1802 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1803 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1805 if(TransactionManager
== NULL
)
1807 this->TransactionManager
= this;
1808 this->TransactionManager
->Add(this);
1811 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1812 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1813 << this->TransactionManager
<< std::endl
;
1816 Init(URIDesc
, ShortDesc
);
1819 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1820 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1822 DestFile
= GetPartialFileNameFromURI(RealURI
);
1825 Desc
.Description
= URIDesc
;
1827 Desc
.ShortDesc
= ShortDesc
;
1830 // we expect more item
1831 ExpectedAdditionalItems
= IndexTargets
->size();
1835 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1836 // ---------------------------------------------------------------------
1837 string
pkgAcqMetaIndex::Custom600Headers() const
1839 return GetCustom600Headers(RealURI
);
1842 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1843 HashStringList
const &Hashes
,
1844 pkgAcquire::MethodConfig
*Cfg
)
1846 Item::Done(Message
,Size
,Hashes
,Cfg
);
1848 if(CheckDownloadDone(Message
, RealURI
))
1850 // we have a Release file, now download the Signature, all further
1851 // verify/queue for additional downloads will be done in the
1852 // pkgAcqMetaSig::Done() code
1853 std::string MetaIndexFile
= DestFile
;
1854 new pkgAcqMetaSig(Owner
, TransactionManager
,
1855 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1856 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1859 string FinalFile
= _config
->FindDir("Dir::State::lists");
1860 FinalFile
+= URItoFileName(RealURI
);
1861 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1865 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1867 // At this point, the gpgv method has succeeded, so there is a
1868 // valid signature from a key in the trusted keyring. We
1869 // perform additional verification of its contents, and use them
1870 // to verify the indexes we are about to download
1872 if (!MetaIndexParser
->Load(DestFile
))
1874 Status
= StatAuthError
;
1875 ErrorText
= MetaIndexParser
->ErrorText
;
1879 if (!VerifyVendor(Message
, RealURI
))
1884 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1885 std::cerr
<< "Signature verification succeeded: "
1886 << DestFile
<< std::endl
;
1888 // Download further indexes with verification
1890 // it would be really nice if we could simply do
1891 // if (IMSHit == false) QueueIndexes(true)
1892 // and skip the download if the Release file has not changed
1893 // - but right now the list cleaner will needs to be tricked
1894 // to not delete all our packages/source indexes in this case
1900 // pkgAcqMetaBase::GetCustom600Headers - Get header for AcqMetaBase /*{{{*/
1901 // ---------------------------------------------------------------------
1902 string
pkgAcqMetaBase::GetCustom600Headers(const string
&RealURI
) const
1904 std::string Header
= "\nIndex-File: true";
1905 std::string MaximumSize
;
1906 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1907 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1908 Header
+= MaximumSize
;
1910 string FinalFile
= _config
->FindDir("Dir::State::lists");
1911 FinalFile
+= URItoFileName(RealURI
);
1914 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1915 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1920 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1921 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1922 const std::string
&MetaIndexFileSignature
)
1925 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1926 DestFile
= MetaIndexFile
;
1928 SetActiveSubprocess("gpgv");
1931 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1932 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1933 const std::string
&RealURI
)
1935 // We have just finished downloading a Release file (it is not
1938 string FileName
= LookupTag(Message
,"Filename");
1939 if (FileName
.empty() == true)
1942 ErrorText
= "Method gave a blank filename";
1946 if (FileName
!= DestFile
)
1949 Desc
.URI
= "copy:" + FileName
;
1954 // make sure to verify against the right file on I-M-S hit
1955 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1958 string FinalFile
= _config
->FindDir("Dir::State::lists");
1959 FinalFile
+= URItoFileName(RealURI
);
1960 DestFile
= FinalFile
;
1963 // set Item to complete as the remaining work is all local (verify etc)
1969 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1971 bool transInRelease
= false;
1973 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1974 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1975 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1976 if (k
->find("Translation-") != std::string::npos
)
1978 transInRelease
= true;
1983 // at this point the real Items are loaded in the fetcher
1984 ExpectedAdditionalItems
= 0;
1985 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1986 Target
!= IndexTargets
->end();
1989 HashStringList ExpectedIndexHashes
;
1990 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1991 bool compressedAvailable
= false;
1994 if ((*Target
)->IsOptional() == true)
1996 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1997 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1998 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
2000 compressedAvailable
= true;
2004 else if (verify
== true)
2006 Status
= StatAuthError
;
2007 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2013 ExpectedIndexHashes
= Record
->Hashes
;
2014 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2016 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2017 << "Expected Hash:" << std::endl
;
2018 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2019 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2020 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
2022 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
2024 Status
= StatAuthError
;
2025 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2030 if ((*Target
)->IsOptional() == true)
2032 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
2034 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
2035 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
2036 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2038 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2043 /* Queue Packages file (either diff or full packages files, depending
2044 on the users option) - we also check if the PDiff Index file is listed
2045 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2046 instead, but passing the required info to it is to much hassle */
2047 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2048 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2049 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2051 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2055 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
2057 string::size_type pos
;
2059 // check for missing sigs (that where not fatal because otherwise we had
2062 string msg
= _("There is no public key available for the "
2063 "following key IDs:\n");
2064 pos
= Message
.find("NO_PUBKEY ");
2065 if (pos
!= std::string::npos
)
2067 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2068 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2069 missingkeys
+= (Fingerprint
);
2071 if(!missingkeys
.empty())
2072 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2074 string Transformed
= MetaIndexParser
->GetExpectedDist();
2076 if (Transformed
== "../project/experimental")
2078 Transformed
= "experimental";
2081 pos
= Transformed
.rfind('/');
2082 if (pos
!= string::npos
)
2084 Transformed
= Transformed
.substr(0, pos
);
2087 if (Transformed
== ".")
2092 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2093 MetaIndexParser
->GetValidUntil() > 0) {
2094 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2095 if (invalid_since
> 0)
2096 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2097 // the time since then the file is invalid - formated in the same way as in
2098 // the download progress display (e.g. 7d 3h 42min 1s)
2099 return _error
->Error(
2100 _("Release file for %s is expired (invalid since %s). "
2101 "Updates for this repository will not be applied."),
2102 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2105 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2107 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2108 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2109 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2112 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2114 // This might become fatal one day
2115 // Status = StatAuthError;
2116 // ErrorText = "Conflicting distribution; expected "
2117 // + MetaIndexParser->GetExpectedDist() + " but got "
2118 // + MetaIndexParser->GetDist();
2120 if (!Transformed
.empty())
2122 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2123 Desc
.Description
.c_str(),
2124 Transformed
.c_str(),
2125 MetaIndexParser
->GetDist().c_str());
2132 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2133 void pkgAcqMetaIndex::Failed(string Message
,
2134 pkgAcquire::MethodConfig
* Cnf
)
2136 pkgAcquire::Item::Failed(Message
, Cnf
);
2139 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2141 _error
->Warning(_("The repository '%s' does not have a Release file. "
2142 "This is deprecated, please contact the owner of the "
2143 "repository."), URIDesc
.c_str());
2145 // No Release file was present so fall
2146 // back to queueing Packages files without verification
2147 // only allow going further if the users explicitely wants it
2148 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2150 // Done, queue for rename on transaction finished
2151 if (FileExists(DestFile
))
2152 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2154 // queue without any kind of hashsum support
2155 QueueIndexes(false);
2157 // warn if the repository is unsinged
2158 _error
->Warning("Use --allow-insecure-repositories to force the update");
2159 TransactionManager
->AbortTransaction();
2165 void pkgAcqMetaIndex::Finished() /*{{{*/
2167 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2168 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2169 if(TransactionManager
!= NULL
&&
2170 TransactionManager
->TransactionHasError() == false)
2171 TransactionManager
->CommitTransaction();
2174 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2175 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2176 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2177 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2178 const vector
<IndexTarget
*>* IndexTargets
,
2179 indexRecords
* MetaIndexParser
) :
2180 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2181 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2182 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2184 // index targets + (worst case:) Release/Release.gpg
2185 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2189 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2193 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2194 // ---------------------------------------------------------------------
2195 string
pkgAcqMetaClearSig::Custom600Headers() const
2197 string Header
= GetCustom600Headers(RealURI
);
2198 Header
+= "\nFail-Ignore: true";
2202 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2203 // ---------------------------------------------------------------------
2204 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long /*Size*/,
2205 HashStringList
const &/*Hashes*/,
2206 pkgAcquire::MethodConfig
*Cnf
)
2208 // if we expect a ClearTextSignature (InRelase), ensure that
2209 // this is what we get and if not fail to queue a
2210 // Release/Release.gpg, see #346386
2211 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2213 pkgAcquire::Item::Failed(Message
, Cnf
);
2214 RenameOnError(NotClearsigned
);
2215 TransactionManager
->AbortTransaction();
2219 if(AuthPass
== false)
2221 if(CheckDownloadDone(Message
, RealURI
) == true)
2222 QueueForSignatureVerify(DestFile
, DestFile
);
2227 if(CheckAuthDone(Message
, RealURI
) == true)
2229 string FinalFile
= _config
->FindDir("Dir::State::lists");
2230 FinalFile
+= URItoFileName(RealURI
);
2232 // queue for copy in place
2233 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2238 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2240 Item::Failed(Message
, Cnf
);
2242 // we failed, we will not get additional items from this method
2243 ExpectedAdditionalItems
= 0;
2245 if (AuthPass
== false)
2247 // Queue the 'old' InRelease file for removal if we try Release.gpg
2248 // as otherwise the file will stay around and gives a false-auth
2249 // impression (CVE-2012-0214)
2250 string FinalFile
= _config
->FindDir("Dir::State::lists");
2251 FinalFile
.append(URItoFileName(RealURI
));
2252 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2255 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2256 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2257 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2258 IndexTargets
, MetaIndexParser
);
2262 if(CheckStopAuthentication(RealURI
, Message
))
2265 _error
->Warning(_("The data from '%s' is not signed. Packages "
2266 "from that repository can not be authenticated."),
2269 // No Release file was present, or verification failed, so fall
2270 // back to queueing Packages files without verification
2271 // only allow going further if the users explicitely wants it
2272 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2276 /* Always move the meta index, even if gpgv failed. This ensures
2277 * that PackageFile objects are correctly filled in */
2278 if (FileExists(DestFile
))
2280 string FinalFile
= _config
->FindDir("Dir::State::lists");
2281 FinalFile
+= URItoFileName(RealURI
);
2282 /* InRelease files become Release files, otherwise
2283 * they would be considered as trusted later on */
2284 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2286 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2289 // Done, queue for rename on transaction finished
2290 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2292 QueueIndexes(false);
2294 // warn if the repository is unsigned
2295 _error
->Warning("Use --allow-insecure-repositories to force the update");
2296 TransactionManager
->AbortTransaction();
2302 // AcqArchive::AcqArchive - Constructor /*{{{*/
2303 // ---------------------------------------------------------------------
2304 /* This just sets up the initial fetch environment and queues the first
2306 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2307 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2308 string
&StoreFilename
) :
2309 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2310 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2313 Retries
= _config
->FindI("Acquire::Retries",0);
2315 if (Version
.Arch() == 0)
2317 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2318 "This might mean you need to manually fix this package. "
2319 "(due to missing arch)"),
2320 Version
.ParentPkg().FullName().c_str());
2324 /* We need to find a filename to determine the extension. We make the
2325 assumption here that all the available sources for this version share
2326 the same extension.. */
2327 // Skip not source sources, they do not have file fields.
2328 for (; Vf
.end() == false; ++Vf
)
2330 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2335 // Does not really matter here.. we are going to fail out below
2336 if (Vf
.end() != true)
2338 // If this fails to get a file name we will bomb out below.
2339 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2340 if (_error
->PendingError() == true)
2343 // Generate the final file name as: package_version_arch.foo
2344 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2345 QuoteString(Version
.VerStr(),"_:") + '_' +
2346 QuoteString(Version
.Arch(),"_:.") +
2347 "." + flExtension(Parse
.FileName());
2350 // check if we have one trusted source for the package. if so, switch
2351 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2352 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2353 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2354 bool seenUntrusted
= false;
2355 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2357 pkgIndexFile
*Index
;
2358 if (Sources
->FindIndex(i
.File(),Index
) == false)
2361 if (debugAuth
== true)
2362 std::cerr
<< "Checking index: " << Index
->Describe()
2363 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2365 if (Index
->IsTrusted() == true)
2368 if (allowUnauth
== false)
2372 seenUntrusted
= true;
2375 // "allow-unauthenticated" restores apts old fetching behaviour
2376 // that means that e.g. unauthenticated file:// uris are higher
2377 // priority than authenticated http:// uris
2378 if (allowUnauth
== true && seenUntrusted
== true)
2382 if (QueueNext() == false && _error
->PendingError() == false)
2383 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2384 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2387 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2388 // ---------------------------------------------------------------------
2389 /* This queues the next available file version for download. It checks if
2390 the archive is already available in the cache and stashs the MD5 for
2392 bool pkgAcqArchive::QueueNext()
2394 for (; Vf
.end() == false; ++Vf
)
2396 // Ignore not source sources
2397 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2400 // Try to cross match against the source list
2401 pkgIndexFile
*Index
;
2402 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2405 // only try to get a trusted package from another source if that source
2407 if(Trusted
&& !Index
->IsTrusted())
2410 // Grab the text package record
2411 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2412 if (_error
->PendingError() == true)
2415 string PkgFile
= Parse
.FileName();
2416 ExpectedHashes
= Parse
.Hashes();
2418 if (PkgFile
.empty() == true)
2419 return _error
->Error(_("The package index files are corrupted. No Filename: "
2420 "field for package %s."),
2421 Version
.ParentPkg().Name());
2423 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2424 Desc
.Description
= Index
->ArchiveInfo(Version
);
2426 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2428 // See if we already have the file. (Legacy filenames)
2429 FileSize
= Version
->Size
;
2430 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2432 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2434 // Make sure the size matches
2435 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2440 StoreFilename
= DestFile
= FinalFile
;
2444 /* Hmm, we have a file and its size does not match, this means it is
2445 an old style mismatched arch */
2446 unlink(FinalFile
.c_str());
2449 // Check it again using the new style output filenames
2450 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2451 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2453 // Make sure the size matches
2454 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2459 StoreFilename
= DestFile
= FinalFile
;
2463 /* Hmm, we have a file and its size does not match, this shouldn't
2465 unlink(FinalFile
.c_str());
2468 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2470 // Check the destination file
2471 if (stat(DestFile
.c_str(),&Buf
) == 0)
2473 // Hmm, the partial file is too big, erase it
2474 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2475 unlink(DestFile
.c_str());
2478 PartialSize
= Buf
.st_size
;
2479 ChangeOwnerAndPermissionOfFile("pkgAcqArchive::QueueNext", FinalFile
.c_str(), "_apt", "root", 0600);
2483 // Disables download of archives - useful if no real installation follows,
2484 // e.g. if we are just interested in proposed installation order
2485 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2490 StoreFilename
= DestFile
= FinalFile
;
2504 // AcqArchive::Done - Finished fetching /*{{{*/
2505 // ---------------------------------------------------------------------
2507 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2508 pkgAcquire::MethodConfig
*Cfg
)
2510 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2513 if (Size
!= Version
->Size
)
2515 RenameOnError(SizeMismatch
);
2519 // FIXME: could this empty() check impose *any* sort of security issue?
2520 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2522 RenameOnError(HashSumMismatch
);
2523 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2527 // Grab the output filename
2528 string FileName
= LookupTag(Message
,"Filename");
2529 if (FileName
.empty() == true)
2532 ErrorText
= "Method gave a blank filename";
2536 // Reference filename
2537 if (FileName
!= DestFile
)
2539 StoreFilename
= DestFile
= FileName
;
2545 // Done, move it into position
2546 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2547 FinalFile
+= flNotDir(StoreFilename
);
2548 Rename(DestFile
,FinalFile
);
2549 ChangeOwnerAndPermissionOfFile("pkgAcqArchive::Done", FinalFile
.c_str(), "root", "root", 0644);
2550 StoreFilename
= DestFile
= FinalFile
;
2554 // AcqArchive::Failed - Failure handler /*{{{*/
2555 // ---------------------------------------------------------------------
2556 /* Here we try other sources */
2557 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2559 ErrorText
= LookupTag(Message
,"Message");
2561 /* We don't really want to retry on failed media swaps, this prevents
2562 that. An interesting observation is that permanent failures are not
2564 if (Cnf
->Removable
== true &&
2565 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2567 // Vf = Version.FileList();
2568 while (Vf
.end() == false) ++Vf
;
2569 StoreFilename
= string();
2570 Item::Failed(Message
,Cnf
);
2574 if (QueueNext() == false)
2576 // This is the retry counter
2578 Cnf
->LocalOnly
== false &&
2579 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2582 Vf
= Version
.FileList();
2583 if (QueueNext() == true)
2587 StoreFilename
= string();
2588 Item::Failed(Message
,Cnf
);
2592 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2593 // ---------------------------------------------------------------------
2594 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2599 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2600 // ---------------------------------------------------------------------
2602 void pkgAcqArchive::Finished()
2604 if (Status
== pkgAcquire::Item::StatDone
&&
2607 StoreFilename
= string();
2610 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2611 // ---------------------------------------------------------------------
2612 /* The file is added to the queue */
2613 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2614 unsigned long long Size
,string Dsc
,string ShortDesc
,
2615 const string
&DestDir
, const string
&DestFilename
,
2617 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2619 Retries
= _config
->FindI("Acquire::Retries",0);
2621 if(!DestFilename
.empty())
2622 DestFile
= DestFilename
;
2623 else if(!DestDir
.empty())
2624 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2626 DestFile
= flNotDir(URI
);
2630 Desc
.Description
= Dsc
;
2633 // Set the short description to the archive component
2634 Desc
.ShortDesc
= ShortDesc
;
2636 // Get the transfer sizes
2639 if (stat(DestFile
.c_str(),&Buf
) == 0)
2641 // Hmm, the partial file is too big, erase it
2642 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2643 unlink(DestFile
.c_str());
2646 PartialSize
= Buf
.st_size
;
2647 ChangeOwnerAndPermissionOfFile("pkgAcqFile", DestFile
.c_str(), "_apt", "root", 0600);
2654 // AcqFile::Done - Item downloaded OK /*{{{*/
2655 // ---------------------------------------------------------------------
2657 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2658 pkgAcquire::MethodConfig
*Cnf
)
2660 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2663 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2665 RenameOnError(HashSumMismatch
);
2666 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2670 string FileName
= LookupTag(Message
,"Filename");
2671 if (FileName
.empty() == true)
2674 ErrorText
= "Method gave a blank filename";
2680 // The files timestamp matches
2681 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2684 // We have to copy it into place
2685 if (FileName
!= DestFile
)
2688 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2689 Cnf
->Removable
== true)
2691 Desc
.URI
= "copy:" + FileName
;
2696 // Erase the file if it is a symlink so we can overwrite it
2698 if (lstat(DestFile
.c_str(),&St
) == 0)
2700 if (S_ISLNK(St
.st_mode
) != 0)
2701 unlink(DestFile
.c_str());
2705 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2707 ErrorText
= "Link to " + DestFile
+ " failure ";
2714 // AcqFile::Failed - Failure handler /*{{{*/
2715 // ---------------------------------------------------------------------
2716 /* Here we try other sources */
2717 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2719 ErrorText
= LookupTag(Message
,"Message");
2721 // This is the retry counter
2723 Cnf
->LocalOnly
== false &&
2724 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2731 Item::Failed(Message
,Cnf
);
2734 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2735 // ---------------------------------------------------------------------
2736 /* The only header we use is the last-modified header. */
2737 string
pkgAcqFile::Custom600Headers() const
2740 return "\nIndex-File: true";