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
);
82 static std::string
GetPartialFileName(std::string
const &file
) /*{{{*/
84 std::string DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
89 static std::string
GetPartialFileNameFromURI(std::string
const &uri
) /*{{{*/
91 return GetPartialFileName(URItoFileName(uri
));
94 static std::string
GetCompressedFileName(std::string
const &URI
, std::string
const &Name
, std::string
const &Ext
) /*{{{*/
96 if (Ext
.empty() || Ext
== "uncompressed")
99 // do not reverify cdrom sources as apt-cdrom may rewrite the Packages
100 // file when its doing the indexcopy
101 if (URI
.substr(0,6) == "cdrom:")
104 // adjust DestFile if its compressed on disk
105 if (_config
->FindB("Acquire::GzipIndexes",false) == true)
106 return Name
+ '.' + Ext
;
110 static bool AllowInsecureRepositories(indexRecords
const * const MetaIndexParser
, pkgAcqMetaBase
* const TransactionManager
, pkgAcquire::Item
* const I
) /*{{{*/
112 if(MetaIndexParser
->IsAlwaysTrusted() || _config
->FindB("Acquire::AllowInsecureRepositories") == true)
115 _error
->Error(_("Use --allow-insecure-repositories to force the update"));
116 TransactionManager
->AbortTransaction();
117 I
->Status
= pkgAcquire::Item::StatError
;
123 // Acquire::Item::Item - Constructor /*{{{*/
125 #pragma GCC diagnostic push
126 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
128 pkgAcquire::Item::Item(pkgAcquire
*Owner
,
129 HashStringList
const &ExpectedHashes
,
130 pkgAcqMetaBase
*TransactionManager
)
131 : Owner(Owner
), FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false),
132 Local(false), QueueCounter(0), TransactionManager(TransactionManager
),
133 ExpectedAdditionalItems(0), ExpectedHashes(ExpectedHashes
)
137 if(TransactionManager
!= NULL
)
138 TransactionManager
->Add(this);
141 #pragma GCC diagnostic pop
144 // Acquire::Item::~Item - Destructor /*{{{*/
145 // ---------------------------------------------------------------------
147 pkgAcquire::Item::~Item()
152 // Acquire::Item::Failed - Item failed to download /*{{{*/
153 // ---------------------------------------------------------------------
154 /* We return to an idle state if there are still other queues that could
156 void pkgAcquire::Item::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
159 ErrorText
= LookupTag(Message
,"Message");
160 UsedMirror
= LookupTag(Message
,"UsedMirror");
161 if (QueueCounter
<= 1)
163 /* This indicates that the file is not available right now but might
164 be sometime later. If we do a retry cycle then this should be
166 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
167 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
182 string FailReason
= LookupTag(Message
, "FailReason");
183 if(FailReason
== "MaximumSizeExceeded")
184 Rename(DestFile
, DestFile
+".FAILED");
186 // report mirror failure back to LP if we actually use a mirror
187 if(FailReason
.size() != 0)
188 ReportMirrorFailure(FailReason
);
190 ReportMirrorFailure(ErrorText
);
193 // Acquire::Item::Start - Item has begun to download /*{{{*/
194 // ---------------------------------------------------------------------
195 /* Stash status and the file size. Note that setting Complete means
196 sub-phases of the acquire process such as decompresion are operating */
197 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
199 Status
= StatFetching
;
200 if (FileSize
== 0 && Complete
== false)
204 // Acquire::Item::Done - Item downloaded OK /*{{{*/
205 // ---------------------------------------------------------------------
207 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
208 pkgAcquire::MethodConfig
* /*Cnf*/)
210 // We just downloaded something..
211 string FileName
= LookupTag(Message
,"Filename");
212 UsedMirror
= LookupTag(Message
,"UsedMirror");
213 if (Complete
== false && !Local
&& FileName
== DestFile
)
216 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
222 ErrorText
= string();
223 Owner
->Dequeue(this);
226 // Acquire::Item::Rename - Rename a file /*{{{*/
227 // ---------------------------------------------------------------------
228 /* This helper function is used by a lot of item methods as their final
230 bool pkgAcquire::Item::Rename(string From
,string To
)
232 if (rename(From
.c_str(),To
.c_str()) == 0)
236 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
237 From
.c_str(),To
.c_str());
243 void pkgAcquire::Item::QueueURI(ItemDesc
&Item
) /*{{{*/
245 if (RealFileExists(DestFile
))
247 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
248 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile
.c_str(),
249 SandboxUser
.c_str(), "root", 0600);
251 Owner
->Enqueue(Item
);
254 void pkgAcquire::Item::Dequeue() /*{{{*/
256 Owner
->Dequeue(this);
259 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
261 if(FileExists(DestFile
))
262 Rename(DestFile
, DestFile
+ ".FAILED");
266 case HashSumMismatch
:
267 ErrorText
= _("Hash Sum mismatch");
268 Status
= StatAuthError
;
269 ReportMirrorFailure("HashChecksumFailure");
272 ErrorText
= _("Size mismatch");
273 Status
= StatAuthError
;
274 ReportMirrorFailure("SizeFailure");
277 ErrorText
= _("Invalid file format");
279 // do not report as usually its not the mirrors fault, but Portal/Proxy
282 ErrorText
= _("Signature error");
286 ErrorText
= _("Does not start with a cleartext signature");
293 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
295 ActiveSubprocess
= subprocess
;
297 #pragma GCC diagnostic push
298 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
300 Mode
= ActiveSubprocess
.c_str();
302 #pragma GCC diagnostic pop
306 // Acquire::Item::ReportMirrorFailure /*{{{*/
307 // ---------------------------------------------------------------------
308 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
310 // we only act if a mirror was used at all
311 if(UsedMirror
.empty())
314 std::cerr
<< "\nReportMirrorFailure: "
316 << " Uri: " << DescURI()
318 << FailCode
<< std::endl
;
320 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
321 "/usr/lib/apt/apt-report-mirror-failure");
322 if(!FileExists(report
))
325 std::vector
<char const*> Args
;
326 Args
.push_back(report
.c_str());
327 Args
.push_back(UsedMirror
.c_str());
328 Args
.push_back(DescURI().c_str());
329 Args
.push_back(FailCode
.c_str());
330 Args
.push_back(NULL
);
332 pid_t pid
= ExecFork();
335 _error
->Error("ReportMirrorFailure Fork failed");
340 execvp(Args
[0], (char**)Args
.data());
341 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
344 if(!ExecWait(pid
, "report-mirror-failure"))
346 _error
->Warning("Couldn't report problem to '%s'",
347 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
351 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
352 // ---------------------------------------------------------------------
353 /* Get the DiffIndex file first and see if there are patches available
354 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
355 * patches. If anything goes wrong in that process, it will fall back to
356 * the original packages file
358 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
359 pkgAcqMetaBase
*TransactionManager
,
360 IndexTarget
const * const Target
,
361 HashStringList
const &ExpectedHashes
,
362 indexRecords
*MetaIndexParser
)
363 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
364 MetaIndexParser
), PackagesFileReadyInPartial(false)
367 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
369 RealURI
= Target
->URI
;
371 Desc
.Description
= Target
->Description
+ ".diff/Index";
372 Desc
.ShortDesc
= Target
->ShortDesc
;
373 Desc
.URI
= Target
->URI
+ ".diff/Index";
375 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
378 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
380 // look for the current package file
381 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
382 CurrentPackagesFile
+= URItoFileName(RealURI
);
384 // FIXME: this file:/ check is a hack to prevent fetching
385 // from local sources. this is really silly, and
386 // should be fixed cleanly as soon as possible
387 if(!FileExists(CurrentPackagesFile
) ||
388 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
390 // we don't have a pkg file or we don't want to queue
391 Failed("No index file, local or canceld by user", NULL
);
396 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
397 << CurrentPackagesFile
<< std::endl
;
403 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
404 // ---------------------------------------------------------------------
405 /* The only header we use is the last-modified header. */
406 string
pkgAcqDiffIndex::Custom600Headers() const
408 string Final
= _config
->FindDir("Dir::State::lists");
409 Final
+= URItoFileName(Desc
.URI
);
412 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
415 if (stat(Final
.c_str(),&Buf
) != 0)
416 return "\nIndex-File: true";
418 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
421 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
423 // failing here is fine: our caller will take care of trying to
424 // get the complete file if patching fails
426 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
429 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
431 if (_error
->PendingError() == true)
435 if(unlikely(TF
.Step(Tags
) == false))
438 HashStringList ServerHashes
;
439 unsigned long long ServerSize
= 0;
441 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
443 std::string tagname
= *type
;
444 tagname
.append("-Current");
445 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
446 if (tmp
.empty() == true)
450 unsigned long long size
;
451 std::stringstream
ss(tmp
);
453 if (unlikely(hash
.empty() == true))
455 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
457 ServerHashes
.push_back(HashString(*type
, hash
));
461 if (ServerHashes
.usable() == false)
464 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
468 if (ServerHashes
!= HashSums())
472 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
473 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, HashSums());
478 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
480 // we have the same sha1 as the server so we are done here
482 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
484 // list cleanup needs to know that this file as well as the already
485 // present index is ours, so we create an empty diff to save it for us
486 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
487 ExpectedHashes
, MetaIndexParser
);
491 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
492 Hashes LocalHashesCalc
;
493 LocalHashesCalc
.AddFD(fd
);
494 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
497 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
498 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
500 // parse all of (provided) history
501 vector
<DiffInfo
> available_patches
;
502 bool firstAcceptedHashes
= true;
503 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
505 if (LocalHashes
.find(*type
) == NULL
)
508 std::string tagname
= *type
;
509 tagname
.append("-History");
510 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
511 if (tmp
.empty() == true)
514 string hash
, filename
;
515 unsigned long long size
;
516 std::stringstream
ss(tmp
);
518 while (ss
>> hash
>> size
>> filename
)
520 if (unlikely(hash
.empty() == true || filename
.empty() == true))
523 // see if we have a record for this file already
524 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
525 for (; cur
!= available_patches
.end(); ++cur
)
527 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
529 cur
->result_hashes
.push_back(HashString(*type
, hash
));
532 if (cur
!= available_patches
.end())
534 if (firstAcceptedHashes
== true)
537 next
.file
= filename
;
538 next
.result_hashes
.push_back(HashString(*type
, hash
));
539 next
.result_size
= size
;
541 available_patches
.push_back(next
);
546 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
547 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
551 firstAcceptedHashes
= false;
554 if (unlikely(available_patches
.empty() == true))
557 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
558 << "Couldn't find any patches for the patch series." << std::endl
;
562 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
564 if (LocalHashes
.find(*type
) == NULL
)
567 std::string tagname
= *type
;
568 tagname
.append("-Patches");
569 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
570 if (tmp
.empty() == true)
573 string hash
, filename
;
574 unsigned long long size
;
575 std::stringstream
ss(tmp
);
577 while (ss
>> hash
>> size
>> filename
)
579 if (unlikely(hash
.empty() == true || filename
.empty() == true))
582 // see if we have a record for this file already
583 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
584 for (; cur
!= available_patches
.end(); ++cur
)
586 if (cur
->file
!= filename
)
588 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
590 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
591 cur
->patch_size
= size
;
594 if (cur
!= available_patches
.end())
597 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
598 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
603 bool foundStart
= false;
604 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
605 cur
!= available_patches
.end(); ++cur
)
607 if (LocalHashes
!= cur
->result_hashes
)
610 available_patches
.erase(available_patches
.begin(), cur
);
615 if (foundStart
== false || unlikely(available_patches
.empty() == true))
618 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
619 << "Couldn't find the start of the patch series." << std::endl
;
623 // patching with too many files is rather slow compared to a fast download
624 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
625 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
628 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
629 << ") so fallback to complete download" << std::endl
;
633 // calculate the size of all patches we have to get
634 // note that all sizes are uncompressed, while we download compressed files
635 unsigned long long patchesSize
= 0;
636 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
637 cur
!= available_patches
.end(); ++cur
)
638 patchesSize
+= cur
->patch_size
;
639 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
640 if (false && sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
643 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
644 << ") so fallback to complete download" << std::endl
;
648 // FIXME: make this use the method
649 PackagesFileReadyInPartial
= true;
650 std::string
const Partial
= GetPartialFileNameFromURI(RealURI
);
652 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
653 FileFd
To(Partial
, FileFd::WriteEmpty
);
654 if(CopyFile(From
, To
) == false)
655 return _error
->Errno("CopyFile", "failed to copy");
658 std::cerr
<< "Done copying " << CurrentPackagesFile
662 // we have something, queue the diffs
663 string::size_type
const last_space
= Description
.rfind(" ");
664 if(last_space
!= string::npos
)
665 Description
.erase(last_space
, Description
.size()-last_space
);
667 /* decide if we should download patches one by one or in one go:
668 The first is good if the server merges patches, but many don't so client
669 based merging can be attempt in which case the second is better.
670 "bad things" will happen if patches are merged on the server,
671 but client side merging is attempt as well */
672 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
673 if (pdiff_merge
== true)
675 // reprepro adds this flag if it has merged patches on the server
676 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
677 pdiff_merge
= (precedence
!= "merged");
680 if (pdiff_merge
== false)
682 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
683 MetaIndexParser
, available_patches
);
687 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
688 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
689 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
693 available_patches
[i
],
703 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
706 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
707 << "Falling back to normal index file acquire" << std::endl
;
709 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
711 Item::Failed(Message
,Cnf
);
715 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
716 pkgAcquire::MethodConfig
*Cnf
)
719 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
721 Item::Done(Message
, Size
, Hashes
, Cnf
);
723 // verify the index target
724 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
726 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
727 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
728 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
730 RenameOnError(HashSumMismatch
);
731 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
732 Failed(Message
, Cnf
);
739 FinalFile
= _config
->FindDir("Dir::State::lists");
740 FinalFile
+= URItoFileName(Desc
.URI
);
742 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
743 DestFile
= FinalFile
;
745 if(!ParseDiffIndex(DestFile
))
746 return Failed("Message: Couldn't parse pdiff index", Cnf
);
748 // queue for final move
749 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
757 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
758 // ---------------------------------------------------------------------
759 /* The package diff is added to the queue. one object is constructed
760 * for each diff and the index
762 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
763 pkgAcqMetaBase
*TransactionManager
,
764 struct IndexTarget
const * const Target
,
765 HashStringList
const &ExpectedHashes
,
766 indexRecords
*MetaIndexParser
,
767 vector
<DiffInfo
> diffs
)
768 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
769 available_patches(diffs
)
771 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
773 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
775 RealURI
= Target
->URI
;
777 Description
= Target
->Description
;
778 Desc
.ShortDesc
= Target
->ShortDesc
;
780 if(available_patches
.empty() == true)
782 // we are done (yeah!), check hashes against the final file
783 DestFile
= _config
->FindDir("Dir::State::lists");
784 DestFile
+= URItoFileName(Target
->URI
);
790 State
= StateFetchDiff
;
795 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* /*Cnf*/)/*{{{*/
798 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
799 << "Falling back to normal index file acquire" << std::endl
;
800 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
804 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
805 void pkgAcqIndexDiffs::Finish(bool allDone
)
808 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
810 << Desc
.URI
<< std::endl
;
812 // we restore the original name, this is required, otherwise
813 // the file will be cleaned
816 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
818 RenameOnError(HashSumMismatch
);
824 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
825 FinalFile
+= URItoFileName(RealURI
);
826 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
828 // this is for the "real" finish
833 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
838 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
845 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
847 // calc sha1 of the just patched file
848 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
850 if(!FileExists(FinalFile
))
852 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
856 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
857 Hashes LocalHashesCalc
;
858 LocalHashesCalc
.AddFD(fd
);
859 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
862 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
864 if (unlikely(LocalHashes
.usable() == false || ExpectedHashes
.usable() == false))
866 Failed("Local/Expected hashes are not usable", NULL
);
871 // final file reached before all patches are applied
872 if(LocalHashes
== ExpectedHashes
)
878 // remove all patches until the next matching patch is found
879 // this requires the Index file to be ordered
880 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
881 available_patches
.empty() == false &&
882 I
!= available_patches
.end() &&
883 I
->result_hashes
!= LocalHashes
;
886 available_patches
.erase(I
);
889 // error checking and falling back if no patch was found
890 if(available_patches
.empty() == true)
892 Failed("No patches left to reach target", NULL
);
896 // queue the right diff
897 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
898 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
899 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
902 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
909 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
910 pkgAcquire::MethodConfig
*Cnf
)
913 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
915 Item::Done(Message
, Size
, Hashes
, Cnf
);
917 // FIXME: verify this download too before feeding it to rred
918 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
920 // success in downloading a diff, enter ApplyDiff state
921 if(State
== StateFetchDiff
)
923 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
924 class Hashes LocalHashesCalc
;
925 LocalHashesCalc
.AddFD(fd
);
926 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
928 if (fd
.Size() != available_patches
[0].patch_size
||
929 available_patches
[0].patch_hashes
!= LocalHashes
)
931 Failed("Patch has Size/Hashsum mismatch", NULL
);
935 // rred excepts the patch as $FinalFile.ed
936 Rename(DestFile
,FinalFile
+".ed");
939 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
941 State
= StateApplyDiff
;
943 Desc
.URI
= "rred:" + FinalFile
;
945 SetActiveSubprocess("rred");
950 // success in download/apply a diff, queue next (if needed)
951 if(State
== StateApplyDiff
)
953 // remove the just applied patch
954 available_patches
.erase(available_patches
.begin());
955 unlink((FinalFile
+ ".ed").c_str());
960 std::clog
<< "Moving patched file in place: " << std::endl
961 << DestFile
<< " -> " << FinalFile
<< std::endl
;
963 Rename(DestFile
,FinalFile
);
964 chmod(FinalFile
.c_str(),0644);
966 // see if there is more to download
967 if(available_patches
.empty() == false) {
968 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
969 ExpectedHashes
, MetaIndexParser
,
974 DestFile
= FinalFile
;
979 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
980 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
981 pkgAcqMetaBase
*TransactionManager
,
982 struct IndexTarget
const * const Target
,
983 HashStringList
const &ExpectedHashes
,
984 indexRecords
*MetaIndexParser
,
985 DiffInfo
const &patch
,
986 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
987 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
988 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
990 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
992 RealURI
= Target
->URI
;
994 Description
= Target
->Description
;
995 Desc
.ShortDesc
= Target
->ShortDesc
;
997 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
998 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
1000 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + patch
.file
);
1003 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
1008 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
1011 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
1013 Item::Failed(Message
,Cnf
);
1016 // check if we are the first to fail, otherwise we are done here
1017 State
= StateDoneDiff
;
1018 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1019 I
!= allPatches
->end(); ++I
)
1020 if ((*I
)->State
== StateErrorDiff
)
1023 // first failure means we should fallback
1024 State
= StateErrorDiff
;
1025 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
1026 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
1029 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1030 pkgAcquire::MethodConfig
*Cnf
)
1033 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
1035 Item::Done(Message
,Size
,Hashes
,Cnf
);
1037 // FIXME: verify download before feeding it to rred
1038 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1040 if (State
== StateFetchDiff
)
1042 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1043 class Hashes LocalHashesCalc
;
1044 LocalHashesCalc
.AddFD(fd
);
1045 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1047 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1049 Failed("Patch has Size/Hashsum mismatch", NULL
);
1053 // rred expects the patch as $FinalFile.ed.$patchname.gz
1054 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1056 // check if this is the last completed diff
1057 State
= StateDoneDiff
;
1058 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1059 I
!= allPatches
->end(); ++I
)
1060 if ((*I
)->State
!= StateDoneDiff
)
1063 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1067 // this is the last completed diff, so we are ready to apply now
1068 State
= StateApplyDiff
;
1071 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1074 Desc
.URI
= "rred:" + FinalFile
;
1076 SetActiveSubprocess("rred");
1079 // success in download/apply all diffs, clean up
1080 else if (State
== StateApplyDiff
)
1082 // see if we really got the expected file
1083 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
1085 RenameOnError(HashSumMismatch
);
1090 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1091 FinalFile
+= URItoFileName(RealURI
);
1093 // move the result into place
1095 std::clog
<< "Queue patched file in place: " << std::endl
1096 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1098 // queue for copy by the transaction manager
1099 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1101 // ensure the ed's are gone regardless of list-cleanup
1102 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1103 I
!= allPatches
->end(); ++I
)
1105 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1106 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1107 unlink(patch
.c_str());
1113 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1117 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1118 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1120 if(MetaKey
!= "" && Hashes
.usable())
1122 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1123 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1125 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1132 // AcqIndex::AcqIndex - Constructor /*{{{*/
1133 // ---------------------------------------------------------------------
1134 /* The package file is added to the queue and a second class is
1135 instantiated to fetch the revision file */
1136 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1137 string URI
,string URIDesc
,string ShortDesc
,
1138 HashStringList
const &ExpectedHash
)
1139 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1143 AutoSelectCompression();
1144 Init(URI
, URIDesc
, ShortDesc
);
1146 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1147 std::clog
<< "New pkgIndex with TransactionManager "
1148 << TransactionManager
<< std::endl
;
1151 // AcqIndex::AcqIndex - Constructor /*{{{*/
1152 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1153 pkgAcqMetaBase
*TransactionManager
,
1154 IndexTarget
const *Target
,
1155 HashStringList
const &ExpectedHash
,
1156 indexRecords
*MetaIndexParser
)
1157 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1160 RealURI
= Target
->URI
;
1162 // autoselect the compression method
1163 AutoSelectCompression();
1164 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1166 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1167 std::clog
<< "New pkgIndex with TransactionManager "
1168 << TransactionManager
<< std::endl
;
1171 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1172 void pkgAcqIndex::AutoSelectCompression()
1174 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1175 CompressionExtensions
= "";
1176 if (ExpectedHashes
.usable())
1178 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1179 t
!= types
.end(); ++t
)
1181 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1182 if (*t
== "uncompressed" ||
1183 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1184 CompressionExtensions
.append(*t
).append(" ");
1189 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1190 CompressionExtensions
.append(*t
).append(" ");
1192 if (CompressionExtensions
.empty() == false)
1193 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1196 // AcqIndex::Init - defered Constructor /*{{{*/
1197 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1198 string
const &ShortDesc
)
1200 Stage
= STAGE_DOWNLOAD
;
1202 DestFile
= GetPartialFileNameFromURI(URI
);
1204 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1205 if (CurrentCompressionExtension
== "uncompressed")
1209 MetaKey
= string(Target
->MetaKey
);
1213 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1214 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1216 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1219 // load the filesize
1222 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1224 FileSize
= Record
->Size
;
1226 InitByHashIfNeeded(MetaKey
);
1229 Desc
.Description
= URIDesc
;
1231 Desc
.ShortDesc
= ShortDesc
;
1236 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1237 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1240 // - (maybe?) add support for by-hash into the sources.list as flag
1241 // - make apt-ftparchive generate the hashes (and expire?)
1242 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1243 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1244 _config
->FindB(HostKnob
, false) == true ||
1245 MetaIndexParser
->GetSupportsAcquireByHash())
1247 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1250 // FIXME: should we really use the best hash here? or a fixed one?
1251 const HashString
*TargetHash
= Record
->Hashes
.find("");
1252 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1253 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1254 Desc
.URI
= Desc
.URI
.replace(
1256 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1260 "Fetching ByHash requested but can not find record for %s",
1266 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1267 // ---------------------------------------------------------------------
1268 /* The only header we use is the last-modified header. */
1269 string
pkgAcqIndex::Custom600Headers() const
1271 string Final
= GetFinalFilename();
1273 string msg
= "\nIndex-File: true";
1275 if (stat(Final
.c_str(),&Buf
) == 0)
1276 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1281 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1282 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1284 size_t const nextExt
= CompressionExtensions
.find(' ');
1285 if (nextExt
!= std::string::npos
)
1287 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1288 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1292 // on decompression failure, remove bad versions in partial/
1293 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1295 unlink(EraseFileName
.c_str());
1298 Item::Failed(Message
,Cnf
);
1300 /// cancel the entire transaction
1301 TransactionManager
->AbortTransaction();
1304 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1305 std::string
pkgAcqIndex::GetFinalFilename() const
1307 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1308 FinalFile
+= URItoFileName(RealURI
);
1309 return GetCompressedFileName(RealURI
, FinalFile
, CurrentCompressionExtension
);
1312 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1313 void pkgAcqIndex::ReverifyAfterIMS()
1315 // update destfile to *not* include the compression extension when doing
1316 // a reverify (as its uncompressed on disk already)
1317 DestFile
= GetCompressedFileName(RealURI
, GetPartialFileNameFromURI(RealURI
), CurrentCompressionExtension
);
1319 // copy FinalFile into partial/ so that we check the hash again
1320 string FinalFile
= GetFinalFilename();
1321 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1322 Desc
.URI
= "copy:" + FinalFile
;
1326 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1327 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1329 // FIXME: this can go away once we only ever download stuff that
1330 // has a valid hash and we never do GET based probing
1331 // FIXME2: this also leaks debian-isms into the code and should go therefore
1333 /* Always validate the index file for correctness (all indexes must
1334 * have a Package field) (LP: #346386) (Closes: #627642)
1336 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1337 // Only test for correctness if the content of the file is not empty
1342 pkgTagFile
tag(&fd
);
1344 // all our current indexes have a field 'Package' in each section
1345 if (_error
->PendingError() == true ||
1346 tag
.Step(sec
) == false ||
1347 sec
.Exists("Package") == false)
1353 // AcqIndex::Done - Finished a fetch /*{{{*/
1354 // ---------------------------------------------------------------------
1355 /* This goes through a number of states.. On the initial fetch the
1356 method could possibly return an alternate filename which points
1357 to the uncompressed version of the file. If this is so the file
1358 is copied into the partial directory. In all other cases the file
1359 is decompressed with a compressed uri. */
1360 void pkgAcqIndex::Done(string Message
,
1361 unsigned long long Size
,
1362 HashStringList
const &Hashes
,
1363 pkgAcquire::MethodConfig
*Cfg
)
1365 Item::Done(Message
,Size
,Hashes
,Cfg
);
1369 case STAGE_DOWNLOAD
:
1370 StageDownloadDone(Message
, Hashes
, Cfg
);
1372 case STAGE_DECOMPRESS_AND_VERIFY
:
1373 StageDecompressDone(Message
, Hashes
, Cfg
);
1378 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1379 void pkgAcqIndex::StageDownloadDone(string Message
,
1380 HashStringList
const &Hashes
,
1381 pkgAcquire::MethodConfig
*Cfg
)
1383 // First check if the calculcated Hash of the (compressed) downloaded
1384 // file matches the hash we have in the MetaIndexRecords for this file
1385 if(VerifyHashByMetaKey(Hashes
) == false)
1387 RenameOnError(HashSumMismatch
);
1388 Failed(Message
, Cfg
);
1394 // Handle the unzipd case
1395 string FileName
= LookupTag(Message
,"Alt-Filename");
1396 if (FileName
.empty() == false)
1398 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1400 DestFile
+= ".decomp";
1401 Desc
.URI
= "copy:" + FileName
;
1403 SetActiveSubprocess("copy");
1407 FileName
= LookupTag(Message
,"Filename");
1408 if (FileName
.empty() == true)
1411 ErrorText
= "Method gave a blank filename";
1414 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1415 // not the "DestFile" we set, in this case we uncompress from the local file
1416 if (FileName
!= DestFile
)
1419 EraseFileName
= FileName
;
1421 // we need to verify the file against the current Release file again
1422 // on if-modfied-since hit to avoid a stale attack against us
1423 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1425 // The files timestamp matches, reverify by copy into partial/
1431 // If we have compressed indexes enabled, queue for hash verification
1432 if (_config
->FindB("Acquire::GzipIndexes",false))
1434 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1436 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1437 Desc
.URI
= "copy:" + FileName
;
1439 SetActiveSubprocess("copy");
1443 // get the binary name for your used compression type
1445 if(CurrentCompressionExtension
== "uncompressed")
1446 decompProg
= "copy";
1448 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1449 if(decompProg
.empty() == true)
1451 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1455 // queue uri for the next stage
1456 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1457 DestFile
+= ".decomp";
1458 Desc
.URI
= decompProg
+ ":" + FileName
;
1460 SetActiveSubprocess(decompProg
);
1463 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1464 void pkgAcqIndex::StageDecompressDone(string Message
,
1465 HashStringList
const &Hashes
,
1466 pkgAcquire::MethodConfig
*Cfg
)
1468 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1471 RenameOnError(HashSumMismatch
);
1472 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1473 Failed(Message
, Cfg
);
1477 if(!ValidateFile(DestFile
))
1479 RenameOnError(InvalidFormat
);
1480 Failed(Message
, Cfg
);
1484 // remove the compressed version of the file
1485 unlink(EraseFileName
.c_str());
1487 // Done, queue for rename on transaction finished
1488 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1493 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1494 // ---------------------------------------------------------------------
1495 /* The Translation file is added to the queue */
1496 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1497 string URI
,string URIDesc
,string ShortDesc
)
1498 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1501 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1502 pkgAcqMetaBase
*TransactionManager
,
1503 IndexTarget
const * const Target
,
1504 HashStringList
const &ExpectedHashes
,
1505 indexRecords
*MetaIndexParser
)
1506 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1510 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1511 string
pkgAcqIndexTrans::Custom600Headers() const
1513 string Final
= GetFinalFilename();
1516 if (stat(Final
.c_str(),&Buf
) != 0)
1517 return "\nFail-Ignore: true\nIndex-File: true";
1518 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1521 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1522 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1524 size_t const nextExt
= CompressionExtensions
.find(' ');
1525 if (nextExt
!= std::string::npos
)
1527 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1528 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1533 Item::Failed(Message
,Cnf
);
1535 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1536 if (Cnf
->LocalOnly
== true ||
1537 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1544 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1545 void pkgAcqMetaBase::Add(Item
*I
)
1547 Transaction
.push_back(I
);
1550 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1551 void pkgAcqMetaBase::AbortTransaction()
1553 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1554 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1556 // ensure the toplevel is in error state too
1557 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1558 I
!= Transaction
.end(); ++I
)
1560 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1561 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1562 // the transaction will abort, so stop anything that is idle
1563 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1564 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1566 // kill failed files in partial
1567 if ((*I
)->Status
== pkgAcquire::Item::StatError
)
1569 std::string
const PartialFile
= GetPartialFileName(flNotDir((*I
)->DestFile
));
1570 if(FileExists(PartialFile
))
1571 Rename(PartialFile
, PartialFile
+ ".FAILED");
1573 // fix permissions for existing files which were part of a reverify
1574 // like InRelease files or files in partial we might work with next time
1575 else if (FileExists((*I
)->DestFile
))
1576 ChangeOwnerAndPermissionOfFile("AbortTransaction", (*I
)->DestFile
.c_str(), "root", "root", 0644);
1578 Transaction
.clear();
1581 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1582 bool pkgAcqMetaBase::TransactionHasError()
1584 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1585 I
!= Transaction
.end(); ++I
)
1586 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1587 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1593 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1594 void pkgAcqMetaBase::CommitTransaction()
1596 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1597 std::clog
<< "CommitTransaction: " << this << std::endl
;
1599 // move new files into place *and* remove files that are not
1600 // part of the transaction but are still on disk
1601 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1602 I
!= Transaction
.end(); ++I
)
1604 if((*I
)->PartialFile
!= "")
1606 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1607 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1608 << (*I
)->DescURI() << std::endl
;
1610 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1611 ChangeOwnerAndPermissionOfFile("CommitTransaction", (*I
)->DestFile
.c_str(), "root", "root", 0644);
1614 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1620 unlink((*I
)->DestFile
.c_str());
1622 // mark that this transaction is finished
1623 (*I
)->TransactionManager
= 0;
1625 Transaction
.clear();
1628 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1629 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1630 const std::string
&From
,
1631 const std::string
&To
)
1633 I
->PartialFile
= From
;
1637 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1638 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1639 const std::string
&FinalFile
)
1641 I
->PartialFile
= "";
1642 I
->DestFile
= FinalFile
;
1645 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1646 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&RealURI
,
1647 const std::string
&Message
)
1649 // FIXME: this entire function can do now that we disallow going to
1650 // a unauthenticated state and can cleanly rollback
1652 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1654 if(FileExists(Final
))
1656 Status
= StatTransientNetworkError
;
1657 _error
->Warning(_("An error occurred during the signature "
1658 "verification. The repository is not updated "
1659 "and the previous index files will be used. "
1660 "GPG error: %s: %s\n"),
1661 Desc
.Description
.c_str(),
1662 LookupTag(Message
,"Message").c_str());
1663 RunScripts("APT::Update::Auth-Failure");
1665 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1666 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1667 _error
->Error(_("GPG error: %s: %s"),
1668 Desc
.Description
.c_str(),
1669 LookupTag(Message
,"Message").c_str());
1673 _error
->Warning(_("GPG error: %s: %s"),
1674 Desc
.Description
.c_str(),
1675 LookupTag(Message
,"Message").c_str());
1677 // gpgv method failed
1678 ReportMirrorFailure("GPGFailure");
1682 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1683 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1684 pkgAcqMetaBase
*TransactionManager
,
1685 string URI
,string URIDesc
,string ShortDesc
,
1686 string MetaIndexFile
,
1687 const vector
<IndexTarget
*>* IndexTargets
,
1688 indexRecords
* MetaIndexParser
) :
1689 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1690 HashStringList(), TransactionManager
),
1691 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1692 ShortDesc(ShortDesc
)
1694 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1695 DestFile
+= URItoFileName(RealURI
);
1697 // remove any partial downloaded sig-file in partial/.
1698 // it may confuse proxies and is too small to warrant a
1699 // partial download anyway
1700 unlink(DestFile
.c_str());
1702 // set the TransactionManager
1703 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1704 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1705 << TransactionManager
<< std::endl
;
1708 Desc
.Description
= URIDesc
;
1710 Desc
.ShortDesc
= ShortDesc
;
1716 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1720 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1721 // ---------------------------------------------------------------------
1722 string
pkgAcqMetaSig::Custom600Headers() const
1724 std::string Header
= GetCustom600Headers(RealURI
);
1728 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1729 // ---------------------------------------------------------------------
1730 /* The only header we use is the last-modified header. */
1731 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1732 HashStringList
const &Hashes
,
1733 pkgAcquire::MethodConfig
*Cfg
)
1735 Item::Done(Message
, Size
, Hashes
, Cfg
);
1737 if(AuthPass
== false)
1739 if(CheckDownloadDone(Message
, RealURI
) == true)
1741 // destfile will be modified to point to MetaIndexFile for the
1742 // gpgv method, so we need to save it here
1743 MetaIndexFileSignature
= DestFile
;
1744 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1750 if(CheckAuthDone(Message
, RealURI
) == true)
1752 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1753 FinalFile
+= URItoFileName(RealURI
);
1754 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1759 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1761 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1763 // check if we need to fail at this point
1764 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1767 // FIXME: meh, this is not really elegant
1768 string InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1770 string FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1772 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1774 std::string downgrade_msg
;
1775 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1777 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1779 // meh, the users wants to take risks (we still mark the packages
1780 // from this repository as unauthenticated)
1781 _error
->Warning("%s", downgrade_msg
.c_str());
1782 _error
->Warning(_("This is normally not allowed, but the option "
1783 "Acquire::AllowDowngradeToInsecureRepositories was "
1784 "given to override it."));
1787 _error
->Error("%s", downgrade_msg
.c_str());
1788 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1789 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1790 TransactionManager
->AbortTransaction();
1795 _error
->Warning(_("The data from '%s' is not signed. Packages "
1796 "from that repository can not be authenticated."),
1799 // this ensures that any file in the lists/ dir is removed by the
1801 DestFile
= GetPartialFileNameFromURI(RealURI
);
1802 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1804 // only allow going further if the users explicitely wants it
1805 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
1807 // we parse the indexes here because at this point the user wanted
1808 // a repository that may potentially harm him
1809 MetaIndexParser
->Load(MetaIndexFile
);
1813 Item::Failed(Message
,Cnf
);
1815 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1816 if (Cnf
->LocalOnly
== true ||
1817 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1824 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1825 pkgAcqMetaBase
*TransactionManager
,
1826 string URI
,string URIDesc
,string ShortDesc
,
1827 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1828 const vector
<IndexTarget
*>* IndexTargets
,
1829 indexRecords
* MetaIndexParser
) :
1830 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1831 TransactionManager
),
1832 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1833 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1834 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1836 if(TransactionManager
== NULL
)
1838 this->TransactionManager
= this;
1839 this->TransactionManager
->Add(this);
1842 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1843 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1844 << this->TransactionManager
<< std::endl
;
1847 Init(URIDesc
, ShortDesc
);
1850 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1851 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1853 DestFile
= GetPartialFileNameFromURI(RealURI
);
1856 Desc
.Description
= URIDesc
;
1858 Desc
.ShortDesc
= ShortDesc
;
1861 // we expect more item
1862 ExpectedAdditionalItems
= IndexTargets
->size();
1866 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1867 // ---------------------------------------------------------------------
1868 string
pkgAcqMetaIndex::Custom600Headers() const
1870 return GetCustom600Headers(RealURI
);
1873 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1874 HashStringList
const &Hashes
,
1875 pkgAcquire::MethodConfig
*Cfg
)
1877 Item::Done(Message
,Size
,Hashes
,Cfg
);
1879 if(CheckDownloadDone(Message
, RealURI
))
1881 // we have a Release file, now download the Signature, all further
1882 // verify/queue for additional downloads will be done in the
1883 // pkgAcqMetaSig::Done() code
1884 std::string MetaIndexFile
= DestFile
;
1885 new pkgAcqMetaSig(Owner
, TransactionManager
,
1886 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1887 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1890 string FinalFile
= _config
->FindDir("Dir::State::lists");
1891 FinalFile
+= URItoFileName(RealURI
);
1892 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1896 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1898 // At this point, the gpgv method has succeeded, so there is a
1899 // valid signature from a key in the trusted keyring. We
1900 // perform additional verification of its contents, and use them
1901 // to verify the indexes we are about to download
1903 if (!MetaIndexParser
->Load(DestFile
))
1905 Status
= StatAuthError
;
1906 ErrorText
= MetaIndexParser
->ErrorText
;
1910 if (!VerifyVendor(Message
, RealURI
))
1915 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1916 std::cerr
<< "Signature verification succeeded: "
1917 << DestFile
<< std::endl
;
1919 // Download further indexes with verification
1921 // it would be really nice if we could simply do
1922 // if (IMSHit == false) QueueIndexes(true)
1923 // and skip the download if the Release file has not changed
1924 // - but right now the list cleaner will needs to be tricked
1925 // to not delete all our packages/source indexes in this case
1931 // pkgAcqMetaBase::GetCustom600Headers - Get header for AcqMetaBase /*{{{*/
1932 // ---------------------------------------------------------------------
1933 string
pkgAcqMetaBase::GetCustom600Headers(const string
&RealURI
) const
1935 std::string Header
= "\nIndex-File: true";
1936 std::string MaximumSize
;
1937 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1938 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1939 Header
+= MaximumSize
;
1941 string FinalFile
= _config
->FindDir("Dir::State::lists");
1942 FinalFile
+= URItoFileName(RealURI
);
1945 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1946 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1951 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1952 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1953 const std::string
&MetaIndexFileSignature
)
1956 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1957 DestFile
= MetaIndexFile
;
1959 SetActiveSubprocess("gpgv");
1962 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1963 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1964 const std::string
&RealURI
)
1966 // We have just finished downloading a Release file (it is not
1969 string FileName
= LookupTag(Message
,"Filename");
1970 if (FileName
.empty() == true)
1973 ErrorText
= "Method gave a blank filename";
1977 if (FileName
!= DestFile
)
1980 Desc
.URI
= "copy:" + FileName
;
1985 // make sure to verify against the right file on I-M-S hit
1986 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1989 string FinalFile
= _config
->FindDir("Dir::State::lists");
1990 FinalFile
+= URItoFileName(RealURI
);
1991 DestFile
= FinalFile
;
1994 // set Item to complete as the remaining work is all local (verify etc)
2000 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
2002 bool transInRelease
= false;
2004 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
2005 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
2006 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
2007 if (k
->find("Translation-") != std::string::npos
)
2009 transInRelease
= true;
2014 // at this point the real Items are loaded in the fetcher
2015 ExpectedAdditionalItems
= 0;
2016 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
2017 Target
!= IndexTargets
->end();
2020 HashStringList ExpectedIndexHashes
;
2021 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
2022 bool compressedAvailable
= false;
2025 if ((*Target
)->IsOptional() == true)
2027 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2028 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2029 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
2031 compressedAvailable
= true;
2035 else if (verify
== true)
2037 Status
= StatAuthError
;
2038 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2044 ExpectedIndexHashes
= Record
->Hashes
;
2045 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2047 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2048 << "Expected Hash:" << std::endl
;
2049 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2050 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2051 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
2053 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
2055 Status
= StatAuthError
;
2056 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2061 if ((*Target
)->IsOptional() == true)
2063 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
2065 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
2066 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
2067 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2069 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2074 /* Queue Packages file (either diff or full packages files, depending
2075 on the users option) - we also check if the PDiff Index file is listed
2076 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2077 instead, but passing the required info to it is to much hassle */
2078 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2079 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2080 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2082 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2086 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
2088 string::size_type pos
;
2090 // check for missing sigs (that where not fatal because otherwise we had
2093 string msg
= _("There is no public key available for the "
2094 "following key IDs:\n");
2095 pos
= Message
.find("NO_PUBKEY ");
2096 if (pos
!= std::string::npos
)
2098 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2099 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2100 missingkeys
+= (Fingerprint
);
2102 if(!missingkeys
.empty())
2103 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2105 string Transformed
= MetaIndexParser
->GetExpectedDist();
2107 if (Transformed
== "../project/experimental")
2109 Transformed
= "experimental";
2112 pos
= Transformed
.rfind('/');
2113 if (pos
!= string::npos
)
2115 Transformed
= Transformed
.substr(0, pos
);
2118 if (Transformed
== ".")
2123 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2124 MetaIndexParser
->GetValidUntil() > 0) {
2125 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2126 if (invalid_since
> 0)
2127 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2128 // the time since then the file is invalid - formated in the same way as in
2129 // the download progress display (e.g. 7d 3h 42min 1s)
2130 return _error
->Error(
2131 _("Release file for %s is expired (invalid since %s). "
2132 "Updates for this repository will not be applied."),
2133 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2136 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2138 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2139 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2140 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2143 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2145 // This might become fatal one day
2146 // Status = StatAuthError;
2147 // ErrorText = "Conflicting distribution; expected "
2148 // + MetaIndexParser->GetExpectedDist() + " but got "
2149 // + MetaIndexParser->GetDist();
2151 if (!Transformed
.empty())
2153 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2154 Desc
.Description
.c_str(),
2155 Transformed
.c_str(),
2156 MetaIndexParser
->GetDist().c_str());
2163 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2164 void pkgAcqMetaIndex::Failed(string Message
,
2165 pkgAcquire::MethodConfig
* Cnf
)
2167 pkgAcquire::Item::Failed(Message
, Cnf
);
2170 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2172 _error
->Warning(_("The repository '%s' does not have a Release file. "
2173 "This is deprecated, please contact the owner of the "
2174 "repository."), URIDesc
.c_str());
2176 // No Release file was present so fall
2177 // back to queueing Packages files without verification
2178 // only allow going further if the users explicitely wants it
2179 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2181 // Done, queue for rename on transaction finished
2182 if (FileExists(DestFile
))
2183 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2185 // queue without any kind of hashsum support
2186 QueueIndexes(false);
2190 void pkgAcqMetaIndex::Finished() /*{{{*/
2192 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2193 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2194 if(TransactionManager
!= NULL
&&
2195 TransactionManager
->TransactionHasError() == false)
2196 TransactionManager
->CommitTransaction();
2199 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2200 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2201 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2202 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2203 const vector
<IndexTarget
*>* IndexTargets
,
2204 indexRecords
* MetaIndexParser
) :
2205 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2206 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2207 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2209 // index targets + (worst case:) Release/Release.gpg
2210 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2214 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2218 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2219 // ---------------------------------------------------------------------
2220 string
pkgAcqMetaClearSig::Custom600Headers() const
2222 string Header
= GetCustom600Headers(RealURI
);
2223 Header
+= "\nFail-Ignore: true";
2227 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2228 // ---------------------------------------------------------------------
2229 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long /*Size*/,
2230 HashStringList
const &/*Hashes*/,
2231 pkgAcquire::MethodConfig
*Cnf
)
2233 // if we expect a ClearTextSignature (InRelase), ensure that
2234 // this is what we get and if not fail to queue a
2235 // Release/Release.gpg, see #346386
2236 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2238 pkgAcquire::Item::Failed(Message
, Cnf
);
2239 RenameOnError(NotClearsigned
);
2240 TransactionManager
->AbortTransaction();
2244 if(AuthPass
== false)
2246 if(CheckDownloadDone(Message
, RealURI
) == true)
2247 QueueForSignatureVerify(DestFile
, DestFile
);
2252 if(CheckAuthDone(Message
, RealURI
) == true)
2254 string FinalFile
= _config
->FindDir("Dir::State::lists");
2255 FinalFile
+= URItoFileName(RealURI
);
2257 // queue for copy in place
2258 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2263 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2265 Item::Failed(Message
, Cnf
);
2267 // we failed, we will not get additional items from this method
2268 ExpectedAdditionalItems
= 0;
2270 if (AuthPass
== false)
2272 // Queue the 'old' InRelease file for removal if we try Release.gpg
2273 // as otherwise the file will stay around and gives a false-auth
2274 // impression (CVE-2012-0214)
2275 string FinalFile
= _config
->FindDir("Dir::State::lists");
2276 FinalFile
.append(URItoFileName(RealURI
));
2277 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2280 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2281 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2282 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2283 IndexTargets
, MetaIndexParser
);
2287 if(CheckStopAuthentication(RealURI
, Message
))
2290 _error
->Warning(_("The data from '%s' is not signed. Packages "
2291 "from that repository can not be authenticated."),
2294 // No Release file was present, or verification failed, so fall
2295 // back to queueing Packages files without verification
2296 // only allow going further if the users explicitely wants it
2297 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2301 /* Always move the meta index, even if gpgv failed. This ensures
2302 * that PackageFile objects are correctly filled in */
2303 if (FileExists(DestFile
))
2305 string FinalFile
= _config
->FindDir("Dir::State::lists");
2306 FinalFile
+= URItoFileName(RealURI
);
2307 /* InRelease files become Release files, otherwise
2308 * they would be considered as trusted later on */
2309 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2311 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2314 // Done, queue for rename on transaction finished
2315 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2317 QueueIndexes(false);
2322 // AcqArchive::AcqArchive - Constructor /*{{{*/
2323 // ---------------------------------------------------------------------
2324 /* This just sets up the initial fetch environment and queues the first
2326 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2327 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2328 string
&StoreFilename
) :
2329 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2330 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2333 Retries
= _config
->FindI("Acquire::Retries",0);
2335 if (Version
.Arch() == 0)
2337 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2338 "This might mean you need to manually fix this package. "
2339 "(due to missing arch)"),
2340 Version
.ParentPkg().FullName().c_str());
2344 /* We need to find a filename to determine the extension. We make the
2345 assumption here that all the available sources for this version share
2346 the same extension.. */
2347 // Skip not source sources, they do not have file fields.
2348 for (; Vf
.end() == false; ++Vf
)
2350 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2355 // Does not really matter here.. we are going to fail out below
2356 if (Vf
.end() != true)
2358 // If this fails to get a file name we will bomb out below.
2359 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2360 if (_error
->PendingError() == true)
2363 // Generate the final file name as: package_version_arch.foo
2364 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2365 QuoteString(Version
.VerStr(),"_:") + '_' +
2366 QuoteString(Version
.Arch(),"_:.") +
2367 "." + flExtension(Parse
.FileName());
2370 // check if we have one trusted source for the package. if so, switch
2371 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2372 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2373 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2374 bool seenUntrusted
= false;
2375 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2377 pkgIndexFile
*Index
;
2378 if (Sources
->FindIndex(i
.File(),Index
) == false)
2381 if (debugAuth
== true)
2382 std::cerr
<< "Checking index: " << Index
->Describe()
2383 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2385 if (Index
->IsTrusted() == true)
2388 if (allowUnauth
== false)
2392 seenUntrusted
= true;
2395 // "allow-unauthenticated" restores apts old fetching behaviour
2396 // that means that e.g. unauthenticated file:// uris are higher
2397 // priority than authenticated http:// uris
2398 if (allowUnauth
== true && seenUntrusted
== true)
2402 if (QueueNext() == false && _error
->PendingError() == false)
2403 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2404 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2407 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2408 // ---------------------------------------------------------------------
2409 /* This queues the next available file version for download. It checks if
2410 the archive is already available in the cache and stashs the MD5 for
2412 bool pkgAcqArchive::QueueNext()
2414 for (; Vf
.end() == false; ++Vf
)
2416 // Ignore not source sources
2417 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2420 // Try to cross match against the source list
2421 pkgIndexFile
*Index
;
2422 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2425 // only try to get a trusted package from another source if that source
2427 if(Trusted
&& !Index
->IsTrusted())
2430 // Grab the text package record
2431 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2432 if (_error
->PendingError() == true)
2435 string PkgFile
= Parse
.FileName();
2436 ExpectedHashes
= Parse
.Hashes();
2438 if (PkgFile
.empty() == true)
2439 return _error
->Error(_("The package index files are corrupted. No Filename: "
2440 "field for package %s."),
2441 Version
.ParentPkg().Name());
2443 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2444 Desc
.Description
= Index
->ArchiveInfo(Version
);
2446 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2448 // See if we already have the file. (Legacy filenames)
2449 FileSize
= Version
->Size
;
2450 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
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 means it is
2465 an old style mismatched arch */
2466 unlink(FinalFile
.c_str());
2469 // Check it again using the new style output filenames
2470 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2471 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2473 // Make sure the size matches
2474 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2479 StoreFilename
= DestFile
= FinalFile
;
2483 /* Hmm, we have a file and its size does not match, this shouldn't
2485 unlink(FinalFile
.c_str());
2488 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2490 // Check the destination file
2491 if (stat(DestFile
.c_str(),&Buf
) == 0)
2493 // Hmm, the partial file is too big, erase it
2494 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2495 unlink(DestFile
.c_str());
2498 PartialSize
= Buf
.st_size
;
2499 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
2500 ChangeOwnerAndPermissionOfFile("pkgAcqArchive::QueueNext",DestFile
.c_str(), SandboxUser
.c_str(), "root", 0600);
2504 // Disables download of archives - useful if no real installation follows,
2505 // e.g. if we are just interested in proposed installation order
2506 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2511 StoreFilename
= DestFile
= FinalFile
;
2525 // AcqArchive::Done - Finished fetching /*{{{*/
2526 // ---------------------------------------------------------------------
2528 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2529 pkgAcquire::MethodConfig
*Cfg
)
2531 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2534 if (Size
!= Version
->Size
)
2536 RenameOnError(SizeMismatch
);
2540 // FIXME: could this empty() check impose *any* sort of security issue?
2541 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2543 RenameOnError(HashSumMismatch
);
2544 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2548 // Grab the output filename
2549 string FileName
= LookupTag(Message
,"Filename");
2550 if (FileName
.empty() == true)
2553 ErrorText
= "Method gave a blank filename";
2557 // Reference filename
2558 if (FileName
!= DestFile
)
2560 StoreFilename
= DestFile
= FileName
;
2566 // Done, move it into position
2567 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2568 FinalFile
+= flNotDir(StoreFilename
);
2569 Rename(DestFile
,FinalFile
);
2570 ChangeOwnerAndPermissionOfFile("pkgAcqArchive::Done", FinalFile
.c_str(), "root", "root", 0644);
2571 StoreFilename
= DestFile
= FinalFile
;
2575 // AcqArchive::Failed - Failure handler /*{{{*/
2576 // ---------------------------------------------------------------------
2577 /* Here we try other sources */
2578 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2580 ErrorText
= LookupTag(Message
,"Message");
2582 /* We don't really want to retry on failed media swaps, this prevents
2583 that. An interesting observation is that permanent failures are not
2585 if (Cnf
->Removable
== true &&
2586 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2588 // Vf = Version.FileList();
2589 while (Vf
.end() == false) ++Vf
;
2590 StoreFilename
= string();
2591 Item::Failed(Message
,Cnf
);
2595 if (QueueNext() == false)
2597 // This is the retry counter
2599 Cnf
->LocalOnly
== false &&
2600 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2603 Vf
= Version
.FileList();
2604 if (QueueNext() == true)
2608 StoreFilename
= string();
2609 Item::Failed(Message
,Cnf
);
2613 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2614 // ---------------------------------------------------------------------
2615 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2620 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2621 // ---------------------------------------------------------------------
2623 void pkgAcqArchive::Finished()
2625 if (Status
== pkgAcquire::Item::StatDone
&&
2628 StoreFilename
= string();
2631 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2632 // ---------------------------------------------------------------------
2633 /* The file is added to the queue */
2634 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2635 unsigned long long Size
,string Dsc
,string ShortDesc
,
2636 const string
&DestDir
, const string
&DestFilename
,
2638 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2640 Retries
= _config
->FindI("Acquire::Retries",0);
2642 if(!DestFilename
.empty())
2643 DestFile
= DestFilename
;
2644 else if(!DestDir
.empty())
2645 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2647 DestFile
= flNotDir(URI
);
2651 Desc
.Description
= Dsc
;
2654 // Set the short description to the archive component
2655 Desc
.ShortDesc
= ShortDesc
;
2657 // Get the transfer sizes
2660 if (stat(DestFile
.c_str(),&Buf
) == 0)
2662 // Hmm, the partial file is too big, erase it
2663 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2664 unlink(DestFile
.c_str());
2667 PartialSize
= Buf
.st_size
;
2668 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
2669 ChangeOwnerAndPermissionOfFile("pkgAcqFile", DestFile
.c_str(), SandboxUser
.c_str(), "root", 0600);
2676 // AcqFile::Done - Item downloaded OK /*{{{*/
2677 // ---------------------------------------------------------------------
2679 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2680 pkgAcquire::MethodConfig
*Cnf
)
2682 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2685 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2687 RenameOnError(HashSumMismatch
);
2688 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2692 string FileName
= LookupTag(Message
,"Filename");
2693 if (FileName
.empty() == true)
2696 ErrorText
= "Method gave a blank filename";
2702 // The files timestamp matches
2703 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2706 // We have to copy it into place
2707 if (FileName
!= DestFile
)
2710 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2711 Cnf
->Removable
== true)
2713 Desc
.URI
= "copy:" + FileName
;
2718 // Erase the file if it is a symlink so we can overwrite it
2720 if (lstat(DestFile
.c_str(),&St
) == 0)
2722 if (S_ISLNK(St
.st_mode
) != 0)
2723 unlink(DestFile
.c_str());
2727 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2729 ErrorText
= "Link to " + DestFile
+ " failure ";
2736 // AcqFile::Failed - Failure handler /*{{{*/
2737 // ---------------------------------------------------------------------
2738 /* Here we try other sources */
2739 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2741 ErrorText
= LookupTag(Message
,"Message");
2743 // This is the retry counter
2745 Cnf
->LocalOnly
== false &&
2746 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2753 Item::Failed(Message
,Cnf
);
2756 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2757 // ---------------------------------------------------------------------
2758 /* The only header we use is the last-modified header. */
2759 string
pkgAcqFile::Custom600Headers() const
2762 return "\nIndex-File: true";