+ for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
+ CompressionExtensions.append(*t).append(" ");
+ }
+ if (CompressionExtensions.empty() == false)
+ CompressionExtensions.erase(CompressionExtensions.end()-1);
+}
+ /*}}}*/
+// AcqIndex::Init - defered Constructor /*{{{*/
+void pkgAcqIndex::Init(string const &URI, string const &URIDesc,
+ string const &ShortDesc)
+{
+ Stage = STAGE_DOWNLOAD;
+
+ DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+ DestFile += URItoFileName(URI);
+
+ CurrentCompressionExtension = CompressionExtensions.substr(0, CompressionExtensions.find(' '));
+ if (CurrentCompressionExtension == "uncompressed")
+ {
+ Desc.URI = URI;
+ if(Target)
+ MetaKey = string(Target->MetaKey);
+ }
+ else
+ {
+ Desc.URI = URI + '.' + CurrentCompressionExtension;
+ DestFile = DestFile + '.' + CurrentCompressionExtension;
+ if(Target)
+ MetaKey = string(Target->MetaKey) + '.' + CurrentCompressionExtension;
+ }
+
+ // load the filesize
+ if(MetaIndexParser)
+ {
+ indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
+ if(Record)
+ FileSize = Record->Size;
+
+ InitByHashIfNeeded(MetaKey);
+ }
+
+ Desc.Description = URIDesc;
+ Desc.Owner = this;
+ Desc.ShortDesc = ShortDesc;
+
+ QueueURI(Desc);
+}
+ /*}}}*/
+// AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
+void pkgAcqIndex::InitByHashIfNeeded(const std::string MetaKey)
+{
+ // TODO:
+ // - (maybe?) add support for by-hash into the sources.list as flag
+ // - make apt-ftparchive generate the hashes (and expire?)
+ std::string HostKnob = "APT::Acquire::" + ::URI(Desc.URI).Host + "::By-Hash";
+ if(_config->FindB("APT::Acquire::By-Hash", false) == true ||
+ _config->FindB(HostKnob, false) == true ||
+ MetaIndexParser->GetSupportsAcquireByHash())
+ {
+ indexRecords::checkSum *Record = MetaIndexParser->Lookup(MetaKey);
+ if(Record)
+ {
+ // FIXME: should we really use the best hash here? or a fixed one?
+ const HashString *TargetHash = Record->Hashes.find("");
+ std::string ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
+ size_t trailing_slash = Desc.URI.find_last_of("/");
+ Desc.URI = Desc.URI.replace(
+ trailing_slash,
+ Desc.URI.substr(trailing_slash+1).size()+1,
+ ByHash);
+ } else {
+ _error->Warning(
+ "Fetching ByHash requested but can not find record for %s",
+ MetaKey.c_str());
+ }
+ }
+}
+ /*}}}*/
+// AcqIndex::Custom600Headers - Insert custom request headers /*{{{*/
+// ---------------------------------------------------------------------
+/* The only header we use is the last-modified header. */
+string pkgAcqIndex::Custom600Headers() const
+{
+ string Final = GetFinalFilename();
+
+ string msg = "\nIndex-File: true";
+ struct stat Buf;
+ if (stat(Final.c_str(),&Buf) == 0)
+ msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
+
+ return msg;
+}
+ /*}}}*/
+// pkgAcqIndex::Failed - getting the indexfile failed /*{{{*/
+void pkgAcqIndex::Failed(string Message,pkgAcquire::MethodConfig *Cnf)
+{
+ size_t const nextExt = CompressionExtensions.find(' ');
+ if (nextExt != std::string::npos)
+ {
+ CompressionExtensions = CompressionExtensions.substr(nextExt+1);
+ Init(RealURI, Desc.Description, Desc.ShortDesc);
+ return;
+ }
+
+ // on decompression failure, remove bad versions in partial/
+ if (Stage == STAGE_DECOMPRESS_AND_VERIFY)
+ {
+ unlink(EraseFileName.c_str());
+ }
+
+ Item::Failed(Message,Cnf);
+
+ /// cancel the entire transaction
+ TransactionManager->AbortTransaction();
+}
+ /*}}}*/
+// pkgAcqIndex::GetFinalFilename - Return the full final file path /*{{{*/
+std::string pkgAcqIndex::GetFinalFilename() const
+{
+ std::string FinalFile = _config->FindDir("Dir::State::lists");
+ FinalFile += URItoFileName(RealURI);
+ if (_config->FindB("Acquire::GzipIndexes",false) == true)
+ FinalFile += '.' + CurrentCompressionExtension;
+ return FinalFile;
+}
+ /*}}}*/
+// AcqIndex::ReverifyAfterIMS - Reverify index after an ims-hit /*{{{*/
+void pkgAcqIndex::ReverifyAfterIMS()
+{
+ // update destfile to *not* include the compression extension when doing
+ // a reverify (as its uncompressed on disk already)
+ DestFile = _config->FindDir("Dir::State::lists") + "partial/";
+ DestFile += URItoFileName(RealURI);
+
+ // adjust DestFile if its compressed on disk
+ if (_config->FindB("Acquire::GzipIndexes",false) == true)
+ DestFile += '.' + CurrentCompressionExtension;
+
+ // copy FinalFile into partial/ so that we check the hash again
+ string FinalFile = GetFinalFilename();
+ Stage = STAGE_DECOMPRESS_AND_VERIFY;
+ Desc.URI = "copy:" + FinalFile;
+ QueueURI(Desc);
+}
+ /*}}}*/
+// AcqIndex::ValidateFile - Validate the content of the downloaded file /*{{{*/
+bool pkgAcqIndex::ValidateFile(const std::string &FileName)
+{
+ // FIXME: this can go away once we only ever download stuff that
+ // has a valid hash and we never do GET based probing
+ // FIXME2: this also leaks debian-isms into the code and should go therefore
+
+ /* Always validate the index file for correctness (all indexes must
+ * have a Package field) (LP: #346386) (Closes: #627642)
+ */
+ FileFd fd(FileName, FileFd::ReadOnly, FileFd::Extension);
+ // Only test for correctness if the content of the file is not empty
+ // (empty is ok)
+ if (fd.Size() > 0)
+ {
+ pkgTagSection sec;
+ pkgTagFile tag(&fd);
+
+ // all our current indexes have a field 'Package' in each section
+ if (_error->PendingError() == true ||
+ tag.Step(sec) == false ||
+ sec.Exists("Package") == false)
+ return false;
+ }
+ return true;
+}
+ /*}}}*/
+// AcqIndex::Done - Finished a fetch /*{{{*/
+// ---------------------------------------------------------------------
+/* This goes through a number of states.. On the initial fetch the
+ method could possibly return an alternate filename which points
+ to the uncompressed version of the file. If this is so the file
+ is copied into the partial directory. In all other cases the file
+ is decompressed with a compressed uri. */
+void pkgAcqIndex::Done(string Message,
+ unsigned long long Size,
+ HashStringList const &Hashes,
+ pkgAcquire::MethodConfig *Cfg)
+{
+ Item::Done(Message,Size,Hashes,Cfg);
+
+ switch(Stage)
+ {
+ case STAGE_DOWNLOAD:
+ StageDownloadDone(Message, Hashes, Cfg);
+ break;
+ case STAGE_DECOMPRESS_AND_VERIFY:
+ StageDecompressDone(Message, Hashes, Cfg);
+ break;
+ }
+}
+ /*}}}*/
+// AcqIndex::StageDownloadDone - Queue for decompress and verify /*{{{*/
+void pkgAcqIndex::StageDownloadDone(string Message,
+ HashStringList const &Hashes,
+ pkgAcquire::MethodConfig *Cfg)
+{
+ // First check if the calculcated Hash of the (compressed) downloaded
+ // file matches the hash we have in the MetaIndexRecords for this file
+ if(VerifyHashByMetaKey(Hashes) == false)
+ {
+ RenameOnError(HashSumMismatch);
+ Failed(Message, Cfg);
+ return;
+ }
+
+ Complete = true;
+
+ // Handle the unzipd case
+ string FileName = LookupTag(Message,"Alt-Filename");
+ if (FileName.empty() == false)
+ {
+ Stage = STAGE_DECOMPRESS_AND_VERIFY;