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 string FinalFile
= _config
->FindDir("Dir::State::lists");
1694 FinalFile
+= URItoFileName(RealURI
);
1697 if (stat(FinalFile
.c_str(),&Buf
) != 0)
1698 return "\nIndex-File: true";
1700 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1703 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1704 // ---------------------------------------------------------------------
1705 /* The only header we use is the last-modified header. */
1706 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1707 HashStringList
const &Hashes
,
1708 pkgAcquire::MethodConfig
*Cfg
)
1710 Item::Done(Message
, Size
, Hashes
, Cfg
);
1712 if(AuthPass
== false)
1714 if(CheckDownloadDone(Message
, RealURI
) == true)
1716 // destfile will be modified to point to MetaIndexFile for the
1717 // gpgv method, so we need to save it here
1718 MetaIndexFileSignature
= DestFile
;
1719 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1725 if(CheckAuthDone(Message
, RealURI
) == true)
1727 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1728 FinalFile
+= URItoFileName(RealURI
);
1729 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1734 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1736 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1738 // check if we need to fail at this point
1739 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1742 // FIXME: meh, this is not really elegant
1743 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1745 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1747 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1749 std::string downgrade_msg
;
1750 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1752 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1754 // meh, the users wants to take risks (we still mark the packages
1755 // from this repository as unauthenticated)
1756 _error
->Warning("%s", downgrade_msg
.c_str());
1757 _error
->Warning(_("This is normally not allowed, but the option "
1758 "Acquire::AllowDowngradeToInsecureRepositories was "
1759 "given to override it."));
1762 _error
->Error("%s", downgrade_msg
.c_str());
1763 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1764 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1765 TransactionManager
->AbortTransaction();
1770 // this ensures that any file in the lists/ dir is removed by the
1772 DestFile
= GetPartialFileNameFromURI(RealURI
);
1773 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1775 // only allow going further if the users explicitely wants it
1776 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
1778 // we parse the indexes here because at this point the user wanted
1779 // a repository that may potentially harm him
1780 MetaIndexParser
->Load(MetaIndexFile
);
1785 _error
->Warning("Use --allow-insecure-repositories to force the update");
1788 Item::Failed(Message
,Cnf
);
1790 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1791 if (Cnf
->LocalOnly
== true ||
1792 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1799 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1800 pkgAcqMetaBase
*TransactionManager
,
1801 string URI
,string URIDesc
,string ShortDesc
,
1802 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1803 const vector
<IndexTarget
*>* IndexTargets
,
1804 indexRecords
* MetaIndexParser
) :
1805 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1806 TransactionManager
),
1807 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1808 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1809 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1811 if(TransactionManager
== NULL
)
1813 this->TransactionManager
= this;
1814 this->TransactionManager
->Add(this);
1817 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1818 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1819 << this->TransactionManager
<< std::endl
;
1822 Init(URIDesc
, ShortDesc
);
1825 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1826 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1828 DestFile
= GetPartialFileNameFromURI(RealURI
);
1831 Desc
.Description
= URIDesc
;
1833 Desc
.ShortDesc
= ShortDesc
;
1836 // we expect more item
1837 ExpectedAdditionalItems
= IndexTargets
->size();
1841 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1842 // ---------------------------------------------------------------------
1843 string
pkgAcqMetaIndex::Custom600Headers() const
1845 string Final
= _config
->FindDir("Dir::State::lists");
1846 Final
+= URItoFileName(RealURI
);
1849 if (stat(Final
.c_str(),&Buf
) != 0)
1850 return "\nIndex-File: true";
1852 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1855 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1856 HashStringList
const &Hashes
,
1857 pkgAcquire::MethodConfig
*Cfg
)
1859 Item::Done(Message
,Size
,Hashes
,Cfg
);
1861 if(CheckDownloadDone(Message
, RealURI
))
1863 // we have a Release file, now download the Signature, all further
1864 // verify/queue for additional downloads will be done in the
1865 // pkgAcqMetaSig::Done() code
1866 std::string MetaIndexFile
= DestFile
;
1867 new pkgAcqMetaSig(Owner
, TransactionManager
,
1868 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1869 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1872 string FinalFile
= _config
->FindDir("Dir::State::lists");
1873 FinalFile
+= URItoFileName(RealURI
);
1874 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1878 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1880 // At this point, the gpgv method has succeeded, so there is a
1881 // valid signature from a key in the trusted keyring. We
1882 // perform additional verification of its contents, and use them
1883 // to verify the indexes we are about to download
1885 if (!MetaIndexParser
->Load(DestFile
))
1887 Status
= StatAuthError
;
1888 ErrorText
= MetaIndexParser
->ErrorText
;
1892 if (!VerifyVendor(Message
, RealURI
))
1897 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1898 std::cerr
<< "Signature verification succeeded: "
1899 << DestFile
<< std::endl
;
1901 // Download further indexes with verification
1903 // it would be really nice if we could simply do
1904 // if (IMSHit == false) QueueIndexes(true)
1905 // and skip the download if the Release file has not changed
1906 // - but right now the list cleaner will needs to be tricked
1907 // to not delete all our packages/source indexes in this case
1913 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1914 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1915 const std::string
&MetaIndexFileSignature
)
1918 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1919 DestFile
= MetaIndexFile
;
1921 SetActiveSubprocess("gpgv");
1924 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1925 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1926 const std::string
&RealURI
)
1928 // We have just finished downloading a Release file (it is not
1931 string FileName
= LookupTag(Message
,"Filename");
1932 if (FileName
.empty() == true)
1935 ErrorText
= "Method gave a blank filename";
1939 if (FileName
!= DestFile
)
1942 Desc
.URI
= "copy:" + FileName
;
1947 // make sure to verify against the right file on I-M-S hit
1948 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1951 string FinalFile
= _config
->FindDir("Dir::State::lists");
1952 FinalFile
+= URItoFileName(RealURI
);
1953 DestFile
= FinalFile
;
1956 // set Item to complete as the remaining work is all local (verify etc)
1962 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
1964 bool transInRelease
= false;
1966 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
1967 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
1968 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
1969 if (k
->find("Translation-") != std::string::npos
)
1971 transInRelease
= true;
1976 // at this point the real Items are loaded in the fetcher
1977 ExpectedAdditionalItems
= 0;
1978 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
1979 Target
!= IndexTargets
->end();
1982 HashStringList ExpectedIndexHashes
;
1983 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
1984 bool compressedAvailable
= false;
1987 if ((*Target
)->IsOptional() == true)
1989 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1990 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1991 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
1993 compressedAvailable
= true;
1997 else if (verify
== true)
1999 Status
= StatAuthError
;
2000 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2006 ExpectedIndexHashes
= Record
->Hashes
;
2007 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2009 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2010 << "Expected Hash:" << std::endl
;
2011 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2012 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2013 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
2015 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
2017 Status
= StatAuthError
;
2018 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2023 if ((*Target
)->IsOptional() == true)
2025 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
2027 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
2028 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
2029 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2031 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2036 /* Queue Packages file (either diff or full packages files, depending
2037 on the users option) - we also check if the PDiff Index file is listed
2038 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2039 instead, but passing the required info to it is to much hassle */
2040 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2041 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2042 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2044 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2048 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
2050 string::size_type pos
;
2052 // check for missing sigs (that where not fatal because otherwise we had
2055 string msg
= _("There is no public key available for the "
2056 "following key IDs:\n");
2057 pos
= Message
.find("NO_PUBKEY ");
2058 if (pos
!= std::string::npos
)
2060 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2061 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2062 missingkeys
+= (Fingerprint
);
2064 if(!missingkeys
.empty())
2065 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2067 string Transformed
= MetaIndexParser
->GetExpectedDist();
2069 if (Transformed
== "../project/experimental")
2071 Transformed
= "experimental";
2074 pos
= Transformed
.rfind('/');
2075 if (pos
!= string::npos
)
2077 Transformed
= Transformed
.substr(0, pos
);
2080 if (Transformed
== ".")
2085 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2086 MetaIndexParser
->GetValidUntil() > 0) {
2087 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2088 if (invalid_since
> 0)
2089 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2090 // the time since then the file is invalid - formated in the same way as in
2091 // the download progress display (e.g. 7d 3h 42min 1s)
2092 return _error
->Error(
2093 _("Release file for %s is expired (invalid since %s). "
2094 "Updates for this repository will not be applied."),
2095 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2098 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2100 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2101 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2102 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2105 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2107 // This might become fatal one day
2108 // Status = StatAuthError;
2109 // ErrorText = "Conflicting distribution; expected "
2110 // + MetaIndexParser->GetExpectedDist() + " but got "
2111 // + MetaIndexParser->GetDist();
2113 if (!Transformed
.empty())
2115 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2116 Desc
.Description
.c_str(),
2117 Transformed
.c_str(),
2118 MetaIndexParser
->GetDist().c_str());
2125 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2126 void pkgAcqMetaIndex::Failed(string Message
,
2127 pkgAcquire::MethodConfig
* Cnf
)
2129 pkgAcquire::Item::Failed(Message
, Cnf
);
2132 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2134 _error
->Warning(_("The repository '%s' does not have a Release file. "
2135 "This is deprecated, please contact the owner of the "
2136 "repository."), URIDesc
.c_str());
2138 // No Release file was present so fall
2139 // back to queueing Packages files without verification
2140 // only allow going further if the users explicitely wants it
2141 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2143 // Done, queue for rename on transaction finished
2144 if (FileExists(DestFile
))
2145 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2147 // queue without any kind of hashsum support
2148 QueueIndexes(false);
2150 // warn if the repository is unsinged
2151 _error
->Warning("Use --allow-insecure-repositories to force the update");
2152 TransactionManager
->AbortTransaction();
2158 void pkgAcqMetaIndex::Finished() /*{{{*/
2160 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2161 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2162 if(TransactionManager
!= NULL
&&
2163 TransactionManager
->TransactionHasError() == false)
2164 TransactionManager
->CommitTransaction();
2167 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2168 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2169 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2170 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2171 const vector
<IndexTarget
*>* IndexTargets
,
2172 indexRecords
* MetaIndexParser
) :
2173 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2174 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2175 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2177 // index targets + (worst case:) Release/Release.gpg
2178 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2182 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2186 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2187 // ---------------------------------------------------------------------
2188 string
pkgAcqMetaClearSig::Custom600Headers() const
2190 string Final
= _config
->FindDir("Dir::State::lists");
2191 Final
+= URItoFileName(RealURI
);
2194 if (stat(Final
.c_str(),&Buf
) != 0)
2196 if (stat(Final
.c_str(),&Buf
) != 0)
2197 return "\nIndex-File: true\nFail-Ignore: true\n";
2200 return "\nIndex-File: true\nFail-Ignore: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
2203 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2204 // ---------------------------------------------------------------------
2205 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long /*Size*/,
2206 HashStringList
const &/*Hashes*/,
2207 pkgAcquire::MethodConfig
*Cnf
)
2209 // if we expect a ClearTextSignature (InRelase), ensure that
2210 // this is what we get and if not fail to queue a
2211 // Release/Release.gpg, see #346386
2212 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2214 pkgAcquire::Item::Failed(Message
, Cnf
);
2215 RenameOnError(NotClearsigned
);
2216 TransactionManager
->AbortTransaction();
2220 if(AuthPass
== false)
2222 if(CheckDownloadDone(Message
, RealURI
) == true)
2223 QueueForSignatureVerify(DestFile
, DestFile
);
2228 if(CheckAuthDone(Message
, RealURI
) == true)
2230 string FinalFile
= _config
->FindDir("Dir::State::lists");
2231 FinalFile
+= URItoFileName(RealURI
);
2233 // queue for copy in place
2234 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2239 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2241 Item::Failed(Message
, Cnf
);
2243 // we failed, we will not get additional items from this method
2244 ExpectedAdditionalItems
= 0;
2246 if (AuthPass
== false)
2248 // Queue the 'old' InRelease file for removal if we try Release.gpg
2249 // as otherwise the file will stay around and gives a false-auth
2250 // impression (CVE-2012-0214)
2251 string FinalFile
= _config
->FindDir("Dir::State::lists");
2252 FinalFile
.append(URItoFileName(RealURI
));
2253 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2256 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2257 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2258 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2259 IndexTargets
, MetaIndexParser
);
2263 if(CheckStopAuthentication(RealURI
, Message
))
2266 _error
->Warning(_("The data from '%s' is not signed. Packages "
2267 "from that repository can not be authenticated."),
2270 // No Release file was present, or verification failed, so fall
2271 // back to queueing Packages files without verification
2272 // only allow going further if the users explicitely wants it
2273 if(_config
->FindB("Acquire::AllowInsecureRepositories") == true)
2277 /* Always move the meta index, even if gpgv failed. This ensures
2278 * that PackageFile objects are correctly filled in */
2279 if (FileExists(DestFile
))
2281 string FinalFile
= _config
->FindDir("Dir::State::lists");
2282 FinalFile
+= URItoFileName(RealURI
);
2283 /* InRelease files become Release files, otherwise
2284 * they would be considered as trusted later on */
2285 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2287 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2290 // Done, queue for rename on transaction finished
2291 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2293 QueueIndexes(false);
2295 // warn if the repository is unsigned
2296 _error
->Warning("Use --allow-insecure-repositories to force the update");
2297 TransactionManager
->AbortTransaction();
2303 // AcqArchive::AcqArchive - Constructor /*{{{*/
2304 // ---------------------------------------------------------------------
2305 /* This just sets up the initial fetch environment and queues the first
2307 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2308 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2309 string
&StoreFilename
) :
2310 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2311 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2314 Retries
= _config
->FindI("Acquire::Retries",0);
2316 if (Version
.Arch() == 0)
2318 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2319 "This might mean you need to manually fix this package. "
2320 "(due to missing arch)"),
2321 Version
.ParentPkg().FullName().c_str());
2325 /* We need to find a filename to determine the extension. We make the
2326 assumption here that all the available sources for this version share
2327 the same extension.. */
2328 // Skip not source sources, they do not have file fields.
2329 for (; Vf
.end() == false; ++Vf
)
2331 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2336 // Does not really matter here.. we are going to fail out below
2337 if (Vf
.end() != true)
2339 // If this fails to get a file name we will bomb out below.
2340 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2341 if (_error
->PendingError() == true)
2344 // Generate the final file name as: package_version_arch.foo
2345 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2346 QuoteString(Version
.VerStr(),"_:") + '_' +
2347 QuoteString(Version
.Arch(),"_:.") +
2348 "." + flExtension(Parse
.FileName());
2351 // check if we have one trusted source for the package. if so, switch
2352 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2353 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2354 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2355 bool seenUntrusted
= false;
2356 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2358 pkgIndexFile
*Index
;
2359 if (Sources
->FindIndex(i
.File(),Index
) == false)
2362 if (debugAuth
== true)
2363 std::cerr
<< "Checking index: " << Index
->Describe()
2364 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2366 if (Index
->IsTrusted() == true)
2369 if (allowUnauth
== false)
2373 seenUntrusted
= true;
2376 // "allow-unauthenticated" restores apts old fetching behaviour
2377 // that means that e.g. unauthenticated file:// uris are higher
2378 // priority than authenticated http:// uris
2379 if (allowUnauth
== true && seenUntrusted
== true)
2383 if (QueueNext() == false && _error
->PendingError() == false)
2384 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2385 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2388 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2389 // ---------------------------------------------------------------------
2390 /* This queues the next available file version for download. It checks if
2391 the archive is already available in the cache and stashs the MD5 for
2393 bool pkgAcqArchive::QueueNext()
2395 for (; Vf
.end() == false; ++Vf
)
2397 // Ignore not source sources
2398 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2401 // Try to cross match against the source list
2402 pkgIndexFile
*Index
;
2403 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2406 // only try to get a trusted package from another source if that source
2408 if(Trusted
&& !Index
->IsTrusted())
2411 // Grab the text package record
2412 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2413 if (_error
->PendingError() == true)
2416 string PkgFile
= Parse
.FileName();
2417 ExpectedHashes
= Parse
.Hashes();
2419 if (PkgFile
.empty() == true)
2420 return _error
->Error(_("The package index files are corrupted. No Filename: "
2421 "field for package %s."),
2422 Version
.ParentPkg().Name());
2424 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2425 Desc
.Description
= Index
->ArchiveInfo(Version
);
2427 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2429 // See if we already have the file. (Legacy filenames)
2430 FileSize
= Version
->Size
;
2431 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2433 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2435 // Make sure the size matches
2436 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2441 StoreFilename
= DestFile
= FinalFile
;
2445 /* Hmm, we have a file and its size does not match, this means it is
2446 an old style mismatched arch */
2447 unlink(FinalFile
.c_str());
2450 // Check it again using the new style output filenames
2451 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2452 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2454 // Make sure the size matches
2455 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2460 StoreFilename
= DestFile
= FinalFile
;
2464 /* Hmm, we have a file and its size does not match, this shouldn't
2466 unlink(FinalFile
.c_str());
2469 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2471 // Check the destination file
2472 if (stat(DestFile
.c_str(),&Buf
) == 0)
2474 // Hmm, the partial file is too big, erase it
2475 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2476 unlink(DestFile
.c_str());
2479 PartialSize
= Buf
.st_size
;
2480 ChangeOwnerAndPermissionOfFile("pkgAcqArchive::QueueNext", FinalFile
.c_str(), "_apt", "root", 0600);
2484 // Disables download of archives - useful if no real installation follows,
2485 // e.g. if we are just interested in proposed installation order
2486 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2491 StoreFilename
= DestFile
= FinalFile
;
2505 // AcqArchive::Done - Finished fetching /*{{{*/
2506 // ---------------------------------------------------------------------
2508 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2509 pkgAcquire::MethodConfig
*Cfg
)
2511 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2514 if (Size
!= Version
->Size
)
2516 RenameOnError(SizeMismatch
);
2520 // FIXME: could this empty() check impose *any* sort of security issue?
2521 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2523 RenameOnError(HashSumMismatch
);
2524 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2528 // Grab the output filename
2529 string FileName
= LookupTag(Message
,"Filename");
2530 if (FileName
.empty() == true)
2533 ErrorText
= "Method gave a blank filename";
2537 // Reference filename
2538 if (FileName
!= DestFile
)
2540 StoreFilename
= DestFile
= FileName
;
2546 // Done, move it into position
2547 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2548 FinalFile
+= flNotDir(StoreFilename
);
2549 Rename(DestFile
,FinalFile
);
2550 ChangeOwnerAndPermissionOfFile("pkgAcqArchive::Done", FinalFile
.c_str(), "root", "root", 0644);
2551 StoreFilename
= DestFile
= FinalFile
;
2555 // AcqArchive::Failed - Failure handler /*{{{*/
2556 // ---------------------------------------------------------------------
2557 /* Here we try other sources */
2558 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2560 ErrorText
= LookupTag(Message
,"Message");
2562 /* We don't really want to retry on failed media swaps, this prevents
2563 that. An interesting observation is that permanent failures are not
2565 if (Cnf
->Removable
== true &&
2566 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2568 // Vf = Version.FileList();
2569 while (Vf
.end() == false) ++Vf
;
2570 StoreFilename
= string();
2571 Item::Failed(Message
,Cnf
);
2575 if (QueueNext() == false)
2577 // This is the retry counter
2579 Cnf
->LocalOnly
== false &&
2580 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2583 Vf
= Version
.FileList();
2584 if (QueueNext() == true)
2588 StoreFilename
= string();
2589 Item::Failed(Message
,Cnf
);
2593 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2594 // ---------------------------------------------------------------------
2595 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2600 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2601 // ---------------------------------------------------------------------
2603 void pkgAcqArchive::Finished()
2605 if (Status
== pkgAcquire::Item::StatDone
&&
2608 StoreFilename
= string();
2611 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2612 // ---------------------------------------------------------------------
2613 /* The file is added to the queue */
2614 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2615 unsigned long long Size
,string Dsc
,string ShortDesc
,
2616 const string
&DestDir
, const string
&DestFilename
,
2618 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2620 Retries
= _config
->FindI("Acquire::Retries",0);
2622 if(!DestFilename
.empty())
2623 DestFile
= DestFilename
;
2624 else if(!DestDir
.empty())
2625 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2627 DestFile
= flNotDir(URI
);
2631 Desc
.Description
= Dsc
;
2634 // Set the short description to the archive component
2635 Desc
.ShortDesc
= ShortDesc
;
2637 // Get the transfer sizes
2640 if (stat(DestFile
.c_str(),&Buf
) == 0)
2642 // Hmm, the partial file is too big, erase it
2643 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2644 unlink(DestFile
.c_str());
2647 PartialSize
= Buf
.st_size
;
2648 ChangeOwnerAndPermissionOfFile("pkgAcqFile", DestFile
.c_str(), "_apt", "root", 0600);
2655 // AcqFile::Done - Item downloaded OK /*{{{*/
2656 // ---------------------------------------------------------------------
2658 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2659 pkgAcquire::MethodConfig
*Cnf
)
2661 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2664 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2666 RenameOnError(HashSumMismatch
);
2667 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2671 string FileName
= LookupTag(Message
,"Filename");
2672 if (FileName
.empty() == true)
2675 ErrorText
= "Method gave a blank filename";
2681 // The files timestamp matches
2682 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2685 // We have to copy it into place
2686 if (FileName
!= DestFile
)
2689 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2690 Cnf
->Removable
== true)
2692 Desc
.URI
= "copy:" + FileName
;
2697 // Erase the file if it is a symlink so we can overwrite it
2699 if (lstat(DestFile
.c_str(),&St
) == 0)
2701 if (S_ISLNK(St
.st_mode
) != 0)
2702 unlink(DestFile
.c_str());
2706 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2708 ErrorText
= "Link to " + DestFile
+ " failure ";
2715 // AcqFile::Failed - Failure handler /*{{{*/
2716 // ---------------------------------------------------------------------
2717 /* Here we try other sources */
2718 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2720 ErrorText
= LookupTag(Message
,"Message");
2722 // This is the retry counter
2724 Cnf
->LocalOnly
== false &&
2725 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2732 Item::Failed(Message
,Cnf
);
2735 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2736 // ---------------------------------------------------------------------
2737 /* The only header we use is the last-modified header. */
2738 string
pkgAcqFile::Custom600Headers() const
2741 return "\nIndex-File: true";