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 if (getuid() == 0 && strlen(user
) != 0 && strlen(group
) != 0) // if we aren't root, we can't chown, so don't try it
72 // ensure the file is owned by root and has good permissions
73 struct passwd
const * const pw
= getpwnam(user
);
74 struct group
const * const gr
= getgrnam(group
);
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
)
158 if (RealFileExists(DestFile
))
159 ChangeOwnerAndPermissionOfFile("Item::Failed", DestFile
.c_str(), "root", "root", 0644);
161 if(ErrorText
.empty())
162 ErrorText
= LookupTag(Message
,"Message");
163 UsedMirror
= LookupTag(Message
,"UsedMirror");
164 if (QueueCounter
<= 1)
166 /* This indicates that the file is not available right now but might
167 be sometime later. If we do a retry cycle then this should be
169 if (Cnf
!= NULL
&& Cnf
->LocalOnly
== true &&
170 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
185 string
const FailReason
= LookupTag(Message
, "FailReason");
186 if(FailReason
== "MaximumSizeExceeded")
187 RenameOnError(MaximumSizeExceeded
);
189 // report mirror failure back to LP if we actually use a mirror
190 if(FailReason
.size() != 0)
191 ReportMirrorFailure(FailReason
);
193 ReportMirrorFailure(ErrorText
);
196 // Acquire::Item::Start - Item has begun to download /*{{{*/
197 // ---------------------------------------------------------------------
198 /* Stash status and the file size. Note that setting Complete means
199 sub-phases of the acquire process such as decompresion are operating */
200 void pkgAcquire::Item::Start(string
/*Message*/,unsigned long long Size
)
202 Status
= StatFetching
;
204 if (FileSize
== 0 && Complete
== false)
208 // Acquire::Item::Done - Item downloaded OK /*{{{*/
209 // ---------------------------------------------------------------------
211 void pkgAcquire::Item::Done(string Message
,unsigned long long Size
,HashStringList
const &/*Hash*/,
212 pkgAcquire::MethodConfig
* /*Cnf*/)
214 // We just downloaded something..
215 string FileName
= LookupTag(Message
,"Filename");
216 UsedMirror
= LookupTag(Message
,"UsedMirror");
217 if (Complete
== false && !Local
&& FileName
== DestFile
)
220 Owner
->Log
->Fetched(Size
,atoi(LookupTag(Message
,"Resume-Point","0").c_str()));
222 if (RealFileExists(DestFile
))
223 ChangeOwnerAndPermissionOfFile("Item::Done", DestFile
.c_str(), "root", "root", 0644);
228 ErrorText
= string();
229 Owner
->Dequeue(this);
232 // Acquire::Item::Rename - Rename a file /*{{{*/
233 // ---------------------------------------------------------------------
234 /* This helper function is used by a lot of item methods as their final
236 bool pkgAcquire::Item::Rename(string From
,string To
)
238 if (rename(From
.c_str(),To
.c_str()) == 0)
240 ChangeOwnerAndPermissionOfFile("Item::Failed", To
.c_str(), "root", "root", 0644);
243 strprintf(S
, _("rename failed, %s (%s -> %s)."), strerror(errno
),
244 From
.c_str(),To
.c_str());
250 void pkgAcquire::Item::QueueURI(ItemDesc
&Item
) /*{{{*/
252 if (RealFileExists(DestFile
))
254 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
255 ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile
.c_str(),
256 SandboxUser
.c_str(), "root", 0600);
258 Owner
->Enqueue(Item
);
261 void pkgAcquire::Item::Dequeue() /*{{{*/
263 Owner
->Dequeue(this);
266 bool pkgAcquire::Item::RenameOnError(pkgAcquire::Item::RenameOnErrorState
const error
)/*{{{*/
268 if (RealFileExists(DestFile
))
269 Rename(DestFile
, DestFile
+ ".FAILED");
273 case HashSumMismatch
:
274 ErrorText
= _("Hash Sum mismatch");
275 Status
= StatAuthError
;
276 ReportMirrorFailure("HashChecksumFailure");
279 ErrorText
= _("Size mismatch");
280 Status
= StatAuthError
;
281 ReportMirrorFailure("SizeFailure");
284 ErrorText
= _("Invalid file format");
286 // do not report as usually its not the mirrors fault, but Portal/Proxy
289 ErrorText
= _("Signature error");
293 ErrorText
= _("Does not start with a cleartext signature");
296 case MaximumSizeExceeded
:
297 // the method is expected to report a good error for this
304 void pkgAcquire::Item::SetActiveSubprocess(const std::string
&subprocess
)/*{{{*/
306 ActiveSubprocess
= subprocess
;
308 #pragma GCC diagnostic push
309 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
311 Mode
= ActiveSubprocess
.c_str();
313 #pragma GCC diagnostic pop
317 // Acquire::Item::ReportMirrorFailure /*{{{*/
318 // ---------------------------------------------------------------------
319 void pkgAcquire::Item::ReportMirrorFailure(string FailCode
)
321 // we only act if a mirror was used at all
322 if(UsedMirror
.empty())
325 std::cerr
<< "\nReportMirrorFailure: "
327 << " Uri: " << DescURI()
329 << FailCode
<< std::endl
;
331 string report
= _config
->Find("Methods::Mirror::ProblemReporting",
332 "/usr/lib/apt/apt-report-mirror-failure");
333 if(!FileExists(report
))
336 std::vector
<char const*> Args
;
337 Args
.push_back(report
.c_str());
338 Args
.push_back(UsedMirror
.c_str());
339 Args
.push_back(DescURI().c_str());
340 Args
.push_back(FailCode
.c_str());
341 Args
.push_back(NULL
);
343 pid_t pid
= ExecFork();
346 _error
->Error("ReportMirrorFailure Fork failed");
351 execvp(Args
[0], (char**)Args
.data());
352 std::cerr
<< "Could not exec " << Args
[0] << std::endl
;
355 if(!ExecWait(pid
, "report-mirror-failure"))
357 _error
->Warning("Couldn't report problem to '%s'",
358 _config
->Find("Methods::Mirror::ProblemReporting").c_str());
362 // AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
363 // ---------------------------------------------------------------------
364 /* Get the DiffIndex file first and see if there are patches available
365 * If so, create a pkgAcqIndexDiffs fetcher that will get and apply the
366 * patches. If anything goes wrong in that process, it will fall back to
367 * the original packages file
369 pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire
*Owner
,
370 pkgAcqMetaBase
*TransactionManager
,
371 IndexTarget
const * const Target
,
372 HashStringList
const &ExpectedHashes
,
373 indexRecords
*MetaIndexParser
)
374 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
,
375 MetaIndexParser
), PackagesFileReadyInPartial(false)
378 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
380 RealURI
= Target
->URI
;
382 Desc
.Description
= Target
->Description
+ ".diff/Index";
383 Desc
.ShortDesc
= Target
->ShortDesc
;
384 Desc
.URI
= Target
->URI
+ ".diff/Index";
386 DestFile
= GetPartialFileNameFromURI(Desc
.URI
);
389 std::clog
<< "pkgAcqDiffIndex: " << Desc
.URI
<< std::endl
;
391 // look for the current package file
392 CurrentPackagesFile
= _config
->FindDir("Dir::State::lists");
393 CurrentPackagesFile
+= URItoFileName(RealURI
);
395 // FIXME: this file:/ check is a hack to prevent fetching
396 // from local sources. this is really silly, and
397 // should be fixed cleanly as soon as possible
398 if(!FileExists(CurrentPackagesFile
) ||
399 Desc
.URI
.substr(0,strlen("file:/")) == "file:/")
401 // we don't have a pkg file or we don't want to queue
402 Failed("No index file, local or canceld by user", NULL
);
407 std::clog
<< "pkgAcqDiffIndex::pkgAcqDiffIndex(): "
408 << CurrentPackagesFile
<< std::endl
;
414 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
415 // ---------------------------------------------------------------------
416 /* The only header we use is the last-modified header. */
417 string
pkgAcqDiffIndex::Custom600Headers() const
419 string Final
= _config
->FindDir("Dir::State::lists");
420 Final
+= URItoFileName(Desc
.URI
);
423 std::clog
<< "Custom600Header-IMS: " << Final
<< std::endl
;
426 if (stat(Final
.c_str(),&Buf
) != 0)
427 return "\nIndex-File: true";
429 return "\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
432 bool pkgAcqDiffIndex::ParseDiffIndex(string IndexDiffFile
) /*{{{*/
434 // failing here is fine: our caller will take care of trying to
435 // get the complete file if patching fails
437 std::clog
<< "pkgAcqDiffIndex::ParseIndexDiff() " << IndexDiffFile
440 FileFd
Fd(IndexDiffFile
,FileFd::ReadOnly
);
442 if (_error
->PendingError() == true)
446 if(unlikely(TF
.Step(Tags
) == false))
449 HashStringList ServerHashes
;
450 unsigned long long ServerSize
= 0;
452 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
454 std::string tagname
= *type
;
455 tagname
.append("-Current");
456 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
457 if (tmp
.empty() == true)
461 unsigned long long size
;
462 std::stringstream
ss(tmp
);
464 if (unlikely(hash
.empty() == true))
466 if (unlikely(ServerSize
!= 0 && ServerSize
!= size
))
468 ServerHashes
.push_back(HashString(*type
, hash
));
472 if (ServerHashes
.usable() == false)
475 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Did not find a good hashsum in the index" << std::endl
;
479 if (ServerHashes
!= HashSums())
483 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": Index has different hashes than parser, probably older, so fail pdiffing" << std::endl
;
484 printHashSumComparision(CurrentPackagesFile
, ServerHashes
, HashSums());
489 if (ServerHashes
.VerifyFile(CurrentPackagesFile
) == true)
491 // we have the same sha1 as the server so we are done here
493 std::clog
<< "pkgAcqDiffIndex: Package file " << CurrentPackagesFile
<< " is up-to-date" << std::endl
;
495 // list cleanup needs to know that this file as well as the already
496 // present index is ours, so we create an empty diff to save it for us
497 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
498 ExpectedHashes
, MetaIndexParser
);
502 FileFd
fd(CurrentPackagesFile
, FileFd::ReadOnly
);
503 Hashes LocalHashesCalc
;
504 LocalHashesCalc
.AddFD(fd
);
505 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
508 std::clog
<< "Server-Current: " << ServerHashes
.find(NULL
)->toStr() << " and we start at "
509 << fd
.Name() << " " << fd
.FileSize() << " " << LocalHashes
.find(NULL
)->toStr() << std::endl
;
511 // parse all of (provided) history
512 vector
<DiffInfo
> available_patches
;
513 bool firstAcceptedHashes
= true;
514 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
516 if (LocalHashes
.find(*type
) == NULL
)
519 std::string tagname
= *type
;
520 tagname
.append("-History");
521 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
522 if (tmp
.empty() == true)
525 string hash
, filename
;
526 unsigned long long size
;
527 std::stringstream
ss(tmp
);
529 while (ss
>> hash
>> size
>> filename
)
531 if (unlikely(hash
.empty() == true || filename
.empty() == true))
534 // see if we have a record for this file already
535 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
536 for (; cur
!= available_patches
.end(); ++cur
)
538 if (cur
->file
!= filename
|| unlikely(cur
->result_size
!= size
))
540 cur
->result_hashes
.push_back(HashString(*type
, hash
));
543 if (cur
!= available_patches
.end())
545 if (firstAcceptedHashes
== true)
548 next
.file
= filename
;
549 next
.result_hashes
.push_back(HashString(*type
, hash
));
550 next
.result_size
= size
;
552 available_patches
.push_back(next
);
557 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
558 << " wasn't in the list for the first parsed hash! (history)" << std::endl
;
562 firstAcceptedHashes
= false;
565 if (unlikely(available_patches
.empty() == true))
568 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
569 << "Couldn't find any patches for the patch series." << std::endl
;
573 for (char const * const * type
= HashString::SupportedHashes(); *type
!= NULL
; ++type
)
575 if (LocalHashes
.find(*type
) == NULL
)
578 std::string tagname
= *type
;
579 tagname
.append("-Patches");
580 std::string
const tmp
= Tags
.FindS(tagname
.c_str());
581 if (tmp
.empty() == true)
584 string hash
, filename
;
585 unsigned long long size
;
586 std::stringstream
ss(tmp
);
588 while (ss
>> hash
>> size
>> filename
)
590 if (unlikely(hash
.empty() == true || filename
.empty() == true))
593 // see if we have a record for this file already
594 std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
595 for (; cur
!= available_patches
.end(); ++cur
)
597 if (cur
->file
!= filename
)
599 if (unlikely(cur
->patch_size
!= 0 && cur
->patch_size
!= size
))
601 cur
->patch_hashes
.push_back(HashString(*type
, hash
));
602 cur
->patch_size
= size
;
605 if (cur
!= available_patches
.end())
608 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": File " << filename
609 << " wasn't in the list for the first parsed hash! (patches)" << std::endl
;
614 bool foundStart
= false;
615 for (std::vector
<DiffInfo
>::iterator cur
= available_patches
.begin();
616 cur
!= available_patches
.end(); ++cur
)
618 if (LocalHashes
!= cur
->result_hashes
)
621 available_patches
.erase(available_patches
.begin(), cur
);
626 if (foundStart
== false || unlikely(available_patches
.empty() == true))
629 std::clog
<< "pkgAcqDiffIndex: " << IndexDiffFile
<< ": "
630 << "Couldn't find the start of the patch series." << std::endl
;
634 // patching with too many files is rather slow compared to a fast download
635 unsigned long const fileLimit
= _config
->FindI("Acquire::PDiffs::FileLimit", 0);
636 if (fileLimit
!= 0 && fileLimit
< available_patches
.size())
639 std::clog
<< "Need " << available_patches
.size() << " diffs (Limit is " << fileLimit
640 << ") so fallback to complete download" << std::endl
;
644 // calculate the size of all patches we have to get
645 // note that all sizes are uncompressed, while we download compressed files
646 unsigned long long patchesSize
= 0;
647 for (std::vector
<DiffInfo
>::const_iterator cur
= available_patches
.begin();
648 cur
!= available_patches
.end(); ++cur
)
649 patchesSize
+= cur
->patch_size
;
650 unsigned long long const sizeLimit
= ServerSize
* _config
->FindI("Acquire::PDiffs::SizeLimit", 100);
651 if (false && sizeLimit
> 0 && (sizeLimit
/100) < patchesSize
)
654 std::clog
<< "Need " << patchesSize
<< " bytes (Limit is " << sizeLimit
/100
655 << ") so fallback to complete download" << std::endl
;
659 // FIXME: make this use the method
660 PackagesFileReadyInPartial
= true;
661 std::string
const Partial
= GetPartialFileNameFromURI(RealURI
);
663 FileFd
From(CurrentPackagesFile
, FileFd::ReadOnly
);
664 FileFd
To(Partial
, FileFd::WriteEmpty
);
665 if(CopyFile(From
, To
) == false)
666 return _error
->Errno("CopyFile", "failed to copy");
669 std::cerr
<< "Done copying " << CurrentPackagesFile
673 // we have something, queue the diffs
674 string::size_type
const last_space
= Description
.rfind(" ");
675 if(last_space
!= string::npos
)
676 Description
.erase(last_space
, Description
.size()-last_space
);
678 /* decide if we should download patches one by one or in one go:
679 The first is good if the server merges patches, but many don't so client
680 based merging can be attempt in which case the second is better.
681 "bad things" will happen if patches are merged on the server,
682 but client side merging is attempt as well */
683 bool pdiff_merge
= _config
->FindB("Acquire::PDiffs::Merge", true);
684 if (pdiff_merge
== true)
686 // reprepro adds this flag if it has merged patches on the server
687 std::string
const precedence
= Tags
.FindS("X-Patch-Precedence");
688 pdiff_merge
= (precedence
!= "merged");
691 if (pdiff_merge
== false)
693 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
, ExpectedHashes
,
694 MetaIndexParser
, available_patches
);
698 std::vector
<pkgAcqIndexMergeDiffs
*> *diffs
= new std::vector
<pkgAcqIndexMergeDiffs
*>(available_patches
.size());
699 for(size_t i
= 0; i
< available_patches
.size(); ++i
)
700 (*diffs
)[i
] = new pkgAcqIndexMergeDiffs(Owner
, TransactionManager
,
704 available_patches
[i
],
714 void pkgAcqDiffIndex::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
716 Item::Failed(Message
,Cnf
);
720 std::clog
<< "pkgAcqDiffIndex failed: " << Desc
.URI
<< " with " << Message
<< std::endl
721 << "Falling back to normal index file acquire" << std::endl
;
723 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
726 void pkgAcqDiffIndex::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
727 pkgAcquire::MethodConfig
*Cnf
)
730 std::clog
<< "pkgAcqDiffIndex::Done(): " << Desc
.URI
<< std::endl
;
732 Item::Done(Message
, Size
, Hashes
, Cnf
);
734 // verify the index target
735 if(Target
&& Target
->MetaKey
!= "" && MetaIndexParser
&& Hashes
.usable())
737 std::string IndexMetaKey
= Target
->MetaKey
+ ".diff/Index";
738 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(IndexMetaKey
);
739 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
741 RenameOnError(HashSumMismatch
);
742 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
743 Failed(Message
, Cnf
);
750 FinalFile
= _config
->FindDir("Dir::State::lists");
751 FinalFile
+= URItoFileName(Desc
.URI
);
753 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false))
754 DestFile
= FinalFile
;
756 if(!ParseDiffIndex(DestFile
))
757 return Failed("Message: Couldn't parse pdiff index", Cnf
);
759 // queue for final move
760 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
768 // AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
769 // ---------------------------------------------------------------------
770 /* The package diff is added to the queue. one object is constructed
771 * for each diff and the index
773 pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire
*Owner
,
774 pkgAcqMetaBase
*TransactionManager
,
775 struct IndexTarget
const * const Target
,
776 HashStringList
const &ExpectedHashes
,
777 indexRecords
*MetaIndexParser
,
778 vector
<DiffInfo
> diffs
)
779 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
780 available_patches(diffs
)
782 DestFile
= GetPartialFileNameFromURI(Target
->URI
);
784 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
786 RealURI
= Target
->URI
;
788 Description
= Target
->Description
;
789 Desc
.ShortDesc
= Target
->ShortDesc
;
791 if(available_patches
.empty() == true)
793 // we are done (yeah!), check hashes against the final file
794 DestFile
= _config
->FindDir("Dir::State::lists");
795 DestFile
+= URItoFileName(Target
->URI
);
801 State
= StateFetchDiff
;
806 void pkgAcqIndexDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
808 Item::Failed(Message
,Cnf
);
812 std::clog
<< "pkgAcqIndexDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
813 << "Falling back to normal index file acquire" << std::endl
;
814 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
818 // Finish - helper that cleans the item out of the fetcher queue /*{{{*/
819 void pkgAcqIndexDiffs::Finish(bool allDone
)
822 std::clog
<< "pkgAcqIndexDiffs::Finish(): "
824 << Desc
.URI
<< std::endl
;
826 // we restore the original name, this is required, otherwise
827 // the file will be cleaned
830 if(HashSums().usable() && !HashSums().VerifyFile(DestFile
))
832 RenameOnError(HashSumMismatch
);
838 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
839 FinalFile
+= URItoFileName(RealURI
);
840 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
842 // this is for the "real" finish
847 std::clog
<< "\n\nallDone: " << DestFile
<< "\n" << std::endl
;
852 std::clog
<< "Finishing: " << Desc
.URI
<< std::endl
;
859 bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
861 // calc sha1 of the just patched file
862 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
864 if(!FileExists(FinalFile
))
866 Failed("Message: No FinalFile " + FinalFile
+ " available", NULL
);
870 FileFd
fd(FinalFile
, FileFd::ReadOnly
);
871 Hashes LocalHashesCalc
;
872 LocalHashesCalc
.AddFD(fd
);
873 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
876 std::clog
<< "QueueNextDiff: " << FinalFile
<< " (" << LocalHashes
.find(NULL
)->toStr() << ")" << std::endl
;
878 if (unlikely(LocalHashes
.usable() == false || ExpectedHashes
.usable() == false))
880 Failed("Local/Expected hashes are not usable", NULL
);
885 // final file reached before all patches are applied
886 if(LocalHashes
== ExpectedHashes
)
892 // remove all patches until the next matching patch is found
893 // this requires the Index file to be ordered
894 for(vector
<DiffInfo
>::iterator I
= available_patches
.begin();
895 available_patches
.empty() == false &&
896 I
!= available_patches
.end() &&
897 I
->result_hashes
!= LocalHashes
;
900 available_patches
.erase(I
);
903 // error checking and falling back if no patch was found
904 if(available_patches
.empty() == true)
906 Failed("No patches left to reach target", NULL
);
910 // queue the right diff
911 Desc
.URI
= RealURI
+ ".diff/" + available_patches
[0].file
+ ".gz";
912 Desc
.Description
= Description
+ " " + available_patches
[0].file
+ string(".pdiff");
913 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + available_patches
[0].file
);
916 std::clog
<< "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc
.URI
<< std::endl
;
923 void pkgAcqIndexDiffs::Done(string Message
,unsigned long long Size
, HashStringList
const &Hashes
, /*{{{*/
924 pkgAcquire::MethodConfig
*Cnf
)
927 std::clog
<< "pkgAcqIndexDiffs::Done(): " << Desc
.URI
<< std::endl
;
929 Item::Done(Message
, Size
, Hashes
, Cnf
);
931 // FIXME: verify this download too before feeding it to rred
932 std::string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
934 // success in downloading a diff, enter ApplyDiff state
935 if(State
== StateFetchDiff
)
937 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
938 class Hashes LocalHashesCalc
;
939 LocalHashesCalc
.AddFD(fd
);
940 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
942 if (fd
.Size() != available_patches
[0].patch_size
||
943 available_patches
[0].patch_hashes
!= LocalHashes
)
945 Failed("Patch has Size/Hashsum mismatch", NULL
);
949 // rred excepts the patch as $FinalFile.ed
950 Rename(DestFile
,FinalFile
+".ed");
953 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
955 State
= StateApplyDiff
;
957 Desc
.URI
= "rred:" + FinalFile
;
959 SetActiveSubprocess("rred");
964 // success in download/apply a diff, queue next (if needed)
965 if(State
== StateApplyDiff
)
967 // remove the just applied patch
968 available_patches
.erase(available_patches
.begin());
969 unlink((FinalFile
+ ".ed").c_str());
974 std::clog
<< "Moving patched file in place: " << std::endl
975 << DestFile
<< " -> " << FinalFile
<< std::endl
;
977 Rename(DestFile
,FinalFile
);
978 chmod(FinalFile
.c_str(),0644);
980 // see if there is more to download
981 if(available_patches
.empty() == false) {
982 new pkgAcqIndexDiffs(Owner
, TransactionManager
, Target
,
983 ExpectedHashes
, MetaIndexParser
,
988 DestFile
= FinalFile
;
993 // AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
994 pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire
*Owner
,
995 pkgAcqMetaBase
*TransactionManager
,
996 struct IndexTarget
const * const Target
,
997 HashStringList
const &ExpectedHashes
,
998 indexRecords
*MetaIndexParser
,
999 DiffInfo
const &patch
,
1000 std::vector
<pkgAcqIndexMergeDiffs
*> const * const allPatches
)
1001 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
),
1002 patch(patch
), allPatches(allPatches
), State(StateFetchDiff
)
1004 Debug
= _config
->FindB("Debug::pkgAcquire::Diffs",false);
1006 RealURI
= Target
->URI
;
1008 Description
= Target
->Description
;
1009 Desc
.ShortDesc
= Target
->ShortDesc
;
1011 Desc
.URI
= RealURI
+ ".diff/" + patch
.file
+ ".gz";
1012 Desc
.Description
= Description
+ " " + patch
.file
+ string(".pdiff");
1014 DestFile
= GetPartialFileNameFromURI(RealURI
+ ".diff/" + patch
.file
);
1017 std::clog
<< "pkgAcqIndexMergeDiffs: " << Desc
.URI
<< std::endl
;
1022 void pkgAcqIndexMergeDiffs::Failed(string Message
,pkgAcquire::MethodConfig
* Cnf
)/*{{{*/
1025 std::clog
<< "pkgAcqIndexMergeDiffs failed: " << Desc
.URI
<< " with " << Message
<< std::endl
;
1027 Item::Failed(Message
,Cnf
);
1030 // check if we are the first to fail, otherwise we are done here
1031 State
= StateDoneDiff
;
1032 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1033 I
!= allPatches
->end(); ++I
)
1034 if ((*I
)->State
== StateErrorDiff
)
1037 // first failure means we should fallback
1038 State
= StateErrorDiff
;
1039 std::clog
<< "Falling back to normal index file acquire" << std::endl
;
1040 new pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
);
1043 void pkgAcqIndexMergeDiffs::Done(string Message
,unsigned long long Size
,HashStringList
const &Hashes
, /*{{{*/
1044 pkgAcquire::MethodConfig
*Cnf
)
1047 std::clog
<< "pkgAcqIndexMergeDiffs::Done(): " << Desc
.URI
<< std::endl
;
1049 Item::Done(Message
,Size
,Hashes
,Cnf
);
1051 // FIXME: verify download before feeding it to rred
1052 string
const FinalFile
= GetPartialFileNameFromURI(RealURI
);
1054 if (State
== StateFetchDiff
)
1056 FileFd
fd(DestFile
, FileFd::ReadOnly
, FileFd::Gzip
);
1057 class Hashes LocalHashesCalc
;
1058 LocalHashesCalc
.AddFD(fd
);
1059 HashStringList
const LocalHashes
= LocalHashesCalc
.GetHashStringList();
1061 if (fd
.Size() != patch
.patch_size
|| patch
.patch_hashes
!= LocalHashes
)
1063 Failed("Patch has Size/Hashsum mismatch", NULL
);
1067 // rred expects the patch as $FinalFile.ed.$patchname.gz
1068 Rename(DestFile
, FinalFile
+ ".ed." + patch
.file
+ ".gz");
1070 // check if this is the last completed diff
1071 State
= StateDoneDiff
;
1072 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1073 I
!= allPatches
->end(); ++I
)
1074 if ((*I
)->State
!= StateDoneDiff
)
1077 std::clog
<< "Not the last done diff in the batch: " << Desc
.URI
<< std::endl
;
1081 // this is the last completed diff, so we are ready to apply now
1082 State
= StateApplyDiff
;
1085 std::clog
<< "Sending to rred method: " << FinalFile
<< std::endl
;
1088 Desc
.URI
= "rred:" + FinalFile
;
1090 SetActiveSubprocess("rred");
1093 // success in download/apply all diffs, clean up
1094 else if (State
== StateApplyDiff
)
1096 // see if we really got the expected file
1097 if(ExpectedHashes
.usable() && !ExpectedHashes
.VerifyFile(DestFile
))
1099 RenameOnError(HashSumMismatch
);
1104 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1105 FinalFile
+= URItoFileName(RealURI
);
1107 // move the result into place
1109 std::clog
<< "Queue patched file in place: " << std::endl
1110 << DestFile
<< " -> " << FinalFile
<< std::endl
;
1112 // queue for copy by the transaction manager
1113 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1115 // ensure the ed's are gone regardless of list-cleanup
1116 for (std::vector
<pkgAcqIndexMergeDiffs
*>::const_iterator I
= allPatches
->begin();
1117 I
!= allPatches
->end(); ++I
)
1119 std::string
const PartialFile
= GetPartialFileNameFromURI(RealURI
);
1120 std::string patch
= PartialFile
+ ".ed." + (*I
)->patch
.file
+ ".gz";
1121 unlink(patch
.c_str());
1127 std::clog
<< "allDone: " << DestFile
<< "\n" << std::endl
;
1131 // AcqBaseIndex::VerifyHashByMetaKey - verify hash for the given metakey /*{{{*/
1132 bool pkgAcqBaseIndex::VerifyHashByMetaKey(HashStringList
const &Hashes
)
1134 if(MetaKey
!= "" && Hashes
.usable())
1136 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1137 if(Record
&& Record
->Hashes
.usable() && Hashes
!= Record
->Hashes
)
1139 printHashSumComparision(RealURI
, Record
->Hashes
, Hashes
);
1146 // AcqIndex::AcqIndex - Constructor /*{{{*/
1147 // ---------------------------------------------------------------------
1148 /* The package file is added to the queue and a second class is
1149 instantiated to fetch the revision file */
1150 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1151 string URI
,string URIDesc
,string ShortDesc
,
1152 HashStringList
const &ExpectedHash
)
1153 : pkgAcqBaseIndex(Owner
, 0, NULL
, ExpectedHash
, NULL
)
1157 AutoSelectCompression();
1158 Init(URI
, URIDesc
, ShortDesc
);
1160 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1161 std::clog
<< "New pkgIndex with TransactionManager "
1162 << TransactionManager
<< std::endl
;
1165 // AcqIndex::AcqIndex - Constructor /*{{{*/
1166 pkgAcqIndex::pkgAcqIndex(pkgAcquire
*Owner
,
1167 pkgAcqMetaBase
*TransactionManager
,
1168 IndexTarget
const *Target
,
1169 HashStringList
const &ExpectedHash
,
1170 indexRecords
*MetaIndexParser
)
1171 : pkgAcqBaseIndex(Owner
, TransactionManager
, Target
, ExpectedHash
,
1174 RealURI
= Target
->URI
;
1176 // autoselect the compression method
1177 AutoSelectCompression();
1178 Init(Target
->URI
, Target
->Description
, Target
->ShortDesc
);
1180 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1181 std::clog
<< "New pkgIndex with TransactionManager "
1182 << TransactionManager
<< std::endl
;
1185 // AcqIndex::AutoSelectCompression - Select compression /*{{{*/
1186 void pkgAcqIndex::AutoSelectCompression()
1188 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
1189 CompressionExtensions
= "";
1190 if (ExpectedHashes
.usable())
1192 for (std::vector
<std::string
>::const_iterator t
= types
.begin();
1193 t
!= types
.end(); ++t
)
1195 std::string CompressedMetaKey
= string(Target
->MetaKey
).append(".").append(*t
);
1196 if (*t
== "uncompressed" ||
1197 MetaIndexParser
->Exists(CompressedMetaKey
) == true)
1198 CompressionExtensions
.append(*t
).append(" ");
1203 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
1204 CompressionExtensions
.append(*t
).append(" ");
1206 if (CompressionExtensions
.empty() == false)
1207 CompressionExtensions
.erase(CompressionExtensions
.end()-1);
1210 // AcqIndex::Init - defered Constructor /*{{{*/
1211 void pkgAcqIndex::Init(string
const &URI
, string
const &URIDesc
,
1212 string
const &ShortDesc
)
1214 Stage
= STAGE_DOWNLOAD
;
1216 DestFile
= GetPartialFileNameFromURI(URI
);
1218 CurrentCompressionExtension
= CompressionExtensions
.substr(0, CompressionExtensions
.find(' '));
1219 if (CurrentCompressionExtension
== "uncompressed")
1223 MetaKey
= string(Target
->MetaKey
);
1227 Desc
.URI
= URI
+ '.' + CurrentCompressionExtension
;
1228 DestFile
= DestFile
+ '.' + CurrentCompressionExtension
;
1230 MetaKey
= string(Target
->MetaKey
) + '.' + CurrentCompressionExtension
;
1233 // load the filesize
1236 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1238 FileSize
= Record
->Size
;
1240 InitByHashIfNeeded(MetaKey
);
1243 Desc
.Description
= URIDesc
;
1245 Desc
.ShortDesc
= ShortDesc
;
1250 // AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
1251 void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey
)
1254 // - (maybe?) add support for by-hash into the sources.list as flag
1255 // - make apt-ftparchive generate the hashes (and expire?)
1256 std::string HostKnob
= "APT::Acquire::" + ::URI(Desc
.URI
).Host
+ "::By-Hash";
1257 if(_config
->FindB("APT::Acquire::By-Hash", false) == true ||
1258 _config
->FindB(HostKnob
, false) == true ||
1259 MetaIndexParser
->GetSupportsAcquireByHash())
1261 indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup(MetaKey
);
1264 // FIXME: should we really use the best hash here? or a fixed one?
1265 const HashString
*TargetHash
= Record
->Hashes
.find("");
1266 std::string ByHash
= "/by-hash/" + TargetHash
->HashType() + "/" + TargetHash
->HashValue();
1267 size_t trailing_slash
= Desc
.URI
.find_last_of("/");
1268 Desc
.URI
= Desc
.URI
.replace(
1270 Desc
.URI
.substr(trailing_slash
+1).size()+1,
1274 "Fetching ByHash requested but can not find record for %s",
1280 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
1281 // ---------------------------------------------------------------------
1282 /* The only header we use is the last-modified header. */
1283 string
pkgAcqIndex::Custom600Headers() const
1285 string Final
= GetFinalFilename();
1287 string msg
= "\nIndex-File: true";
1289 if (stat(Final
.c_str(),&Buf
) == 0)
1290 msg
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1295 // pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
1296 void pkgAcqIndex::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1298 Item::Failed(Message
,Cnf
);
1300 size_t const nextExt
= CompressionExtensions
.find(' ');
1301 if (nextExt
!= std::string::npos
)
1303 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1304 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1309 // on decompression failure, remove bad versions in partial/
1310 if (Stage
== STAGE_DECOMPRESS_AND_VERIFY
)
1312 unlink(EraseFileName
.c_str());
1315 /// cancel the entire transaction
1316 TransactionManager
->AbortTransaction();
1319 // pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
1320 std::string
pkgAcqIndex::GetFinalFilename() const
1322 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1323 FinalFile
+= URItoFileName(RealURI
);
1324 return GetCompressedFileName(RealURI
, FinalFile
, CurrentCompressionExtension
);
1327 // AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
1328 void pkgAcqIndex::ReverifyAfterIMS()
1330 // update destfile to *not* include the compression extension when doing
1331 // a reverify (as its uncompressed on disk already)
1332 DestFile
= GetCompressedFileName(RealURI
, GetPartialFileNameFromURI(RealURI
), CurrentCompressionExtension
);
1334 // copy FinalFile into partial/ so that we check the hash again
1335 string FinalFile
= GetFinalFilename();
1336 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1337 Desc
.URI
= "copy:" + FinalFile
;
1341 // AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
1342 bool pkgAcqIndex::ValidateFile(const std::string
&FileName
)
1344 // FIXME: this can go away once we only ever download stuff that
1345 // has a valid hash and we never do GET based probing
1346 // FIXME2: this also leaks debian-isms into the code and should go therefore
1348 /* Always validate the index file for correctness (all indexes must
1349 * have a Package field) (LP: #346386) (Closes: #627642)
1351 FileFd
fd(FileName
, FileFd::ReadOnly
, FileFd::Extension
);
1352 // Only test for correctness if the content of the file is not empty
1357 pkgTagFile
tag(&fd
);
1359 // all our current indexes have a field 'Package' in each section
1360 if (_error
->PendingError() == true ||
1361 tag
.Step(sec
) == false ||
1362 sec
.Exists("Package") == false)
1368 // AcqIndex::Done - Finished a fetch /*{{{*/
1369 // ---------------------------------------------------------------------
1370 /* This goes through a number of states.. On the initial fetch the
1371 method could possibly return an alternate filename which points
1372 to the uncompressed version of the file. If this is so the file
1373 is copied into the partial directory. In all other cases the file
1374 is decompressed with a compressed uri. */
1375 void pkgAcqIndex::Done(string Message
,
1376 unsigned long long Size
,
1377 HashStringList
const &Hashes
,
1378 pkgAcquire::MethodConfig
*Cfg
)
1380 Item::Done(Message
,Size
,Hashes
,Cfg
);
1384 case STAGE_DOWNLOAD
:
1385 StageDownloadDone(Message
, Hashes
, Cfg
);
1387 case STAGE_DECOMPRESS_AND_VERIFY
:
1388 StageDecompressDone(Message
, Hashes
, Cfg
);
1393 // AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
1394 void pkgAcqIndex::StageDownloadDone(string Message
,
1395 HashStringList
const &Hashes
,
1396 pkgAcquire::MethodConfig
*Cfg
)
1398 // First check if the calculcated Hash of the (compressed) downloaded
1399 // file matches the hash we have in the MetaIndexRecords for this file
1400 if(VerifyHashByMetaKey(Hashes
) == false)
1402 RenameOnError(HashSumMismatch
);
1403 Failed(Message
, Cfg
);
1409 // Handle the unzipd case
1410 string FileName
= LookupTag(Message
,"Alt-Filename");
1411 if (FileName
.empty() == false)
1413 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1415 DestFile
+= ".decomp";
1416 Desc
.URI
= "copy:" + FileName
;
1418 SetActiveSubprocess("copy");
1422 FileName
= LookupTag(Message
,"Filename");
1423 if (FileName
.empty() == true)
1426 ErrorText
= "Method gave a blank filename";
1429 // Methods like e.g. "file:" will give us a (compressed) FileName that is
1430 // not the "DestFile" we set, in this case we uncompress from the local file
1431 if (FileName
!= DestFile
)
1434 EraseFileName
= FileName
;
1436 // we need to verify the file against the current Release file again
1437 // on if-modfied-since hit to avoid a stale attack against us
1438 if(StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
1440 // The files timestamp matches, reverify by copy into partial/
1446 // If we have compressed indexes enabled, queue for hash verification
1447 if (_config
->FindB("Acquire::GzipIndexes",false))
1449 DestFile
= GetPartialFileNameFromURI(RealURI
+ '.' + CurrentCompressionExtension
);
1451 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1452 Desc
.URI
= "copy:" + FileName
;
1454 SetActiveSubprocess("copy");
1458 // get the binary name for your used compression type
1460 if(CurrentCompressionExtension
== "uncompressed")
1461 decompProg
= "copy";
1463 decompProg
= _config
->Find(string("Acquire::CompressionTypes::").append(CurrentCompressionExtension
),"");
1464 if(decompProg
.empty() == true)
1466 _error
->Error("Unsupported extension: %s", CurrentCompressionExtension
.c_str());
1470 // queue uri for the next stage
1471 Stage
= STAGE_DECOMPRESS_AND_VERIFY
;
1472 DestFile
+= ".decomp";
1473 Desc
.URI
= decompProg
+ ":" + FileName
;
1475 SetActiveSubprocess(decompProg
);
1478 // pkgAcqIndex::StageDecompressDone - Final verification /*{{{*/
1479 void pkgAcqIndex::StageDecompressDone(string Message
,
1480 HashStringList
const &Hashes
,
1481 pkgAcquire::MethodConfig
*Cfg
)
1483 if (ExpectedHashes
.usable() && ExpectedHashes
!= Hashes
)
1486 RenameOnError(HashSumMismatch
);
1487 printHashSumComparision(RealURI
, ExpectedHashes
, Hashes
);
1488 Failed(Message
, Cfg
);
1492 if(!ValidateFile(DestFile
))
1494 RenameOnError(InvalidFormat
);
1495 Failed(Message
, Cfg
);
1499 // remove the compressed version of the file
1500 unlink(EraseFileName
.c_str());
1502 // Done, queue for rename on transaction finished
1503 TransactionManager
->TransactionStageCopy(this, DestFile
, GetFinalFilename());
1508 // AcqIndexTrans::pkgAcqIndexTrans - Constructor /*{{{*/
1509 // ---------------------------------------------------------------------
1510 /* The Translation file is added to the queue */
1511 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1512 string URI
,string URIDesc
,string ShortDesc
)
1513 : pkgAcqIndex(Owner
, URI
, URIDesc
, ShortDesc
, HashStringList())
1516 pkgAcqIndexTrans::pkgAcqIndexTrans(pkgAcquire
*Owner
,
1517 pkgAcqMetaBase
*TransactionManager
,
1518 IndexTarget
const * const Target
,
1519 HashStringList
const &ExpectedHashes
,
1520 indexRecords
*MetaIndexParser
)
1521 : pkgAcqIndex(Owner
, TransactionManager
, Target
, ExpectedHashes
, MetaIndexParser
)
1525 // AcqIndexTrans::Custom600Headers - Insert custom request headers /*{{{*/
1526 string
pkgAcqIndexTrans::Custom600Headers() const
1528 string Final
= GetFinalFilename();
1531 if (stat(Final
.c_str(),&Buf
) != 0)
1532 return "\nFail-Ignore: true\nIndex-File: true";
1533 return "\nFail-Ignore: true\nIndex-File: true\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1536 // AcqIndexTrans::Failed - Silence failure messages for missing files /*{{{*/
1537 void pkgAcqIndexTrans::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
1539 Item::Failed(Message
,Cnf
);
1541 size_t const nextExt
= CompressionExtensions
.find(' ');
1542 if (nextExt
!= std::string::npos
)
1544 CompressionExtensions
= CompressionExtensions
.substr(nextExt
+1);
1545 Init(RealURI
, Desc
.Description
, Desc
.ShortDesc
);
1550 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1551 if (Cnf
->LocalOnly
== true ||
1552 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1559 // AcqMetaBase::Add - Add a item to the current Transaction /*{{{*/
1560 void pkgAcqMetaBase::Add(Item
*I
)
1562 Transaction
.push_back(I
);
1565 // AcqMetaBase::AbortTransaction - Abort the current Transaction /*{{{*/
1566 void pkgAcqMetaBase::AbortTransaction()
1568 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1569 std::clog
<< "AbortTransaction: " << TransactionManager
<< std::endl
;
1571 // ensure the toplevel is in error state too
1572 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1573 I
!= Transaction
.end(); ++I
)
1575 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1576 std::clog
<< " Cancel: " << (*I
)->DestFile
<< std::endl
;
1577 // the transaction will abort, so stop anything that is idle
1578 if ((*I
)->Status
== pkgAcquire::Item::StatIdle
)
1579 (*I
)->Status
= pkgAcquire::Item::StatDone
;
1581 // reverify might act on a file outside of partial
1582 // (as it itself is good, but needed to verify others, like Release)
1583 if ((*I
)->DestFile
== (*I
)->PartialFile
&& RealFileExists((*I
)->DestFile
))
1584 ChangeOwnerAndPermissionOfFile("AbortTransaction", (*I
)->DestFile
.c_str(), "root", "root", 0644);
1586 Transaction
.clear();
1589 // AcqMetaBase::TransactionHasError - Check for errors in Transaction /*{{{*/
1590 bool pkgAcqMetaBase::TransactionHasError()
1592 for (pkgAcquire::ItemIterator I
= Transaction
.begin();
1593 I
!= Transaction
.end(); ++I
)
1594 if((*I
)->Status
!= pkgAcquire::Item::StatDone
&&
1595 (*I
)->Status
!= pkgAcquire::Item::StatIdle
)
1601 // AcqMetaBase::CommitTransaction - Commit a transaction /*{{{*/
1602 void pkgAcqMetaBase::CommitTransaction()
1604 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1605 std::clog
<< "CommitTransaction: " << this << std::endl
;
1607 // move new files into place *and* remove files that are not
1608 // part of the transaction but are still on disk
1609 for (std::vector
<Item
*>::iterator I
= Transaction
.begin();
1610 I
!= Transaction
.end(); ++I
)
1612 if((*I
)->PartialFile
!= "")
1614 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1615 std::clog
<< "mv " << (*I
)->PartialFile
<< " -> "<< (*I
)->DestFile
<< " "
1616 << (*I
)->DescURI() << std::endl
;
1618 Rename((*I
)->PartialFile
, (*I
)->DestFile
);
1620 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1626 unlink((*I
)->DestFile
.c_str());
1628 // mark that this transaction is finished
1629 (*I
)->TransactionManager
= 0;
1631 Transaction
.clear();
1634 // AcqMetaBase::TransactionStageCopy - Stage a file for copying /*{{{*/
1635 void pkgAcqMetaBase::TransactionStageCopy(Item
*I
,
1636 const std::string
&From
,
1637 const std::string
&To
)
1639 I
->PartialFile
= From
;
1643 // AcqMetaBase::TransactionStageRemoval - Sage a file for removal /*{{{*/
1644 void pkgAcqMetaBase::TransactionStageRemoval(Item
*I
,
1645 const std::string
&FinalFile
)
1647 I
->PartialFile
= "";
1648 I
->DestFile
= FinalFile
;
1651 // AcqMetaBase::GenerateAuthWarning - Check gpg authentication error /*{{{*/
1652 bool pkgAcqMetaBase::CheckStopAuthentication(const std::string
&RealURI
,
1653 const std::string
&Message
)
1655 // FIXME: this entire function can do now that we disallow going to
1656 // a unauthenticated state and can cleanly rollback
1658 string Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1660 if(FileExists(Final
))
1662 Status
= StatTransientNetworkError
;
1663 _error
->Warning(_("An error occurred during the signature "
1664 "verification. The repository is not updated "
1665 "and the previous index files will be used. "
1666 "GPG error: %s: %s\n"),
1667 Desc
.Description
.c_str(),
1668 LookupTag(Message
,"Message").c_str());
1669 RunScripts("APT::Update::Auth-Failure");
1671 } else if (LookupTag(Message
,"Message").find("NODATA") != string::npos
) {
1672 /* Invalid signature file, reject (LP: #346386) (Closes: #627642) */
1673 _error
->Error(_("GPG error: %s: %s"),
1674 Desc
.Description
.c_str(),
1675 LookupTag(Message
,"Message").c_str());
1679 _error
->Warning(_("GPG error: %s: %s"),
1680 Desc
.Description
.c_str(),
1681 LookupTag(Message
,"Message").c_str());
1683 // gpgv method failed
1684 ReportMirrorFailure("GPGFailure");
1688 // AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
1689 pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire
*Owner
,
1690 pkgAcqMetaBase
*TransactionManager
,
1691 string URI
,string URIDesc
,string ShortDesc
,
1692 string MetaIndexFile
,
1693 const vector
<IndexTarget
*>* IndexTargets
,
1694 indexRecords
* MetaIndexParser
) :
1695 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
,
1696 HashStringList(), TransactionManager
),
1697 RealURI(URI
), MetaIndexFile(MetaIndexFile
), URIDesc(URIDesc
),
1698 ShortDesc(ShortDesc
)
1700 DestFile
= _config
->FindDir("Dir::State::lists") + "partial/";
1701 DestFile
+= URItoFileName(RealURI
);
1703 // remove any partial downloaded sig-file in partial/.
1704 // it may confuse proxies and is too small to warrant a
1705 // partial download anyway
1706 unlink(DestFile
.c_str());
1708 // set the TransactionManager
1709 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1710 std::clog
<< "New pkgAcqMetaSig with TransactionManager "
1711 << TransactionManager
<< std::endl
;
1714 Desc
.Description
= URIDesc
;
1716 Desc
.ShortDesc
= ShortDesc
;
1722 pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
1726 // pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
1727 // ---------------------------------------------------------------------
1728 string
pkgAcqMetaSig::Custom600Headers() const
1730 std::string Header
= GetCustom600Headers(RealURI
);
1734 // pkgAcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
1735 // ---------------------------------------------------------------------
1736 /* The only header we use is the last-modified header. */
1737 void pkgAcqMetaSig::Done(string Message
,unsigned long long Size
,
1738 HashStringList
const &Hashes
,
1739 pkgAcquire::MethodConfig
*Cfg
)
1741 Item::Done(Message
, Size
, Hashes
, Cfg
);
1743 if(AuthPass
== false)
1745 if(CheckDownloadDone(Message
, RealURI
) == true)
1747 // destfile will be modified to point to MetaIndexFile for the
1748 // gpgv method, so we need to save it here
1749 MetaIndexFileSignature
= DestFile
;
1750 QueueForSignatureVerify(MetaIndexFile
, MetaIndexFileSignature
);
1756 if(CheckAuthDone(Message
, RealURI
) == true)
1758 std::string FinalFile
= _config
->FindDir("Dir::State::lists");
1759 FinalFile
+= URItoFileName(RealURI
);
1760 TransactionManager
->TransactionStageCopy(this, MetaIndexFileSignature
, FinalFile
);
1765 void pkgAcqMetaSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)/*{{{*/
1767 Item::Failed(Message
,Cnf
);
1769 // check if we need to fail at this point
1770 if (AuthPass
== true && CheckStopAuthentication(RealURI
, Message
))
1773 // FIXME: meh, this is not really elegant
1774 string
const Final
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
1775 string
const InReleaseURI
= RealURI
.replace(RealURI
.rfind("Release.gpg"), 12,
1777 string
const FinalInRelease
= _config
->FindDir("Dir::State::lists") + URItoFileName(InReleaseURI
);
1779 if (RealFileExists(Final
) || RealFileExists(FinalInRelease
))
1781 std::string downgrade_msg
;
1782 strprintf(downgrade_msg
, _("The repository '%s' is no longer signed."),
1784 if(_config
->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
1786 // meh, the users wants to take risks (we still mark the packages
1787 // from this repository as unauthenticated)
1788 _error
->Warning("%s", downgrade_msg
.c_str());
1789 _error
->Warning(_("This is normally not allowed, but the option "
1790 "Acquire::AllowDowngradeToInsecureRepositories was "
1791 "given to override it."));
1794 _error
->Error("%s", downgrade_msg
.c_str());
1795 Rename(MetaIndexFile
, MetaIndexFile
+".FAILED");
1796 Item::Failed("Message: " + downgrade_msg
, Cnf
);
1797 TransactionManager
->AbortTransaction();
1802 _error
->Warning(_("The data from '%s' is not signed. Packages "
1803 "from that repository can not be authenticated."),
1806 // this ensures that any file in the lists/ dir is removed by the
1808 DestFile
= GetPartialFileNameFromURI(RealURI
);
1809 TransactionManager
->TransactionStageRemoval(this, DestFile
);
1811 // only allow going further if the users explicitely wants it
1812 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
1814 // we parse the indexes here because at this point the user wanted
1815 // a repository that may potentially harm him
1816 MetaIndexParser
->Load(MetaIndexFile
);
1820 // FIXME: this is used often (e.g. in pkgAcqIndexTrans) so refactor
1821 if (Cnf
->LocalOnly
== true ||
1822 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == false)
1829 pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire
*Owner
, /*{{{*/
1830 pkgAcqMetaBase
*TransactionManager
,
1831 string URI
,string URIDesc
,string ShortDesc
,
1832 string MetaIndexSigURI
,string MetaIndexSigURIDesc
, string MetaIndexSigShortDesc
,
1833 const vector
<IndexTarget
*>* IndexTargets
,
1834 indexRecords
* MetaIndexParser
) :
1835 pkgAcqMetaBase(Owner
, IndexTargets
, MetaIndexParser
, HashStringList(),
1836 TransactionManager
),
1837 RealURI(URI
), URIDesc(URIDesc
), ShortDesc(ShortDesc
),
1838 MetaIndexSigURI(MetaIndexSigURI
), MetaIndexSigURIDesc(MetaIndexSigURIDesc
),
1839 MetaIndexSigShortDesc(MetaIndexSigShortDesc
)
1841 if(TransactionManager
== NULL
)
1843 this->TransactionManager
= this;
1844 this->TransactionManager
->Add(this);
1847 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
1848 std::clog
<< "New pkgAcqMetaIndex with TransactionManager "
1849 << this->TransactionManager
<< std::endl
;
1852 Init(URIDesc
, ShortDesc
);
1855 // pkgAcqMetaIndex::Init - Delayed constructor /*{{{*/
1856 void pkgAcqMetaIndex::Init(std::string URIDesc
, std::string ShortDesc
)
1858 DestFile
= GetPartialFileNameFromURI(RealURI
);
1861 Desc
.Description
= URIDesc
;
1863 Desc
.ShortDesc
= ShortDesc
;
1866 // we expect more item
1867 ExpectedAdditionalItems
= IndexTargets
->size();
1871 // pkgAcqMetaIndex::Custom600Headers - Insert custom request headers /*{{{*/
1872 // ---------------------------------------------------------------------
1873 string
pkgAcqMetaIndex::Custom600Headers() const
1875 return GetCustom600Headers(RealURI
);
1878 void pkgAcqMetaIndex::Done(string Message
,unsigned long long Size
, /*{{{*/
1879 HashStringList
const &Hashes
,
1880 pkgAcquire::MethodConfig
*Cfg
)
1882 Item::Done(Message
,Size
,Hashes
,Cfg
);
1884 if(CheckDownloadDone(Message
, RealURI
))
1886 // we have a Release file, now download the Signature, all further
1887 // verify/queue for additional downloads will be done in the
1888 // pkgAcqMetaSig::Done() code
1889 std::string MetaIndexFile
= DestFile
;
1890 new pkgAcqMetaSig(Owner
, TransactionManager
,
1891 MetaIndexSigURI
, MetaIndexSigURIDesc
,
1892 MetaIndexSigShortDesc
, MetaIndexFile
, IndexTargets
,
1895 string FinalFile
= _config
->FindDir("Dir::State::lists");
1896 FinalFile
+= URItoFileName(RealURI
);
1897 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
1901 bool pkgAcqMetaBase::CheckAuthDone(string Message
, const string
&RealURI
) /*{{{*/
1903 // At this point, the gpgv method has succeeded, so there is a
1904 // valid signature from a key in the trusted keyring. We
1905 // perform additional verification of its contents, and use them
1906 // to verify the indexes we are about to download
1908 if (!MetaIndexParser
->Load(DestFile
))
1910 Status
= StatAuthError
;
1911 ErrorText
= MetaIndexParser
->ErrorText
;
1915 if (!VerifyVendor(Message
, RealURI
))
1920 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
1921 std::cerr
<< "Signature verification succeeded: "
1922 << DestFile
<< std::endl
;
1924 // Download further indexes with verification
1926 // it would be really nice if we could simply do
1927 // if (IMSHit == false) QueueIndexes(true)
1928 // and skip the download if the Release file has not changed
1929 // - but right now the list cleaner will needs to be tricked
1930 // to not delete all our packages/source indexes in this case
1936 // pkgAcqMetaBase::GetCustom600Headers - Get header for AcqMetaBase /*{{{*/
1937 // ---------------------------------------------------------------------
1938 string
pkgAcqMetaBase::GetCustom600Headers(const string
&RealURI
) const
1940 std::string Header
= "\nIndex-File: true";
1941 std::string MaximumSize
;
1942 strprintf(MaximumSize
, "\nMaximum-Size: %i",
1943 _config
->FindI("Acquire::MaxReleaseFileSize", 10*1000*1000));
1944 Header
+= MaximumSize
;
1946 string FinalFile
= _config
->FindDir("Dir::State::lists");
1947 FinalFile
+= URItoFileName(RealURI
);
1950 if (stat(FinalFile
.c_str(),&Buf
) == 0)
1951 Header
+= "\nLast-Modified: " + TimeRFC1123(Buf
.st_mtime
);
1956 // pkgAcqMetaBase::QueueForSignatureVerify /*{{{*/
1957 void pkgAcqMetaBase::QueueForSignatureVerify(const std::string
&MetaIndexFile
,
1958 const std::string
&MetaIndexFileSignature
)
1961 Desc
.URI
= "gpgv:" + MetaIndexFileSignature
;
1962 DestFile
= MetaIndexFile
;
1964 SetActiveSubprocess("gpgv");
1967 // pkgAcqMetaBase::CheckDownloadDone /*{{{*/
1968 bool pkgAcqMetaBase::CheckDownloadDone(const std::string
&Message
,
1969 const std::string
&RealURI
)
1971 // We have just finished downloading a Release file (it is not
1974 string FileName
= LookupTag(Message
,"Filename");
1975 if (FileName
.empty() == true)
1978 ErrorText
= "Method gave a blank filename";
1982 if (FileName
!= DestFile
)
1985 Desc
.URI
= "copy:" + FileName
;
1990 // make sure to verify against the right file on I-M-S hit
1991 IMSHit
= StringToBool(LookupTag(Message
,"IMS-Hit"),false);
1994 string FinalFile
= _config
->FindDir("Dir::State::lists");
1995 FinalFile
+= URItoFileName(RealURI
);
1996 DestFile
= FinalFile
;
1999 // set Item to complete as the remaining work is all local (verify etc)
2005 void pkgAcqMetaBase::QueueIndexes(bool verify
) /*{{{*/
2007 bool transInRelease
= false;
2009 std::vector
<std::string
> const keys
= MetaIndexParser
->MetaKeys();
2010 for (std::vector
<std::string
>::const_iterator k
= keys
.begin(); k
!= keys
.end(); ++k
)
2011 // FIXME: Feels wrong to check for hardcoded string here, but what should we do else…
2012 if (k
->find("Translation-") != std::string::npos
)
2014 transInRelease
= true;
2019 // at this point the real Items are loaded in the fetcher
2020 ExpectedAdditionalItems
= 0;
2021 for (vector
<IndexTarget
*>::const_iterator Target
= IndexTargets
->begin();
2022 Target
!= IndexTargets
->end();
2025 HashStringList ExpectedIndexHashes
;
2026 const indexRecords::checkSum
*Record
= MetaIndexParser
->Lookup((*Target
)->MetaKey
);
2027 bool compressedAvailable
= false;
2030 if ((*Target
)->IsOptional() == true)
2032 std::vector
<std::string
> types
= APT::Configuration::getCompressionTypes();
2033 for (std::vector
<std::string
>::const_iterator t
= types
.begin(); t
!= types
.end(); ++t
)
2034 if (MetaIndexParser
->Exists((*Target
)->MetaKey
+ "." + *t
) == true)
2036 compressedAvailable
= true;
2040 else if (verify
== true)
2042 Status
= StatAuthError
;
2043 strprintf(ErrorText
, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target
)->MetaKey
.c_str());
2049 ExpectedIndexHashes
= Record
->Hashes
;
2050 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2052 std::cerr
<< "Queueing: " << (*Target
)->URI
<< std::endl
2053 << "Expected Hash:" << std::endl
;
2054 for (HashStringList::const_iterator hs
= ExpectedIndexHashes
.begin(); hs
!= ExpectedIndexHashes
.end(); ++hs
)
2055 std::cerr
<< "\t- " << hs
->toStr() << std::endl
;
2056 std::cerr
<< "For: " << Record
->MetaKeyFilename
<< std::endl
;
2058 if (verify
== true && ExpectedIndexHashes
.empty() == true && (*Target
)->IsOptional() == false)
2060 Status
= StatAuthError
;
2061 strprintf(ErrorText
, _("Unable to find hash sum for '%s' in Release file"), (*Target
)->MetaKey
.c_str());
2066 if ((*Target
)->IsOptional() == true)
2068 if (transInRelease
== false || Record
!= NULL
|| compressedAvailable
== true)
2070 if (_config
->FindB("Acquire::PDiffs",true) == true && transInRelease
== true &&
2071 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true)
2072 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2074 new pkgAcqIndexTrans(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2079 /* Queue Packages file (either diff or full packages files, depending
2080 on the users option) - we also check if the PDiff Index file is listed
2081 in the Meta-Index file. Ideal would be if pkgAcqDiffIndex would test this
2082 instead, but passing the required info to it is to much hassle */
2083 if(_config
->FindB("Acquire::PDiffs",true) == true && (verify
== false ||
2084 MetaIndexParser
->Exists((*Target
)->MetaKey
+ ".diff/Index") == true))
2085 new pkgAcqDiffIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2087 new pkgAcqIndex(Owner
, TransactionManager
, *Target
, ExpectedIndexHashes
, MetaIndexParser
);
2091 bool pkgAcqMetaBase::VerifyVendor(string Message
, const string
&RealURI
)/*{{{*/
2093 string::size_type pos
;
2095 // check for missing sigs (that where not fatal because otherwise we had
2098 string msg
= _("There is no public key available for the "
2099 "following key IDs:\n");
2100 pos
= Message
.find("NO_PUBKEY ");
2101 if (pos
!= std::string::npos
)
2103 string::size_type start
= pos
+strlen("NO_PUBKEY ");
2104 string Fingerprint
= Message
.substr(start
, Message
.find("\n")-start
);
2105 missingkeys
+= (Fingerprint
);
2107 if(!missingkeys
.empty())
2108 _error
->Warning("%s", (msg
+ missingkeys
).c_str());
2110 string Transformed
= MetaIndexParser
->GetExpectedDist();
2112 if (Transformed
== "../project/experimental")
2114 Transformed
= "experimental";
2117 pos
= Transformed
.rfind('/');
2118 if (pos
!= string::npos
)
2120 Transformed
= Transformed
.substr(0, pos
);
2123 if (Transformed
== ".")
2128 if (_config
->FindB("Acquire::Check-Valid-Until", true) == true &&
2129 MetaIndexParser
->GetValidUntil() > 0) {
2130 time_t const invalid_since
= time(NULL
) - MetaIndexParser
->GetValidUntil();
2131 if (invalid_since
> 0)
2132 // TRANSLATOR: The first %s is the URL of the bad Release file, the second is
2133 // the time since then the file is invalid - formated in the same way as in
2134 // the download progress display (e.g. 7d 3h 42min 1s)
2135 return _error
->Error(
2136 _("Release file for %s is expired (invalid since %s). "
2137 "Updates for this repository will not be applied."),
2138 RealURI
.c_str(), TimeToStr(invalid_since
).c_str());
2141 if (_config
->FindB("Debug::pkgAcquire::Auth", false))
2143 std::cerr
<< "Got Codename: " << MetaIndexParser
->GetDist() << std::endl
;
2144 std::cerr
<< "Expecting Dist: " << MetaIndexParser
->GetExpectedDist() << std::endl
;
2145 std::cerr
<< "Transformed Dist: " << Transformed
<< std::endl
;
2148 if (MetaIndexParser
->CheckDist(Transformed
) == false)
2150 // This might become fatal one day
2151 // Status = StatAuthError;
2152 // ErrorText = "Conflicting distribution; expected "
2153 // + MetaIndexParser->GetExpectedDist() + " but got "
2154 // + MetaIndexParser->GetDist();
2156 if (!Transformed
.empty())
2158 _error
->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
2159 Desc
.Description
.c_str(),
2160 Transformed
.c_str(),
2161 MetaIndexParser
->GetDist().c_str());
2168 // pkgAcqMetaIndex::Failed - no Release file present /*{{{*/
2169 void pkgAcqMetaIndex::Failed(string Message
,
2170 pkgAcquire::MethodConfig
* Cnf
)
2172 pkgAcquire::Item::Failed(Message
, Cnf
);
2175 string FinalFile
= _config
->FindDir("Dir::State::lists") + URItoFileName(RealURI
);
2177 _error
->Warning(_("The repository '%s' does not have a Release file. "
2178 "This is deprecated, please contact the owner of the "
2179 "repository."), URIDesc
.c_str());
2181 // No Release file was present so fall
2182 // back to queueing Packages files without verification
2183 // only allow going further if the users explicitely wants it
2184 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2186 // Done, queue for rename on transaction finished
2187 if (FileExists(DestFile
))
2188 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2190 // queue without any kind of hashsum support
2191 QueueIndexes(false);
2195 void pkgAcqMetaIndex::Finished() /*{{{*/
2197 if(_config
->FindB("Debug::Acquire::Transaction", false) == true)
2198 std::clog
<< "Finished: " << DestFile
<<std::endl
;
2199 if(TransactionManager
!= NULL
&&
2200 TransactionManager
->TransactionHasError() == false)
2201 TransactionManager
->CommitTransaction();
2204 pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire
*Owner
, /*{{{*/
2205 string
const &URI
, string
const &URIDesc
, string
const &ShortDesc
,
2206 string
const &MetaIndexURI
, string
const &MetaIndexURIDesc
, string
const &MetaIndexShortDesc
,
2207 string
const &MetaSigURI
, string
const &MetaSigURIDesc
, string
const &MetaSigShortDesc
,
2208 const vector
<IndexTarget
*>* IndexTargets
,
2209 indexRecords
* MetaIndexParser
) :
2210 pkgAcqMetaIndex(Owner
, NULL
, URI
, URIDesc
, ShortDesc
, MetaSigURI
, MetaSigURIDesc
,MetaSigShortDesc
, IndexTargets
, MetaIndexParser
),
2211 MetaIndexURI(MetaIndexURI
), MetaIndexURIDesc(MetaIndexURIDesc
), MetaIndexShortDesc(MetaIndexShortDesc
),
2212 MetaSigURI(MetaSigURI
), MetaSigURIDesc(MetaSigURIDesc
), MetaSigShortDesc(MetaSigShortDesc
)
2214 // index targets + (worst case:) Release/Release.gpg
2215 ExpectedAdditionalItems
= IndexTargets
->size() + 2;
2219 pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
2223 // pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
2224 // ---------------------------------------------------------------------
2225 string
pkgAcqMetaClearSig::Custom600Headers() const
2227 string Header
= GetCustom600Headers(RealURI
);
2228 Header
+= "\nFail-Ignore: true";
2232 // pkgAcqMetaClearSig::Done - We got a file /*{{{*/
2233 // ---------------------------------------------------------------------
2234 void pkgAcqMetaClearSig::Done(std::string Message
,unsigned long long Size
,
2235 HashStringList
const &Hashes
,
2236 pkgAcquire::MethodConfig
*Cnf
)
2238 Item::Done(Message
, Size
, Hashes
, Cnf
);
2240 // if we expect a ClearTextSignature (InRelase), ensure that
2241 // this is what we get and if not fail to queue a
2242 // Release/Release.gpg, see #346386
2243 if (FileExists(DestFile
) && !StartsWithGPGClearTextSignature(DestFile
))
2245 pkgAcquire::Item::Failed(Message
, Cnf
);
2246 RenameOnError(NotClearsigned
);
2247 TransactionManager
->AbortTransaction();
2251 if(AuthPass
== false)
2253 if(CheckDownloadDone(Message
, RealURI
) == true)
2254 QueueForSignatureVerify(DestFile
, DestFile
);
2259 if(CheckAuthDone(Message
, RealURI
) == true)
2261 string FinalFile
= _config
->FindDir("Dir::State::lists");
2262 FinalFile
+= URItoFileName(RealURI
);
2264 // queue for copy in place
2265 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2270 void pkgAcqMetaClearSig::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
) /*{{{*/
2272 Item::Failed(Message
, Cnf
);
2274 // we failed, we will not get additional items from this method
2275 ExpectedAdditionalItems
= 0;
2277 if (AuthPass
== false)
2279 // Queue the 'old' InRelease file for removal if we try Release.gpg
2280 // as otherwise the file will stay around and gives a false-auth
2281 // impression (CVE-2012-0214)
2282 string FinalFile
= _config
->FindDir("Dir::State::lists");
2283 FinalFile
.append(URItoFileName(RealURI
));
2284 TransactionManager
->TransactionStageRemoval(this, FinalFile
);
2287 new pkgAcqMetaIndex(Owner
, TransactionManager
,
2288 MetaIndexURI
, MetaIndexURIDesc
, MetaIndexShortDesc
,
2289 MetaSigURI
, MetaSigURIDesc
, MetaSigShortDesc
,
2290 IndexTargets
, MetaIndexParser
);
2294 if(CheckStopAuthentication(RealURI
, Message
))
2297 _error
->Warning(_("The data from '%s' is not signed. Packages "
2298 "from that repository can not be authenticated."),
2301 // No Release file was present, or verification failed, so fall
2302 // back to queueing Packages files without verification
2303 // only allow going further if the users explicitely wants it
2304 if(AllowInsecureRepositories(MetaIndexParser
, TransactionManager
, this) == true)
2308 /* Always move the meta index, even if gpgv failed. This ensures
2309 * that PackageFile objects are correctly filled in */
2310 if (FileExists(DestFile
))
2312 string FinalFile
= _config
->FindDir("Dir::State::lists");
2313 FinalFile
+= URItoFileName(RealURI
);
2314 /* InRelease files become Release files, otherwise
2315 * they would be considered as trusted later on */
2316 RealURI
= RealURI
.replace(RealURI
.rfind("InRelease"), 9,
2318 FinalFile
= FinalFile
.replace(FinalFile
.rfind("InRelease"), 9,
2321 // Done, queue for rename on transaction finished
2322 TransactionManager
->TransactionStageCopy(this, DestFile
, FinalFile
);
2324 QueueIndexes(false);
2329 // AcqArchive::AcqArchive - Constructor /*{{{*/
2330 // ---------------------------------------------------------------------
2331 /* This just sets up the initial fetch environment and queues the first
2333 pkgAcqArchive::pkgAcqArchive(pkgAcquire
*Owner
,pkgSourceList
*Sources
,
2334 pkgRecords
*Recs
,pkgCache::VerIterator
const &Version
,
2335 string
&StoreFilename
) :
2336 Item(Owner
, HashStringList()), Version(Version
), Sources(Sources
), Recs(Recs
),
2337 StoreFilename(StoreFilename
), Vf(Version
.FileList()),
2340 Retries
= _config
->FindI("Acquire::Retries",0);
2342 if (Version
.Arch() == 0)
2344 _error
->Error(_("I wasn't able to locate a file for the %s package. "
2345 "This might mean you need to manually fix this package. "
2346 "(due to missing arch)"),
2347 Version
.ParentPkg().FullName().c_str());
2351 /* We need to find a filename to determine the extension. We make the
2352 assumption here that all the available sources for this version share
2353 the same extension.. */
2354 // Skip not source sources, they do not have file fields.
2355 for (; Vf
.end() == false; ++Vf
)
2357 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2362 // Does not really matter here.. we are going to fail out below
2363 if (Vf
.end() != true)
2365 // If this fails to get a file name we will bomb out below.
2366 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2367 if (_error
->PendingError() == true)
2370 // Generate the final file name as: package_version_arch.foo
2371 StoreFilename
= QuoteString(Version
.ParentPkg().Name(),"_:") + '_' +
2372 QuoteString(Version
.VerStr(),"_:") + '_' +
2373 QuoteString(Version
.Arch(),"_:.") +
2374 "." + flExtension(Parse
.FileName());
2377 // check if we have one trusted source for the package. if so, switch
2378 // to "TrustedOnly" mode - but only if not in AllowUnauthenticated mode
2379 bool const allowUnauth
= _config
->FindB("APT::Get::AllowUnauthenticated", false);
2380 bool const debugAuth
= _config
->FindB("Debug::pkgAcquire::Auth", false);
2381 bool seenUntrusted
= false;
2382 for (pkgCache::VerFileIterator i
= Version
.FileList(); i
.end() == false; ++i
)
2384 pkgIndexFile
*Index
;
2385 if (Sources
->FindIndex(i
.File(),Index
) == false)
2388 if (debugAuth
== true)
2389 std::cerr
<< "Checking index: " << Index
->Describe()
2390 << "(Trusted=" << Index
->IsTrusted() << ")" << std::endl
;
2392 if (Index
->IsTrusted() == true)
2395 if (allowUnauth
== false)
2399 seenUntrusted
= true;
2402 // "allow-unauthenticated" restores apts old fetching behaviour
2403 // that means that e.g. unauthenticated file:// uris are higher
2404 // priority than authenticated http:// uris
2405 if (allowUnauth
== true && seenUntrusted
== true)
2409 if (QueueNext() == false && _error
->PendingError() == false)
2410 _error
->Error(_("Can't find a source to download version '%s' of '%s'"),
2411 Version
.VerStr(), Version
.ParentPkg().FullName(false).c_str());
2414 // AcqArchive::QueueNext - Queue the next file source /*{{{*/
2415 // ---------------------------------------------------------------------
2416 /* This queues the next available file version for download. It checks if
2417 the archive is already available in the cache and stashs the MD5 for
2419 bool pkgAcqArchive::QueueNext()
2421 for (; Vf
.end() == false; ++Vf
)
2423 // Ignore not source sources
2424 if ((Vf
.File()->Flags
& pkgCache::Flag::NotSource
) != 0)
2427 // Try to cross match against the source list
2428 pkgIndexFile
*Index
;
2429 if (Sources
->FindIndex(Vf
.File(),Index
) == false)
2432 // only try to get a trusted package from another source if that source
2434 if(Trusted
&& !Index
->IsTrusted())
2437 // Grab the text package record
2438 pkgRecords::Parser
&Parse
= Recs
->Lookup(Vf
);
2439 if (_error
->PendingError() == true)
2442 string PkgFile
= Parse
.FileName();
2443 ExpectedHashes
= Parse
.Hashes();
2445 if (PkgFile
.empty() == true)
2446 return _error
->Error(_("The package index files are corrupted. No Filename: "
2447 "field for package %s."),
2448 Version
.ParentPkg().Name());
2450 Desc
.URI
= Index
->ArchiveURI(PkgFile
);
2451 Desc
.Description
= Index
->ArchiveInfo(Version
);
2453 Desc
.ShortDesc
= Version
.ParentPkg().FullName(true);
2455 // See if we already have the file. (Legacy filenames)
2456 FileSize
= Version
->Size
;
2457 string FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(PkgFile
);
2459 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2461 // Make sure the size matches
2462 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2467 StoreFilename
= DestFile
= FinalFile
;
2471 /* Hmm, we have a file and its size does not match, this means it is
2472 an old style mismatched arch */
2473 unlink(FinalFile
.c_str());
2476 // Check it again using the new style output filenames
2477 FinalFile
= _config
->FindDir("Dir::Cache::Archives") + flNotDir(StoreFilename
);
2478 if (stat(FinalFile
.c_str(),&Buf
) == 0)
2480 // Make sure the size matches
2481 if ((unsigned long long)Buf
.st_size
== Version
->Size
)
2486 StoreFilename
= DestFile
= FinalFile
;
2490 /* Hmm, we have a file and its size does not match, this shouldn't
2492 unlink(FinalFile
.c_str());
2495 DestFile
= _config
->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename
);
2497 // Check the destination file
2498 if (stat(DestFile
.c_str(),&Buf
) == 0)
2500 // Hmm, the partial file is too big, erase it
2501 if ((unsigned long long)Buf
.st_size
> Version
->Size
)
2502 unlink(DestFile
.c_str());
2505 PartialSize
= Buf
.st_size
;
2506 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
2507 ChangeOwnerAndPermissionOfFile("pkgAcqArchive::QueueNext",DestFile
.c_str(), SandboxUser
.c_str(), "root", 0600);
2511 // Disables download of archives - useful if no real installation follows,
2512 // e.g. if we are just interested in proposed installation order
2513 if (_config
->FindB("Debug::pkgAcqArchive::NoQueue", false) == true)
2518 StoreFilename
= DestFile
= FinalFile
;
2532 // AcqArchive::Done - Finished fetching /*{{{*/
2533 // ---------------------------------------------------------------------
2535 void pkgAcqArchive::Done(string Message
,unsigned long long Size
, HashStringList
const &CalcHashes
,
2536 pkgAcquire::MethodConfig
*Cfg
)
2538 Item::Done(Message
, Size
, CalcHashes
, Cfg
);
2541 if (Size
!= Version
->Size
)
2543 RenameOnError(SizeMismatch
);
2547 // FIXME: could this empty() check impose *any* sort of security issue?
2548 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2550 RenameOnError(HashSumMismatch
);
2551 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2555 // Grab the output filename
2556 string FileName
= LookupTag(Message
,"Filename");
2557 if (FileName
.empty() == true)
2560 ErrorText
= "Method gave a blank filename";
2564 // Reference filename
2565 if (FileName
!= DestFile
)
2567 StoreFilename
= DestFile
= FileName
;
2573 // Done, move it into position
2574 string FinalFile
= _config
->FindDir("Dir::Cache::Archives");
2575 FinalFile
+= flNotDir(StoreFilename
);
2576 Rename(DestFile
,FinalFile
);
2577 StoreFilename
= DestFile
= FinalFile
;
2581 // AcqArchive::Failed - Failure handler /*{{{*/
2582 // ---------------------------------------------------------------------
2583 /* Here we try other sources */
2584 void pkgAcqArchive::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2586 Item::Failed(Message
,Cnf
);
2588 /* We don't really want to retry on failed media swaps, this prevents
2589 that. An interesting observation is that permanent failures are not
2591 if (Cnf
->Removable
== true &&
2592 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2594 // Vf = Version.FileList();
2595 while (Vf
.end() == false) ++Vf
;
2596 StoreFilename
= string();
2601 if (QueueNext() == false)
2603 // This is the retry counter
2605 Cnf
->LocalOnly
== false &&
2606 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2609 Vf
= Version
.FileList();
2610 if (QueueNext() == true)
2614 StoreFilename
= string();
2619 // AcqArchive::IsTrusted - Determine whether this archive comes from a trusted source /*{{{*/
2620 // ---------------------------------------------------------------------
2621 APT_PURE
bool pkgAcqArchive::IsTrusted() const
2626 // AcqArchive::Finished - Fetching has finished, tidy up /*{{{*/
2627 // ---------------------------------------------------------------------
2629 void pkgAcqArchive::Finished()
2631 if (Status
== pkgAcquire::Item::StatDone
&&
2634 StoreFilename
= string();
2637 // AcqFile::pkgAcqFile - Constructor /*{{{*/
2638 // ---------------------------------------------------------------------
2639 /* The file is added to the queue */
2640 pkgAcqFile::pkgAcqFile(pkgAcquire
*Owner
,string URI
, HashStringList
const &Hashes
,
2641 unsigned long long Size
,string Dsc
,string ShortDesc
,
2642 const string
&DestDir
, const string
&DestFilename
,
2644 Item(Owner
, Hashes
), IsIndexFile(IsIndexFile
)
2646 Retries
= _config
->FindI("Acquire::Retries",0);
2648 if(!DestFilename
.empty())
2649 DestFile
= DestFilename
;
2650 else if(!DestDir
.empty())
2651 DestFile
= DestDir
+ "/" + flNotDir(URI
);
2653 DestFile
= flNotDir(URI
);
2657 Desc
.Description
= Dsc
;
2660 // Set the short description to the archive component
2661 Desc
.ShortDesc
= ShortDesc
;
2663 // Get the transfer sizes
2666 if (stat(DestFile
.c_str(),&Buf
) == 0)
2668 // Hmm, the partial file is too big, erase it
2669 if ((Size
> 0) && (unsigned long long)Buf
.st_size
> Size
)
2670 unlink(DestFile
.c_str());
2673 PartialSize
= Buf
.st_size
;
2674 std::string SandboxUser
= _config
->Find("APT::Sandbox::User");
2675 ChangeOwnerAndPermissionOfFile("pkgAcqFile", DestFile
.c_str(), SandboxUser
.c_str(), "root", 0600);
2682 // AcqFile::Done - Item downloaded OK /*{{{*/
2683 // ---------------------------------------------------------------------
2685 void pkgAcqFile::Done(string Message
,unsigned long long Size
,HashStringList
const &CalcHashes
,
2686 pkgAcquire::MethodConfig
*Cnf
)
2688 Item::Done(Message
,Size
,CalcHashes
,Cnf
);
2691 if(ExpectedHashes
.usable() && ExpectedHashes
!= CalcHashes
)
2693 RenameOnError(HashSumMismatch
);
2694 printHashSumComparision(DestFile
, ExpectedHashes
, CalcHashes
);
2698 string FileName
= LookupTag(Message
,"Filename");
2699 if (FileName
.empty() == true)
2702 ErrorText
= "Method gave a blank filename";
2708 // The files timestamp matches
2709 if (StringToBool(LookupTag(Message
,"IMS-Hit"),false) == true)
2712 // We have to copy it into place
2713 if (FileName
!= DestFile
)
2716 if (_config
->FindB("Acquire::Source-Symlinks",true) == false ||
2717 Cnf
->Removable
== true)
2719 Desc
.URI
= "copy:" + FileName
;
2724 // Erase the file if it is a symlink so we can overwrite it
2726 if (lstat(DestFile
.c_str(),&St
) == 0)
2728 if (S_ISLNK(St
.st_mode
) != 0)
2729 unlink(DestFile
.c_str());
2733 if (symlink(FileName
.c_str(),DestFile
.c_str()) != 0)
2735 _error
->PushToStack();
2736 _error
->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile
.c_str());
2737 std::stringstream msg
;
2738 _error
->DumpErrors(msg
);
2739 _error
->RevertToStack();
2740 ErrorText
= msg
.str();
2747 // AcqFile::Failed - Failure handler /*{{{*/
2748 // ---------------------------------------------------------------------
2749 /* Here we try other sources */
2750 void pkgAcqFile::Failed(string Message
,pkgAcquire::MethodConfig
*Cnf
)
2752 Item::Failed(Message
,Cnf
);
2754 // This is the retry counter
2756 Cnf
->LocalOnly
== false &&
2757 StringToBool(LookupTag(Message
,"Transient-Failure"),false) == true)
2767 // AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
2768 // ---------------------------------------------------------------------
2769 /* The only header we use is the last-modified header. */
2770 string
pkgAcqFile::Custom600Headers() const
2773 return "\nIndex-File: true";