#include <apt-pkg/error.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/fileutl.h>
-#include <apt-pkg/sha1.h>
#include <apt-pkg/tagfile.h>
-#include <apt-pkg/indexrecords.h>
+#include <apt-pkg/metaindex.h>
#include <apt-pkg/acquire.h>
#include <apt-pkg/hashes.h>
#include <apt-pkg/indexfile.h>
#include <apt-pkg/pkgcache.h>
#include <apt-pkg/cacheiterators.h>
#include <apt-pkg/pkgrecords.h>
+#include <apt-pkg/gpgv.h>
+#include <algorithm>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <string>
-#include <sstream>
#include <stdio.h>
#include <ctime>
+#include <sstream>
#include <apti18n.h>
/*}}}*/
return _config->FindDir("Dir::State::lists") + URItoFileName(uri);
}
/*}}}*/
-static std::string GetCompressedFileName(std::string const &URI, std::string const &Name, std::string const &Ext) /*{{{*/
+static std::string GetKeepCompressedFileName(std::string file, IndexTarget const &Target)/*{{{*/
+{
+ if (Target.KeepCompressed == false)
+ return file;
+
+ std::string const CompressionTypes = Target.Option(IndexTarget::COMPRESSIONTYPES);
+ if (CompressionTypes.empty() == false)
+ {
+ std::string const ext = CompressionTypes.substr(0, CompressionTypes.find(' '));
+ if (ext != "uncompressed")
+ file.append(".").append(ext);
+ }
+ return file;
+}
+ /*}}}*/
+static std::string GetCompressedFileName(IndexTarget const &Target, std::string const &Name, std::string const &Ext) /*{{{*/
{
if (Ext.empty() || Ext == "uncompressed")
return Name;
// do not reverify cdrom sources as apt-cdrom may rewrite the Packages
// file when its doing the indexcopy
- if (URI.substr(0,6) == "cdrom:")
+ if (Target.URI.substr(0,6) == "cdrom:")
return Name;
// adjust DestFile if its compressed on disk
- if (_config->FindB("Acquire::GzipIndexes",false) == true)
+ if (Target.KeepCompressed == true)
return Name + '.' + Ext;
return Name;
}
return Final + ".ed";
}
/*}}}*/
+static bool BootstrapPDiffWith(std::string const &PartialFile, std::string const &FinalFile, IndexTarget const &Target)/*{{{*/
+{
+ // patching needs to be bootstrapped with the 'old' version
+ std::vector<std::string> types = VectorizeString(Target.Option(IndexTarget::COMPRESSIONTYPES), ' ');
+ auto typeItr = types.cbegin();
+ for (; typeItr != types.cend(); ++typeItr)
+ {
+ std::string Final = FinalFile;
+ if (*typeItr != "uncompressed")
+ Final.append(".").append(*typeItr);
+ if (RealFileExists(Final) == false)
+ continue;
+ std::string Partial = PartialFile;
+ if (*typeItr != "uncompressed")
+ Partial.append(".").append(*typeItr);
+ if (FileExists(Partial.c_str()) == true)
+ return true;
+ if (symlink(Final.c_str(), Partial.c_str()) != 0)
+ return false;
+ break;
+ }
+ return typeItr != types.cend();
+}
+ /*}}}*/
-static bool AllowInsecureRepositories(indexRecords const * const MetaIndexParser, pkgAcqMetaBase * const TransactionManager, pkgAcquire::Item * const I) /*{{{*/
+static bool MessageInsecureRepository(bool const isError, std::string const &msg)/*{{{*/
{
- if(MetaIndexParser->IsAlwaysTrusted() || _config->FindB("Acquire::AllowInsecureRepositories") == true)
+ if (isError)
+ {
+ _error->Error("%s", msg.c_str());
+ _error->Notice("%s", _("Updating from such a repository can't be done securely, and is therefore disabled by default."));
+ }
+ else
+ {
+ _error->Warning("%s", msg.c_str());
+ _error->Notice("%s", _("Data from such a repository can't be authenticated and is therefore potentially dangerous to use."));
+ }
+ _error->Notice("%s", _("See apt-secure(8) manpage for repository creation and user configuration details."));
+ return false;
+}
+static bool MessageInsecureRepository(bool const isError, char const * const msg, std::string const &repo)
+{
+ std::string m;
+ strprintf(m, msg, repo.c_str());
+ return MessageInsecureRepository(isError, m);
+}
+ /*}}}*/
+static bool AllowInsecureRepositories(char const * const msg, std::string const &repo,/*{{{*/
+ metaIndex const * const MetaIndexParser, pkgAcqMetaClearSig * const TransactionManager, pkgAcquire::Item * const I)
+{
+ if(MetaIndexParser->GetTrusted() == metaIndex::TRI_YES)
return true;
- _error->Error(_("Use --allow-insecure-repositories to force the update"));
+ if (_config->FindB("Acquire::AllowInsecureRepositories") == true)
+ {
+ MessageInsecureRepository(false, msg, repo);
+ return true;
+ }
+
+ MessageInsecureRepository(true, msg, repo);
TransactionManager->AbortTransaction();
I->Status = pkgAcquire::Item::StatError;
return false;
}
/*}}}*/
-static HashStringList GetExpectedHashesFromFor(indexRecords * const Parser, std::string const MetaKey)/*{{{*/
+static HashStringList GetExpectedHashesFromFor(metaIndex * const Parser, std::string const &MetaKey)/*{{{*/
{
if (Parser == NULL)
return HashStringList();
- indexRecords::checkSum * const R = Parser->Lookup(MetaKey);
+ metaIndex::checkSum * const R = Parser->Lookup(MetaKey);
if (R == NULL)
return HashStringList();
return R->Hashes;
we can at least trust them for integrity of the download itself.
Only repositories without a Release file can (obviously) not have
hashes – and they are very uncommon and strongly discouraged */
- return TransactionManager->MetaIndexParser != NULL;
+ return TransactionManager->MetaIndexParser != NULL &&
+ TransactionManager->MetaIndexParser->GetLoadedSuccessfully() == metaIndex::TRI_YES;
}
HashStringList pkgAcqTransactionItem::GetExpectedHashes() const
{
if (State == StateFetchDiff)
return patch.download_hashes;
else if (State == StateApplyDiff)
- return GetExpectedHashesFor(Target->MetaKey);
+ return GetExpectedHashesFor(Target.MetaKey);
return HashStringList();
}
}
std::string pkgAcqIndex::GetFinalFilename() const
{
- std::string const FinalFile = GetFinalFileNameFromURI(Target->URI);
- return GetCompressedFileName(Target->URI, FinalFile, CurrentCompressionExtension);
+ std::string const FinalFile = GetFinalFileNameFromURI(Target.URI);
+ return GetCompressedFileName(Target, FinalFile, CurrentCompressionExtension);
}
std::string pkgAcqMetaSig::GetFinalFilename() const
{
- return GetFinalFileNameFromURI(Target->URI);
+ return GetFinalFileNameFromURI(Target.URI);
}
std::string pkgAcqBaseIndex::GetFinalFilename() const
{
- return GetFinalFileNameFromURI(Target->URI);
+ return GetFinalFileNameFromURI(Target.URI);
}
std::string pkgAcqMetaBase::GetFinalFilename() const
{
- return GetFinalFileNameFromURI(DataTarget.URI);
+ return GetFinalFileNameFromURI(Target.URI);
}
std::string pkgAcqArchive::GetFinalFilename() const
{
// pkgAcqTransactionItem::GetMetaKey and specialisations for child classes /*{{{*/
std::string pkgAcqTransactionItem::GetMetaKey() const
{
- return Target->MetaKey;
+ return Target.MetaKey;
}
std::string pkgAcqIndex::GetMetaKey() const
{
if (Stage == STAGE_DECOMPRESS_AND_VERIFY || CurrentCompressionExtension == "uncompressed")
- return Target->MetaKey;
- return Target->MetaKey + "." + CurrentCompressionExtension;
+ return Target.MetaKey;
+ return Target.MetaKey + "." + CurrentCompressionExtension;
}
std::string pkgAcqDiffIndex::GetMetaKey() const
{
- return Target->MetaKey + ".diff/Index";
+ return Target.MetaKey + ".diff/Index";
}
/*}}}*/
//pkgAcqTransactionItem::TransactionState and specialisations for child classes /*{{{*/
} else {
if(Debug == true)
std::clog << "rm " << DestFile << " # " << DescURI() << std::endl;
- unlink(DestFile.c_str());
+ RemoveFile("TransactionCommit", DestFile);
}
break;
}
// keep the compressed file, but drop the decompressed
EraseFileName.clear();
if (PartialFile.empty() == false && flExtension(PartialFile) == "decomp")
- unlink(PartialFile.c_str());
+ RemoveFile("TransactionAbort", PartialFile);
}
break;
case TransactionCommit:
if (EraseFileName.empty() == false)
- unlink(EraseFileName.c_str());
+ RemoveFile("TransactionCommit", EraseFileName);
break;
}
return true;
case TransactionCommit:
break;
case TransactionAbort:
- std::string const Partial = GetPartialFileNameFromURI(Target->URI);
- unlink(Partial.c_str());
+ std::string const Partial = GetPartialFileNameFromURI(Target.URI);
+ RemoveFile("TransactionAbort", Partial);
break;
}
}
/*}}}*/
-// IndexTarget - Constructor /*{{{*/
-IndexTarget::IndexTarget(std::string const &MetaKey, std::string const &ShortDesc,
- std::string const &LongDesc, std::string const &URI, bool const IsOptional,
- std::map<std::string, std::string> const &Options) :
- URI(URI), Description(LongDesc), ShortDesc(ShortDesc), MetaKey(MetaKey), IsOptional(IsOptional), Options(Options)
-{
-}
- /*}}}*/
-
class APT_HIDDEN NoActionItem : public pkgAcquire::Item /*{{{*/
/* The sole purpose of this class is having an item which does nothing to
reach its done state to prevent cleanup deleting the mentioned file.
Handy in cases in which we know we have the file already, like IMS-Hits. */
{
- IndexTarget const * const Target;
+ IndexTarget const Target;
public:
- virtual std::string DescURI() const {return Target->URI;};
- virtual HashStringList GetExpectedHashes() const {return HashStringList();};
+ virtual std::string DescURI() const APT_OVERRIDE {return Target.URI;};
+ virtual HashStringList GetExpectedHashes() const APT_OVERRIDE {return HashStringList();};
- NoActionItem(pkgAcquire * const Owner, IndexTarget const * const Target) :
+ NoActionItem(pkgAcquire * const Owner, IndexTarget const &Target) :
pkgAcquire::Item(Owner), Target(Target)
{
Status = StatDone;
- DestFile = GetFinalFileNameFromURI(Target->URI);
+ DestFile = GetFinalFileNameFromURI(Target.URI);
+ }
+ NoActionItem(pkgAcquire * const Owner, IndexTarget const &Target, std::string const &FinalFile) :
+ pkgAcquire::Item(Owner), Target(Target)
+ {
+ Status = StatDone;
+ DestFile = FinalFile;
}
};
/*}}}*/
// Acquire::Item::Item - Constructor /*{{{*/
APT_IGNORE_DEPRECATED_PUSH
-pkgAcquire::Item::Item(pkgAcquire * const Owner) :
- FileSize(0), PartialSize(0), Mode(0), Complete(false), Local(false),
- QueueCounter(0), ExpectedAdditionalItems(0), Owner(Owner)
+pkgAcquire::Item::Item(pkgAcquire * const owner) :
+ FileSize(0), PartialSize(0), Mode(0), ID(0), Complete(false), Local(false),
+ QueueCounter(0), ExpectedAdditionalItems(0), Owner(owner), d(NULL)
{
Owner->Add(this);
Status = StatIdle;
return Owner;
}
/*}}}*/
+APT_CONST pkgAcquire::ItemDesc &pkgAcquire::Item::GetItemDesc() /*{{{*/
+{
+ return Desc;
+}
+ /*}}}*/
APT_CONST bool pkgAcquire::Item::IsTrusted() const /*{{{*/
{
return false;
{
if(ErrorText.empty())
ErrorText = LookupTag(Message,"Message");
- UsedMirror = LookupTag(Message,"UsedMirror");
if (QueueCounter <= 1)
{
/* This indicates that the file is not available right now but might
FileSize = Size;
}
/*}}}*/
+// Acquire::Item::VerifyDone - check if Item was downloaded OK /*{{{*/
+/* Note that hash-verification is 'hardcoded' in acquire-worker and has
+ * already passed if this method is called. */
+bool pkgAcquire::Item::VerifyDone(std::string const &Message,
+ pkgAcquire::MethodConfig const * const /*Cnf*/)
+{
+ std::string const FileName = LookupTag(Message,"Filename");
+ if (FileName.empty() == true)
+ {
+ Status = StatError;
+ ErrorText = "Method gave a blank filename";
+ return false;
+ }
+
+ return true;
+}
+ /*}}}*/
// Acquire::Item::Done - Item downloaded OK /*{{{*/
-void pkgAcquire::Item::Done(string const &Message, HashStringList const &Hashes,
+void pkgAcquire::Item::Done(string const &/*Message*/, HashStringList const &Hashes,
pkgAcquire::MethodConfig const * const /*Cnf*/)
{
// We just downloaded something..
- string FileName = LookupTag(Message,"Filename");
- UsedMirror = LookupTag(Message,"UsedMirror");
- unsigned long long const downloadedSize = Hashes.FileSize();
- if (downloadedSize != 0)
+ if (FileSize == 0)
{
- if (Complete == false && !Local && FileName == DestFile)
+ unsigned long long const downloadedSize = Hashes.FileSize();
+ if (downloadedSize != 0)
{
- if (Owner->Log != 0)
- Owner->Log->Fetched(Hashes.FileSize(),atoi(LookupTag(Message,"Resume-Point","0").c_str()));
+ FileSize = downloadedSize;
}
-
- if (FileSize == 0)
- FileSize= downloadedSize;
}
Status = StatDone;
ErrorText = string();
Status = StatError;
break;
case NotClearsigned:
- errtext = _("Does not start with a cleartext signature");
- Status = StatError;
+ strprintf(errtext, _("Clearsigned file isn't valid, got '%s' (does the network require authentication?)"), "NOSPLIT");
+ Status = StatAuthError;
break;
case MaximumSizeExceeded:
// the method is expected to report a good error for this
/*}}}*/
pkgAcqTransactionItem::pkgAcqTransactionItem(pkgAcquire * const Owner, /*{{{*/
- pkgAcqMetaBase * const TransactionManager, IndexTarget const * const Target) :
- pkgAcquire::Item(Owner), Target(Target), TransactionManager(TransactionManager)
+ pkgAcqMetaClearSig * const transactionManager, IndexTarget const &target) :
+ pkgAcquire::Item(Owner), d(NULL), Target(target), TransactionManager(transactionManager)
{
if (TransactionManager != this)
TransactionManager->Add(this);
{
}
/*}}}*/
-HashStringList pkgAcqTransactionItem::GetExpectedHashesFor(std::string const MetaKey) const /*{{{*/
+HashStringList pkgAcqTransactionItem::GetExpectedHashesFor(std::string const &MetaKey) const /*{{{*/
{
return GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, MetaKey);
}
// AcqMetaBase - Constructor /*{{{*/
pkgAcqMetaBase::pkgAcqMetaBase(pkgAcquire * const Owner,
- pkgAcqMetaBase * const TransactionManager,
- std::vector<IndexTarget*> const * const IndexTargets,
- IndexTarget const &DataTarget,
- indexRecords * const MetaIndexParser)
-: pkgAcqTransactionItem(Owner, TransactionManager, NULL), DataTarget(DataTarget),
- MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL), IndexTargets(IndexTargets),
+ pkgAcqMetaClearSig * const TransactionManager,
+ std::vector<IndexTarget> const &IndexTargets,
+ IndexTarget const &DataTarget)
+: pkgAcqTransactionItem(Owner, TransactionManager, DataTarget), d(NULL),
+ IndexTargets(IndexTargets),
AuthPass(false), IMSHit(false)
{
}
_error->Warning(_("An error occurred during the signature "
"verification. The repository is not updated "
"and the previous index files will be used. "
- "GPG error: %s: %s\n"),
+ "GPG error: %s: %s"),
Desc.Description.c_str(),
LookupTag(Message,"Message").c_str());
RunScripts("APT::Update::Auth-Failure");
_error->Error(_("GPG error: %s: %s"),
Desc.Description.c_str(),
LookupTag(Message,"Message").c_str());
- I->Status = StatError;
+ I->Status = StatAuthError;
return true;
} else {
_error->Warning(_("GPG error: %s: %s"),
Header += MaximumSize;
string const FinalFile = GetFinalFilename();
-
struct stat Buf;
if (stat(FinalFile.c_str(),&Buf) == 0)
Header += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
// We have just finished downloading a Release file (it is not
// verified yet)
- string const FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- I->Status = StatError;
- I->ErrorText = "Method gave a blank filename";
- return false;
- }
-
- if (FileName != I->DestFile)
+ std::string const FileName = LookupTag(Message,"Filename");
+ if (FileName != I->DestFile && RealFileExists(I->DestFile) == false)
{
I->Local = true;
I->Desc.URI = "copy:" + FileName;
if (RealFileExists(FinalFile) && Hashes.VerifyFile(FinalFile) == true)
{
IMSHit = true;
- unlink(I->DestFile.c_str());
+ RemoveFile("CheckDownloadDone", I->DestFile);
}
}
}
if (RealFileExists(FinalInRelease) || RealFileExists(FinalRelease))
{
- TransactionManager->LastMetaIndexParser = new indexRecords;
- _error->PushToStack();
- if (RealFileExists(FinalInRelease))
- TransactionManager->LastMetaIndexParser->Load(FinalInRelease);
- else
- TransactionManager->LastMetaIndexParser->Load(FinalRelease);
- // its unlikely to happen, but if what we have is bad ignore it
- if (_error->PendingError())
+ TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
+ if (TransactionManager->LastMetaIndexParser != NULL)
{
- delete TransactionManager->LastMetaIndexParser;
- TransactionManager->LastMetaIndexParser = NULL;
+ _error->PushToStack();
+ if (RealFileExists(FinalInRelease))
+ TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
+ else
+ TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
+ // its unlikely to happen, but if what we have is bad ignore it
+ if (_error->PendingError())
+ {
+ delete TransactionManager->LastMetaIndexParser;
+ TransactionManager->LastMetaIndexParser = NULL;
+ }
+ _error->RevertToStack();
}
- _error->RevertToStack();
}
}
- if (TransactionManager->MetaIndexParser->Load(DestFile) == false)
+ if (TransactionManager->MetaIndexParser->Load(DestFile, &ErrorText) == false)
{
Status = StatAuthError;
- ErrorText = TransactionManager->MetaIndexParser->ErrorText;
return false;
}
// at this point the real Items are loaded in the fetcher
ExpectedAdditionalItems = 0;
- vector <IndexTarget*>::const_iterator Target;
- for (Target = IndexTargets->begin();
- Target != IndexTargets->end();
+ bool metaBaseSupportsByHash = false;
+ if (TransactionManager != NULL && TransactionManager->MetaIndexParser != NULL)
+ metaBaseSupportsByHash = TransactionManager->MetaIndexParser->GetSupportsAcquireByHash();
+
+ for (std::vector <IndexTarget>::iterator Target = IndexTargets.begin();
+ Target != IndexTargets.end();
++Target)
{
- bool trypdiff = _config->FindB("Acquire::PDiffs", true);
+ // all is an implementation detail. Users shouldn't use this as arch
+ // We need this support trickery here as e.g. Debian has binary-all files already,
+ // but arch:all packages are still in the arch:any files, so we would waste precious
+ // download time, bandwidth and diskspace for nothing, BUT Debian doesn't feature all
+ // in the set of supported architectures, so we can filter based on this property rather
+ // than invent an entirely new flag we would need to carry for all of eternity.
+ if (Target->Option(IndexTarget::ARCHITECTURE) == "all" &&
+ TransactionManager->MetaIndexParser->IsArchitectureSupported("all") == false)
+ continue;
+
+ bool trypdiff = Target->OptionBool(IndexTarget::PDIFFS);
if (verify == true)
{
- if (TransactionManager->MetaIndexParser->Exists((*Target)->MetaKey) == false)
+ if (TransactionManager->MetaIndexParser->Exists(Target->MetaKey) == false)
{
// optional targets that we do not have in the Release file are skipped
- if ((*Target)->IsOptional)
+ if (Target->IsOptional)
continue;
+ std::string const &arch = Target->Option(IndexTarget::ARCHITECTURE);
+ if (arch.empty() == false)
+ {
+ if (TransactionManager->MetaIndexParser->IsArchitectureSupported(arch) == false)
+ {
+ _error->Notice(_("Skipping acquire of configured file '%s' as repository '%s' doesn't support architecture '%s'"),
+ Target->MetaKey.c_str(), TransactionManager->Target.Description.c_str(), arch.c_str());
+ continue;
+ }
+ // if the architecture is officially supported but currently no packages for it available,
+ // ignore silently as this is pretty much the same as just shipping an empty file.
+ // if we don't know which architectures are supported, we do NOT ignore it to notify user about this
+ if (TransactionManager->MetaIndexParser->IsArchitectureSupported("*undefined*") == false)
+ continue;
+ }
+
Status = StatAuthError;
- strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), (*Target)->MetaKey.c_str());
+ strprintf(ErrorText, _("Unable to find expected entry '%s' in Release file (Wrong sources.list entry or malformed file)"), Target->MetaKey.c_str());
return;
}
+ else
+ {
+ auto const hashes = GetExpectedHashesFor(Target->MetaKey);
+ if (hashes.usable() == false && hashes.empty() == false)
+ {
+ _error->Warning(_("Skipping acquire of configured file '%s' as repository '%s' provides only weak security information for it"),
+ Target->MetaKey.c_str(), TransactionManager->Target.Description.c_str());
+ continue;
+ }
+ }
- if (RealFileExists(GetFinalFileNameFromURI((*Target)->URI)))
+ // autoselect the compression method
+ std::vector<std::string> types = VectorizeString(Target->Option(IndexTarget::COMPRESSIONTYPES), ' ');
+ types.erase(std::remove_if(types.begin(), types.end(), [&](std::string const &t) {
+ if (t == "uncompressed")
+ return TransactionManager->MetaIndexParser->Exists(Target->MetaKey) == false;
+ std::string const MetaKey = Target->MetaKey + "." + t;
+ return TransactionManager->MetaIndexParser->Exists(MetaKey) == false;
+ }), types.end());
+ if (types.empty() == false)
{
- if (TransactionManager->LastMetaIndexParser != NULL)
+ std::ostringstream os;
+ // add the special compressiontype byhash first if supported
+ std::string const useByHashConf = Target->Option(IndexTarget::BY_HASH);
+ bool useByHash = false;
+ if(useByHashConf == "force")
+ useByHash = true;
+ else
+ useByHash = StringToBool(useByHashConf) == true && metaBaseSupportsByHash;
+ if (useByHash == true)
+ os << "by-hash ";
+ std::copy(types.begin(), types.end()-1, std::ostream_iterator<std::string>(os, " "));
+ os << *types.rbegin();
+ Target->Options["COMPRESSIONTYPES"] = os.str();
+ }
+ else
+ Target->Options["COMPRESSIONTYPES"].clear();
+
+ std::string filename = GetFinalFileNameFromURI(Target->URI);
+ if (RealFileExists(filename) == false)
+ {
+ if (Target->KeepCompressed)
{
- HashStringList const newFile = GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, (*Target)->MetaKey);
- HashStringList const oldFile = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, (*Target)->MetaKey);
- if (newFile == oldFile)
- {
- // we have the file already, no point in trying to acquire it again
- new NoActionItem(Owner, *Target);
- continue;
- }
+ filename = GetKeepCompressedFileName(filename, *Target);
+ if (RealFileExists(filename) == false)
+ filename.clear();
}
+ else
+ filename.clear();
+ }
+
+ if (filename.empty() == false)
+ {
+ // if the Release file is a hit and we have an index it must be the current one
+ if (TransactionManager->IMSHit == true)
+ ;
+ else if (TransactionManager->LastMetaIndexParser != NULL)
+ {
+ // see if the file changed since the last Release file
+ // we use the uncompressed files as we might compress differently compared to the server,
+ // so the hashes might not match, even if they contain the same data.
+ HashStringList const newFile = GetExpectedHashesFromFor(TransactionManager->MetaIndexParser, Target->MetaKey);
+ HashStringList const oldFile = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target->MetaKey);
+ if (newFile != oldFile)
+ filename.clear();
+ }
+ else
+ filename.clear();
}
else
trypdiff = false; // no file to patch
+ if (filename.empty() == false)
+ {
+ new NoActionItem(Owner, *Target, filename);
+ std::string const idxfilename = GetFinalFileNameFromURI(Target->URI + ".diff/Index");
+ if (FileExists(idxfilename))
+ new NoActionItem(Owner, *Target, idxfilename);
+ continue;
+ }
+
// check if we have patches available
- trypdiff &= TransactionManager->MetaIndexParser->Exists((*Target)->MetaKey + ".diff/Index");
+ trypdiff &= TransactionManager->MetaIndexParser->Exists(Target->MetaKey + ".diff/Index");
+ }
+ else
+ {
+ // if we have no file to patch, no point in trying
+ std::string filename = GetFinalFileNameFromURI(Target->URI);
+ if (RealFileExists(filename) == false)
+ {
+ if (Target->KeepCompressed)
+ {
+ filename = GetKeepCompressedFileName(filename, *Target);
+ if (RealFileExists(filename) == false)
+ filename.clear();
+ }
+ else
+ filename.clear();
+ }
+ trypdiff &= (filename.empty() == false);
}
- // if we have no file to patch, no point in trying
- trypdiff &= RealFileExists(GetFinalFileNameFromURI((*Target)->URI));
// no point in patching from local sources
if (trypdiff)
{
- std::string const proto = (*Target)->URI.substr(0, strlen("file:/"));
+ std::string const proto = Target->URI.substr(0, strlen("file:/"));
if (proto == "file:/" || proto == "copy:/" || proto == "cdrom:")
trypdiff = false;
}
Transformed = "";
}
- if (_config->FindB("Acquire::Check-Valid-Until", true) == true &&
- TransactionManager->MetaIndexParser->GetValidUntil() > 0) {
+ if (TransactionManager->MetaIndexParser->GetValidUntil() > 0)
+ {
time_t const invalid_since = time(NULL) - TransactionManager->MetaIndexParser->GetValidUntil();
if (invalid_since > 0)
{
std::string errmsg;
strprintf(errmsg,
// TRANSLATOR: The first %s is the URL of the bad Release file, the second is
- // the time since then the file is invalid - formated in the same way as in
+ // the time since then the file is invalid - formatted in the same way as in
// the download progress display (e.g. 7d 3h 42min 1s)
_("Release file for %s is expired (invalid since %s). "
"Updates for this repository will not be applied."),
- DataTarget.URI.c_str(), TimeToStr(invalid_since).c_str());
+ Target.URI.c_str(), TimeToStr(invalid_since).c_str());
if (ErrorText.empty())
ErrorText = errmsg;
return _error->Error("%s", errmsg.c_str());
TransactionManager->LastMetaIndexParser->GetDate() > TransactionManager->MetaIndexParser->GetDate())
{
TransactionManager->IMSHit = true;
- unlink(DestFile.c_str());
+ RemoveFile("VerifyVendor", DestFile);
PartialFile = DestFile = GetFinalFilename();
- delete TransactionManager->MetaIndexParser;
- TransactionManager->MetaIndexParser = TransactionManager->LastMetaIndexParser;
+ // load the 'old' file in the 'new' one instead of flipping pointers as
+ // the new one isn't owned by us, while the old one is so cleanup would be confused.
+ TransactionManager->MetaIndexParser->swapLoad(TransactionManager->LastMetaIndexParser);
+ delete TransactionManager->LastMetaIndexParser;
TransactionManager->LastMetaIndexParser = NULL;
}
if (_config->FindB("Debug::pkgAcquire::Auth", false))
{
- std::cerr << "Got Codename: " << TransactionManager->MetaIndexParser->GetDist() << std::endl;
+ std::cerr << "Got Codename: " << TransactionManager->MetaIndexParser->GetCodename() << std::endl;
std::cerr << "Expecting Dist: " << TransactionManager->MetaIndexParser->GetExpectedDist() << std::endl;
std::cerr << "Transformed Dist: " << Transformed << std::endl;
}
// Status = StatAuthError;
// ErrorText = "Conflicting distribution; expected "
// + MetaIndexParser->GetExpectedDist() + " but got "
-// + MetaIndexParser->GetDist();
+// + MetaIndexParser->GetCodename();
// return false;
if (!Transformed.empty())
{
_error->Warning(_("Conflicting distribution: %s (expected %s but got %s)"),
Desc.Description.c_str(),
Transformed.c_str(),
- TransactionManager->MetaIndexParser->GetDist().c_str());
+ TransactionManager->MetaIndexParser->GetCodename().c_str());
}
}
return true;
}
/*}}}*/
+pkgAcqMetaBase::~pkgAcqMetaBase()
+{
+}
pkgAcqMetaClearSig::pkgAcqMetaClearSig(pkgAcquire * const Owner, /*{{{*/
IndexTarget const &ClearsignedTarget,
IndexTarget const &DetachedDataTarget, IndexTarget const &DetachedSigTarget,
- const vector<IndexTarget*>* const IndexTargets,
- indexRecords * const MetaIndexParser) :
- pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget, IndexTargets, MetaIndexParser),
- ClearsignedTarget(ClearsignedTarget),
- DetachedDataTarget(DetachedDataTarget), DetachedSigTarget(DetachedSigTarget)
+ std::vector<IndexTarget> const &IndexTargets,
+ metaIndex * const MetaIndexParser) :
+ pkgAcqMetaIndex(Owner, this, ClearsignedTarget, DetachedSigTarget, IndexTargets),
+ d(NULL), ClearsignedTarget(ClearsignedTarget),
+ DetachedDataTarget(DetachedDataTarget),
+ MetaIndexParser(MetaIndexParser), LastMetaIndexParser(NULL)
{
// index targets + (worst case:) Release/Release.gpg
- ExpectedAdditionalItems = IndexTargets->size() + 2;
+ ExpectedAdditionalItems = IndexTargets.size() + 2;
TransactionManager->Add(this);
}
/*}}}*/
pkgAcqMetaClearSig::~pkgAcqMetaClearSig() /*{{{*/
{
+ if (LastMetaIndexParser != NULL)
+ delete LastMetaIndexParser;
}
/*}}}*/
// pkgAcqMetaClearSig::Custom600Headers - Insert custom request headers /*{{{*/
{
string Header = pkgAcqMetaBase::Custom600Headers();
Header += "\nFail-Ignore: true";
+ std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
+ if (key.empty() == false)
+ Header += "\nSigned-By: " + key;
+
return Header;
}
/*}}}*/
+bool pkgAcqMetaClearSig::VerifyDone(std::string const &Message, /*{{{*/
+ pkgAcquire::MethodConfig const * const Cnf)
+{
+ Item::VerifyDone(Message, Cnf);
+
+ if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
+ return RenameOnError(NotClearsigned);
+
+ return true;
+}
+ /*}}}*/
// pkgAcqMetaClearSig::Done - We got a file /*{{{*/
void pkgAcqMetaClearSig::Done(std::string const &Message,
HashStringList const &Hashes,
{
Item::Done(Message, Hashes, Cnf);
- // if we expect a ClearTextSignature (InRelease), ensure that
- // this is what we get and if not fail to queue a
- // Release/Release.gpg, see #346386
- if (FileExists(DestFile) && !StartsWithGPGClearTextSignature(DestFile))
- {
- pkgAcquire::Item::Failed(Message, Cnf);
- RenameOnError(NotClearsigned);
- TransactionManager->AbortTransaction();
- return;
- }
-
if(AuthPass == false)
{
if(CheckDownloadDone(this, Message, Hashes) == true)
// We got an InRelease file IMSHit, but we haven't one, which means
// we had a valid Release/Release.gpg combo stepping in, which we have
// to 'acquire' now to ensure list cleanup isn't removing them
- new NoActionItem(Owner, &DetachedDataTarget);
- new NoActionItem(Owner, &DetachedSigTarget);
+ new NoActionItem(Owner, DetachedDataTarget);
+ new NoActionItem(Owner, DetachedSigTarget);
}
}
}
if (AuthPass == false)
{
+ if (Status == StatAuthError || Status == StatTransientNetworkError)
+ {
+ // if we expected a ClearTextSignature (InRelease) but got a network
+ // error or got a file, but it wasn't valid, we end up here (see VerifyDone).
+ // As these is usually called by web-portals we do not try Release/Release.gpg
+ // as this is gonna fail anyway and instead abort our try (LP#346386)
+ TransactionManager->AbortTransaction();
+ return;
+ }
+
// Queue the 'old' InRelease file for removal if we try Release.gpg
// as otherwise the file will stay around and gives a false-auth
// impression (CVE-2012-0214)
TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
Status = StatDone;
- new pkgAcqMetaIndex(Owner, TransactionManager, DetachedDataTarget, DetachedSigTarget, IndexTargets, TransactionManager->MetaIndexParser);
+ new pkgAcqMetaIndex(Owner, TransactionManager, DetachedDataTarget, DetachedSigTarget, IndexTargets);
}
else
{
if(CheckStopAuthentication(this, Message))
return;
- _error->Warning(_("The data from '%s' is not signed. Packages "
- "from that repository can not be authenticated."),
- ClearsignedTarget.Description.c_str());
-
// No Release file was present, or verification failed, so fall
// back to queueing Packages files without verification
- // only allow going further if the users explicitely wants it
- if(AllowInsecureRepositories(TransactionManager->MetaIndexParser, TransactionManager, this) == true)
+ // only allow going further if the user explicitly wants it
+ if(AllowInsecureRepositories(_("The repository '%s' is not signed."), ClearsignedTarget.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
{
Status = StatDone;
// open the last Release if we have it
if (TransactionManager->IMSHit == false)
{
- TransactionManager->LastMetaIndexParser = new indexRecords;
- _error->PushToStack();
- if (RealFileExists(FinalInRelease))
- TransactionManager->LastMetaIndexParser->Load(FinalInRelease);
- else
- TransactionManager->LastMetaIndexParser->Load(FinalRelease);
- // its unlikely to happen, but if what we have is bad ignore it
- if (_error->PendingError())
+ TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
+ if (TransactionManager->LastMetaIndexParser != NULL)
{
- delete TransactionManager->LastMetaIndexParser;
- TransactionManager->LastMetaIndexParser = NULL;
+ _error->PushToStack();
+ if (RealFileExists(FinalInRelease))
+ TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
+ else
+ TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
+ // its unlikely to happen, but if what we have is bad ignore it
+ if (_error->PendingError())
+ {
+ delete TransactionManager->LastMetaIndexParser;
+ TransactionManager->LastMetaIndexParser = NULL;
+ }
+ _error->RevertToStack();
}
- _error->RevertToStack();
}
}
// we parse the indexes here because at this point the user wanted
// a repository that may potentially harm him
- if (TransactionManager->MetaIndexParser->Load(PartialRelease) == false || VerifyVendor(Message) == false)
+ if (TransactionManager->MetaIndexParser->Load(PartialRelease, &ErrorText) == false || VerifyVendor(Message) == false)
/* expired Release files are still a problem you need extra force for */;
else
QueueIndexes(true);
/*}}}*/
pkgAcqMetaIndex::pkgAcqMetaIndex(pkgAcquire * const Owner, /*{{{*/
- pkgAcqMetaBase * const TransactionManager,
+ pkgAcqMetaClearSig * const TransactionManager,
IndexTarget const &DataTarget,
IndexTarget const &DetachedSigTarget,
- vector<IndexTarget*> const * const IndexTargets,
- indexRecords * const MetaIndexParser) :
- pkgAcqMetaBase(Owner, TransactionManager, IndexTargets, DataTarget, MetaIndexParser),
+ vector<IndexTarget> const &IndexTargets) :
+ pkgAcqMetaBase(Owner, TransactionManager, IndexTargets, DataTarget), d(NULL),
DetachedSigTarget(DetachedSigTarget)
{
if(_config->FindB("Debug::Acquire::Transaction", false) == true)
Desc.URI = DataTarget.URI;
// we expect more item
- ExpectedAdditionalItems = IndexTargets->size();
+ ExpectedAdditionalItems = IndexTargets.size();
QueueURI(Desc);
}
/*}}}*/
// we have a Release file, now download the Signature, all further
// verify/queue for additional downloads will be done in the
// pkgAcqMetaSig::Done() code
- new pkgAcqMetaSig(Owner, TransactionManager, &DetachedSigTarget, this);
+ new pkgAcqMetaSig(Owner, TransactionManager, DetachedSigTarget, this);
}
}
/*}}}*/
pkgAcquire::Item::Failed(Message, Cnf);
Status = StatDone;
- _error->Warning(_("The repository '%s' does not have a Release file. "
- "This is deprecated, please contact the owner of the "
- "repository."), DataTarget.Description.c_str());
-
// No Release file was present so fall
// back to queueing Packages files without verification
- // only allow going further if the users explicitely wants it
- if(AllowInsecureRepositories(TransactionManager->MetaIndexParser, TransactionManager, this) == true)
+ // only allow going further if the user explicitly wants it
+ if(AllowInsecureRepositories(_("The repository '%s' does not have a Release file."), Target.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
{
// ensure old Release files are removed
TransactionManager->TransactionStageRemoval(this, GetFinalFilename());
- delete TransactionManager->MetaIndexParser;
- TransactionManager->MetaIndexParser = NULL;
// queue without any kind of hashsum support
QueueIndexes(false);
/*}}}*/
std::string pkgAcqMetaIndex::DescURI() const /*{{{*/
{
- return DataTarget.URI;
+ return Target.URI;
}
/*}}}*/
+pkgAcqMetaIndex::~pkgAcqMetaIndex() {}
// AcqMetaSig::AcqMetaSig - Constructor /*{{{*/
pkgAcqMetaSig::pkgAcqMetaSig(pkgAcquire * const Owner,
- pkgAcqMetaBase * const TransactionManager,
- IndexTarget const * const Target,
+ pkgAcqMetaClearSig * const TransactionManager,
+ IndexTarget const &Target,
pkgAcqMetaIndex * const MetaIndex) :
- pkgAcqTransactionItem(Owner, TransactionManager, Target), MetaIndex(MetaIndex)
+ pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL), MetaIndex(MetaIndex)
{
- DestFile = GetPartialFileNameFromURI(Target->URI);
+ DestFile = GetPartialFileNameFromURI(Target.URI);
// remove any partial downloaded sig-file in partial/.
// it may confuse proxies and is too small to warrant a
// partial download anyway
- unlink(DestFile.c_str());
+ RemoveFile("pkgAcqMetaSig", DestFile);
// set the TransactionManager
if(_config->FindB("Debug::Acquire::Transaction", false) == true)
<< TransactionManager << std::endl;
// Create the item
- Desc.Description = Target->Description;
+ Desc.Description = Target.Description;
Desc.Owner = this;
- Desc.ShortDesc = Target->ShortDesc;
- Desc.URI = Target->URI;
+ Desc.ShortDesc = Target.ShortDesc;
+ Desc.URI = Target.URI;
// If we got a hit for Release, we will get one for Release.gpg too (or obscure errors),
// so we skip the download step and go instantly to verification
/*}}}*/
pkgAcqMetaSig::~pkgAcqMetaSig() /*{{{*/
{
+}
+ /*}}}*/
+// pkgAcqMetaSig::Custom600Headers - Insert custom request headers /*{{{*/
+std::string pkgAcqMetaSig::Custom600Headers() const
+{
+ std::string Header = pkgAcqTransactionItem::Custom600Headers();
+ std::string const key = TransactionManager->MetaIndexParser->GetSignedBy();
+ if (key.empty() == false)
+ Header += "\nSigned-By: " + key;
+ return Header;
}
/*}}}*/
// AcqMetaSig::Done - The signature was downloaded/verified /*{{{*/
{
std::string downgrade_msg;
strprintf(downgrade_msg, _("The repository '%s' is no longer signed."),
- MetaIndex->DataTarget.Description.c_str());
+ MetaIndex->Target.Description.c_str());
if(_config->FindB("Acquire::AllowDowngradeToInsecureRepositories"))
{
// meh, the users wants to take risks (we still mark the packages
"given to override it."));
Status = StatDone;
} else {
- _error->Error("%s", downgrade_msg.c_str());
+ MessageInsecureRepository(true, downgrade_msg);
if (TransactionManager->IMSHit == false)
Rename(MetaIndex->DestFile, MetaIndex->DestFile + ".FAILED");
Item::Failed("Message: " + downgrade_msg, Cnf);
return;
}
}
- else
- _error->Warning(_("The data from '%s' is not signed. Packages "
- "from that repository can not be authenticated."),
- MetaIndex->DataTarget.Description.c_str());
// ensures that a Release.gpg file in the lists/ is removed by the transaction
TransactionManager->TransactionStageRemoval(this, DestFile);
- // only allow going further if the users explicitely wants it
- if(AllowInsecureRepositories(TransactionManager->MetaIndexParser, TransactionManager, this) == true)
+ // only allow going further if the user explicitly wants it
+ if (AllowInsecureRepositories(_("The repository '%s' is not signed."), MetaIndex->Target.Description, TransactionManager->MetaIndexParser, TransactionManager, this) == true)
{
if (RealFileExists(FinalReleasegpg) || RealFileExists(FinalInRelease))
{
// open the last Release if we have it
if (TransactionManager->IMSHit == false)
{
- TransactionManager->LastMetaIndexParser = new indexRecords;
- _error->PushToStack();
- if (RealFileExists(FinalInRelease))
- TransactionManager->LastMetaIndexParser->Load(FinalInRelease);
- else
- TransactionManager->LastMetaIndexParser->Load(FinalRelease);
- // its unlikely to happen, but if what we have is bad ignore it
- if (_error->PendingError())
+ TransactionManager->LastMetaIndexParser = TransactionManager->MetaIndexParser->UnloadedClone();
+ if (TransactionManager->LastMetaIndexParser != NULL)
{
- delete TransactionManager->LastMetaIndexParser;
- TransactionManager->LastMetaIndexParser = NULL;
+ _error->PushToStack();
+ if (RealFileExists(FinalInRelease))
+ TransactionManager->LastMetaIndexParser->Load(FinalInRelease, NULL);
+ else
+ TransactionManager->LastMetaIndexParser->Load(FinalRelease, NULL);
+ // its unlikely to happen, but if what we have is bad ignore it
+ if (_error->PendingError())
+ {
+ delete TransactionManager->LastMetaIndexParser;
+ TransactionManager->LastMetaIndexParser = NULL;
+ }
+ _error->RevertToStack();
}
- _error->RevertToStack();
}
}
// we parse the indexes here because at this point the user wanted
// a repository that may potentially harm him
- if (TransactionManager->MetaIndexParser->Load(MetaIndex->DestFile) == false || MetaIndex->VerifyVendor(Message) == false)
+ bool const GoodLoad = TransactionManager->MetaIndexParser->Load(MetaIndex->DestFile, &ErrorText);
+ if (MetaIndex->VerifyVendor(Message) == false)
/* expired Release files are still a problem you need extra force for */;
else
- MetaIndex->QueueIndexes(true);
+ MetaIndex->QueueIndexes(GoodLoad);
TransactionManager->TransactionStageCopy(MetaIndex, MetaIndex->DestFile, MetaIndex->GetFinalFilename());
}
// AcqBaseIndex - Constructor /*{{{*/
pkgAcqBaseIndex::pkgAcqBaseIndex(pkgAcquire * const Owner,
- pkgAcqMetaBase * const TransactionManager,
- IndexTarget const * const Target)
-: pkgAcqTransactionItem(Owner, TransactionManager, Target)
+ pkgAcqMetaClearSig * const TransactionManager,
+ IndexTarget const &Target)
+: pkgAcqTransactionItem(Owner, TransactionManager, Target), d(NULL)
{
}
/*}}}*/
+pkgAcqBaseIndex::~pkgAcqBaseIndex() {}
// AcqDiffIndex::AcqDiffIndex - Constructor /*{{{*/
// ---------------------------------------------------------------------
* the original packages file
*/
pkgAcqDiffIndex::pkgAcqDiffIndex(pkgAcquire * const Owner,
- pkgAcqMetaBase * const TransactionManager,
- IndexTarget const * const Target)
- : pkgAcqBaseIndex(Owner, TransactionManager, Target)
+ pkgAcqMetaClearSig * const TransactionManager,
+ IndexTarget const &Target)
+ : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), diffs(NULL)
{
Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
Desc.Owner = this;
- Desc.Description = Target->Description + ".diff/Index";
- Desc.ShortDesc = Target->ShortDesc;
- Desc.URI = Target->URI + ".diff/Index";
+ Desc.Description = Target.Description + ".diff/Index";
+ Desc.ShortDesc = Target.ShortDesc;
+ Desc.URI = Target.URI + ".diff/Index";
DestFile = GetPartialFileNameFromURI(Desc.URI);
/* The only header we use is the last-modified header. */
string pkgAcqDiffIndex::Custom600Headers() const
{
+ if (TransactionManager->LastMetaIndexParser != NULL)
+ return "\nIndex-File: true";
+
string const Final = GetFinalFilename();
if(Debug)
FileFd Fd(IndexDiffFile,FileFd::ReadOnly);
pkgTagFile TF(&Fd);
- if (_error->PendingError() == true)
+ if (Fd.IsOpen() == false || Fd.Failed())
return false;
pkgTagSection Tags;
return false;
}
- std::string const CurrentPackagesFile = GetFinalFileNameFromURI(Target->URI);
- HashStringList const TargetFileHashes = GetExpectedHashesFor(Target->MetaKey);
+ std::string const CurrentPackagesFile = GetFinalFileNameFromURI(Target.URI);
+ HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
if (TargetFileHashes.usable() == false || ServerHashes != TargetFileHashes)
{
if (Debug == true)
HashStringList LocalHashes;
// try avoiding calculating the hash here as this is costly
if (TransactionManager->LastMetaIndexParser != NULL)
- LocalHashes = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target->MetaKey);
+ LocalHashes = GetExpectedHashesFromFor(TransactionManager->LastMetaIndexParser, Target.MetaKey);
if (LocalHashes.usable() == false)
{
- FileFd fd(CurrentPackagesFile, FileFd::ReadOnly);
+ FileFd fd(CurrentPackagesFile, FileFd::ReadOnly, FileFd::Auto);
Hashes LocalHashesCalc(ServerHashes);
LocalHashesCalc.AddFD(fd);
LocalHashes = LocalHashesCalc.GetHashStringList();
std::clog << "Server-Current: " << ServerHashes.find(NULL)->toStr() << " and we start at "
<< CurrentPackagesFile << " " << LocalHashes.FileSize() << " " << LocalHashes.find(NULL)->toStr() << std::endl;
+ // historically, older hashes have more info than newer ones, so start
+ // collecting with older ones first to avoid implementing complicated
+ // information merging techniques… a failure is after all always
+ // recoverable with a complete file and hashes aren't changed that often.
+ std::vector<char const *> types;
+ for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+ types.push_back(*type);
+
// parse all of (provided) history
vector<DiffInfo> available_patches;
bool firstAcceptedHashes = true;
- for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+ for (auto type = types.crbegin(); type != types.crend(); ++type)
{
if (LocalHashes.find(*type) == NULL)
continue;
return false;
}
- for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+ for (auto type = types.crbegin(); type != types.crend(); ++type)
{
if (LocalHashes.find(*type) == NULL)
continue;
}
}
- for (char const * const * type = HashString::SupportedHashes(); *type != NULL; ++type)
+ for (auto type = types.crbegin(); type != types.crend(); ++type)
{
std::string tagname = *type;
tagname.append("-Download");
new pkgAcqIndexDiffs(Owner, TransactionManager, Target, available_patches);
else
{
- std::vector<pkgAcqIndexMergeDiffs*> *diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
+ diffs = new std::vector<pkgAcqIndexMergeDiffs*>(available_patches.size());
for(size_t i = 0; i < available_patches.size(); ++i)
(*diffs)[i] = new pkgAcqIndexMergeDiffs(Owner, TransactionManager,
Target,
return;
}
/*}}}*/
+pkgAcqDiffIndex::~pkgAcqDiffIndex()
+{
+ if (diffs != NULL)
+ delete diffs;
+}
// AcqIndexDiffs::AcqIndexDiffs - Constructor /*{{{*/
// ---------------------------------------------------------------------
* for each diff and the index
*/
pkgAcqIndexDiffs::pkgAcqIndexDiffs(pkgAcquire * const Owner,
- pkgAcqMetaBase * const TransactionManager,
- IndexTarget const * const Target,
+ pkgAcqMetaClearSig * const TransactionManager,
+ IndexTarget const &Target,
vector<DiffInfo> const &diffs)
- : pkgAcqBaseIndex(Owner, TransactionManager, Target),
+ : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
available_patches(diffs)
{
- DestFile = GetPartialFileNameFromURI(Target->URI);
+ DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
Desc.Owner = this;
- Description = Target->Description;
- Desc.ShortDesc = Target->ShortDesc;
+ Description = Target.Description;
+ Desc.ShortDesc = Target.ShortDesc;
if(available_patches.empty() == true)
{
// we are done (yeah!), check hashes against the final file
- DestFile = GetFinalFileNameFromURI(Target->URI);
+ DestFile = GetKeepCompressedFileName(GetFinalFileNameFromURI(Target.URI), Target);
Finish(true);
}
else
{
- // patching needs to be bootstrapped with the 'old' version
- std::string const PartialFile = GetPartialFileNameFromURI(Target->URI);
- if (RealFileExists(PartialFile) == false)
+ if (BootstrapPDiffWith(GetPartialFileNameFromURI(Target.URI), GetFinalFilename(), Target) == false)
{
- if (symlink(GetFinalFilename().c_str(), PartialFile.c_str()) != 0)
- {
- Failed("Link creation of " + PartialFile + " to " + GetFinalFilename() + " failed", NULL);
- return;
- }
+ Failed("Bootstrapping of " + DestFile + " failed", NULL);
+ return;
}
// get the next diff
Item::Failed(Message,Cnf);
Status = StatDone;
+ DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
if(Debug)
std::clog << "pkgAcqIndexDiffs failed: " << Desc.URI << " with " << Message << std::endl
- << "Falling back to normal index file acquire" << std::endl;
- DestFile = GetPartialFileNameFromURI(Target->URI);
+ << "Falling back to normal index file acquire " << std::endl;
RenameOnError(PDiffError);
std::string const patchname = GetDiffsPatchFileName(DestFile);
if (RealFileExists(patchname))
// the file will be cleaned
if(allDone)
{
- TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
+ std::string Final = GetFinalFilename();
+ if (Target.KeepCompressed)
+ {
+ std::string const ext = flExtension(DestFile);
+ if (ext.empty() == false)
+ Final.append(".").append(ext);
+ }
+ TransactionManager->TransactionStageCopy(this, DestFile, Final);
// this is for the "real" finish
Complete = true;
std::clog << "\n\nallDone: " << DestFile << "\n" << std::endl;
return;
}
+ else
+ DestFile.clear();
if(Debug)
std::clog << "Finishing: " << Desc.URI << std::endl;
bool pkgAcqIndexDiffs::QueueNextDiff() /*{{{*/
{
// calc sha1 of the just patched file
- std::string const FinalFile = GetPartialFileNameFromURI(Target->URI);
-
+ std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
if(!FileExists(FinalFile))
{
Failed("Message: No FinalFile " + FinalFile + " available", NULL);
return false;
}
- FileFd fd(FinalFile, FileFd::ReadOnly);
+ FileFd fd(FinalFile, FileFd::ReadOnly, FileFd::Extension);
Hashes LocalHashesCalc;
LocalHashesCalc.AddFD(fd);
HashStringList const LocalHashes = LocalHashesCalc.GetHashStringList();
if(Debug)
std::clog << "QueueNextDiff: " << FinalFile << " (" << LocalHashes.find(NULL)->toStr() << ")" << std::endl;
- HashStringList const TargetFileHashes = GetExpectedHashesFor(Target->MetaKey);
+ HashStringList const TargetFileHashes = GetExpectedHashesFor(Target.MetaKey);
if (unlikely(LocalHashes.usable() == false || TargetFileHashes.usable() == false))
{
Failed("Local/Expected hashes are not usable", NULL);
// remove all patches until the next matching patch is found
// this requires the Index file to be ordered
- for(vector<DiffInfo>::iterator I = available_patches.begin();
- available_patches.empty() == false &&
- I != available_patches.end() &&
- I->result_hashes != LocalHashes;
- ++I)
- {
- available_patches.erase(I);
- }
+ available_patches.erase(available_patches.begin(),
+ std::find_if(available_patches.begin(), available_patches.end(), [&](DiffInfo const &I) {
+ return I.result_hashes == LocalHashes;
+ }));
// error checking and falling back if no patch was found
if(available_patches.empty() == true)
}
// queue the right diff
- Desc.URI = Target->URI + ".diff/" + available_patches[0].file + ".gz";
+ Desc.URI = Target.URI + ".diff/" + available_patches[0].file + ".gz";
Desc.Description = Description + " " + available_patches[0].file + string(".pdiff");
- DestFile = GetPartialFileNameFromURI(Target->URI + ".diff/" + available_patches[0].file);
+ DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI + ".diff/" + available_patches[0].file), Target);
if(Debug)
std::clog << "pkgAcqIndexDiffs::QueueNextDiff(): " << Desc.URI << std::endl;
Item::Done(Message, Hashes, Cnf);
- std::string const FinalFile = GetPartialFileNameFromURI(Target->URI);
+ std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
std::string const PatchFile = GetDiffsPatchFileName(FinalFile);
// success in downloading a diff, enter ApplyDiff state
{
// remove the just applied patch
available_patches.erase(available_patches.begin());
- unlink(PatchFile.c_str());
+ RemoveFile("pkgAcqIndexDiffs::Done", PatchFile);
// move into place
if(Debug)
return patchhashes.str();
}
/*}}}*/
+pkgAcqIndexDiffs::~pkgAcqIndexDiffs() {}
// AcqIndexMergeDiffs::AcqIndexMergeDiffs - Constructor /*{{{*/
pkgAcqIndexMergeDiffs::pkgAcqIndexMergeDiffs(pkgAcquire * const Owner,
- pkgAcqMetaBase * const TransactionManager,
- IndexTarget const * const Target,
+ pkgAcqMetaClearSig * const TransactionManager,
+ IndexTarget const &Target,
DiffInfo const &patch,
std::vector<pkgAcqIndexMergeDiffs*> const * const allPatches)
- : pkgAcqBaseIndex(Owner, TransactionManager, Target),
+ : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL),
patch(patch), allPatches(allPatches), State(StateFetchDiff)
{
Debug = _config->FindB("Debug::pkgAcquire::Diffs",false);
Desc.Owner = this;
- Description = Target->Description;
- Desc.ShortDesc = Target->ShortDesc;
+ Description = Target.Description;
+ Desc.ShortDesc = Target.ShortDesc;
- Desc.URI = Target->URI + ".diff/" + patch.file + ".gz";
+ Desc.URI = Target.URI + ".diff/" + patch.file + ".gz";
Desc.Description = Description + " " + patch.file + string(".pdiff");
- DestFile = GetPartialFileNameFromURI(Target->URI + ".diff/" + patch.file);
+ DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI + ".diff/" + patch.file), Target);
if(Debug)
std::clog << "pkgAcqIndexMergeDiffs: " << Desc.URI << std::endl;
State = StateErrorDiff;
if (Debug)
std::clog << "Falling back to normal index file acquire" << std::endl;
- DestFile = GetPartialFileNameFromURI(Target->URI);
+ DestFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
RenameOnError(PDiffError);
std::string const patchname = GetMergeDiffsPatchFileName(DestFile, patch.file);
if (RealFileExists(patchname))
rename(patchname.c_str(), std::string(patchname + ".FAILED").c_str());
new pkgAcqIndex(Owner, TransactionManager, Target);
+ DestFile.clear();
}
/*}}}*/
void pkgAcqIndexMergeDiffs::Done(string const &Message, HashStringList const &Hashes, /*{{{*/
Item::Done(Message, Hashes, Cnf);
- string const FinalFile = GetPartialFileNameFromURI(Target->URI);
+ std::string const UncompressedFinalFile = GetPartialFileNameFromURI(Target.URI);
+ std::string const FinalFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
if (State == StateFetchDiff)
{
Rename(DestFile, GetMergeDiffsPatchFileName(FinalFile, patch.file));
// this is the last completed diff, so we are ready to apply now
State = StateApplyDiff;
- // patching needs to be bootstrapped with the 'old' version
- if (symlink(GetFinalFilename().c_str(), FinalFile.c_str()) != 0)
+ if (BootstrapPDiffWith(UncompressedFinalFile, GetFinalFilename(), Target) == false)
{
- Failed("Link creation of " + FinalFile + " to " + GetFinalFilename() + " failed", NULL);
+ Failed("Bootstrapping of " + DestFile + " failed", NULL);
return;
}
else if (State == StateApplyDiff)
{
// move the result into place
- std::string const Final = GetFinalFilename();
+ std::string const Final = GetKeepCompressedFileName(GetFinalFilename(), Target);
if(Debug)
std::clog << "Queue patched file in place: " << std::endl
<< DestFile << " -> " << Final << std::endl;
for (std::vector<pkgAcqIndexMergeDiffs *>::const_iterator I = allPatches->begin();
I != allPatches->end(); ++I)
{
- std::string const PartialFile = GetPartialFileNameFromURI(Target->URI);
+ std::string const PartialFile = GetKeepCompressedFileName(GetPartialFileNameFromURI(Target.URI), Target);
std::string const patch = GetMergeDiffsPatchFileName(PartialFile, (*I)->patch.file);
- unlink(patch.c_str());
+ RemoveFile("pkgAcqIndexMergeDiffs::Done", patch);
}
- unlink(FinalFile.c_str());
+ RemoveFile("pkgAcqIndexMergeDiffs::Done", FinalFile);
// all set and done
Complete = true;
return patchhashes.str();
}
/*}}}*/
+pkgAcqIndexMergeDiffs::~pkgAcqIndexMergeDiffs() {}
// AcqIndex::AcqIndex - Constructor /*{{{*/
pkgAcqIndex::pkgAcqIndex(pkgAcquire * const Owner,
- pkgAcqMetaBase * const TransactionManager,
- IndexTarget const * const Target)
- : pkgAcqBaseIndex(Owner, TransactionManager, Target)
+ pkgAcqMetaClearSig * const TransactionManager,
+ IndexTarget const &Target)
+ : pkgAcqBaseIndex(Owner, TransactionManager, Target), d(NULL), Stage(STAGE_DOWNLOAD),
+ CompressionExtensions(Target.Option(IndexTarget::COMPRESSIONTYPES))
{
- // autoselect the compression method
- AutoSelectCompression();
- Init(Target->URI, Target->Description, Target->ShortDesc);
+ Init(Target.URI, Target.Description, Target.ShortDesc);
if(_config->FindB("Debug::Acquire::Transaction", false) == true)
std::clog << "New pkgIndex with TransactionManager "
<< TransactionManager << std::endl;
}
/*}}}*/
-// AcqIndex::AutoSelectCompression - Select compression /*{{{*/
-void pkgAcqIndex::AutoSelectCompression()
+// AcqIndex::Init - defered Constructor /*{{{*/
+static void NextCompressionExtension(std::string &CurrentCompressionExtension, std::string &CompressionExtensions, bool const preview)
{
- std::vector<std::string> types = APT::Configuration::getCompressionTypes();
- CompressionExtensions = "";
- if (TransactionManager->MetaIndexParser != NULL && TransactionManager->MetaIndexParser->Exists(Target->MetaKey))
+ size_t const nextExt = CompressionExtensions.find(' ');
+ if (nextExt == std::string::npos)
{
- for (std::vector<std::string>::const_iterator t = types.begin();
- t != types.end(); ++t)
- {
- std::string CompressedMetaKey = string(Target->MetaKey).append(".").append(*t);
- if (*t == "uncompressed" ||
- TransactionManager->MetaIndexParser->Exists(CompressedMetaKey) == true)
- CompressionExtensions.append(*t).append(" ");
- }
+ CurrentCompressionExtension = CompressionExtensions;
+ if (preview == false)
+ CompressionExtensions.clear();
}
else
{
- for (std::vector<std::string>::const_iterator t = types.begin(); t != types.end(); ++t)
- CompressionExtensions.append(*t).append(" ");
+ CurrentCompressionExtension = CompressionExtensions.substr(0, nextExt);
+ if (preview == false)
+ CompressionExtensions = CompressionExtensions.substr(nextExt+1);
}
- 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 = GetPartialFileNameFromURI(URI);
+ NextCompressionExtension(CurrentCompressionExtension, CompressionExtensions, false);
- size_t const nextExt = CompressionExtensions.find(' ');
- if (nextExt == std::string::npos)
+ if (CurrentCompressionExtension == "uncompressed")
{
- CurrentCompressionExtension = CompressionExtensions;
- CompressionExtensions.clear();
+ Desc.URI = URI;
}
- else
+ else if (CurrentCompressionExtension == "by-hash")
{
- CurrentCompressionExtension = CompressionExtensions.substr(0, nextExt);
- CompressionExtensions = CompressionExtensions.substr(nextExt+1);
- }
+ NextCompressionExtension(CurrentCompressionExtension, CompressionExtensions, true);
+ if(unlikely(TransactionManager->MetaIndexParser == NULL || CurrentCompressionExtension.empty()))
+ return;
+ if (CurrentCompressionExtension != "uncompressed")
+ {
+ Desc.URI = URI + '.' + CurrentCompressionExtension;
+ DestFile = DestFile + '.' + CurrentCompressionExtension;
+ }
- if (CurrentCompressionExtension == "uncompressed")
- {
- Desc.URI = URI;
+ HashStringList const Hashes = GetExpectedHashes();
+ HashString const * const TargetHash = Hashes.find(NULL);
+ if (unlikely(TargetHash == nullptr))
+ return;
+ std::string const ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
+ size_t const trailing_slash = Desc.URI.find_last_of("/");
+ if (unlikely(trailing_slash == std::string::npos))
+ return;
+ Desc.URI = Desc.URI.replace(
+ trailing_slash,
+ Desc.URI.substr(trailing_slash+1).size()+1,
+ ByHash);
}
else if (unlikely(CurrentCompressionExtension.empty()))
return;
DestFile = DestFile + '.' + CurrentCompressionExtension;
}
- if(TransactionManager->MetaIndexParser != NULL)
- InitByHashIfNeeded();
Desc.Description = URIDesc;
Desc.Owner = this;
QueueURI(Desc);
}
/*}}}*/
-// AcqIndex::AdjustForByHash - modify URI for by-hash support /*{{{*/
-void pkgAcqIndex::InitByHashIfNeeded()
-{
- // 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 ||
- TransactionManager->MetaIndexParser->GetSupportsAcquireByHash())
- {
- HashStringList const Hashes = GetExpectedHashes();
- if(Hashes.usable())
- {
- // FIXME: should we really use the best hash here? or a fixed one?
- HashString const * const TargetHash = Hashes.find("");
- std::string const ByHash = "/by-hash/" + TargetHash->HashType() + "/" + TargetHash->HashValue();
- size_t const 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",
- GetMetaKey().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);
- if(Target->IsOptional)
+ if (TransactionManager->LastMetaIndexParser == NULL)
+ {
+ std::string const Final = GetFinalFilename();
+
+ struct stat Buf;
+ if (stat(Final.c_str(),&Buf) == 0)
+ msg += "\nLast-Modified: " + TimeRFC1123(Buf.st_mtime);
+ }
+
+ if(Target.IsOptional)
msg += "\nFail-Ignore: true";
return msg;
{
if (CompressionExtensions.empty() == false)
{
- Init(Target->URI, Desc.Description, Desc.ShortDesc);
+ Init(Target.URI, Desc.Description, Desc.ShortDesc);
Status = StatIdle;
return;
}
}
- if(Target->IsOptional && GetExpectedHashes().empty() && Stage == STAGE_DOWNLOAD)
+ if(Target.IsOptional && GetExpectedHashes().empty() && Stage == STAGE_DOWNLOAD)
Status = StatDone;
else
TransactionManager->AbortTransaction();
{
// update destfile to *not* include the compression extension when doing
// a reverify (as its uncompressed on disk already)
- DestFile = GetCompressedFileName(Target->URI, GetPartialFileNameFromURI(Target->URI), CurrentCompressionExtension);
+ DestFile = GetCompressedFileName(Target, GetPartialFileNameFromURI(Target.URI), CurrentCompressionExtension);
// copy FinalFile into partial/ so that we check the hash again
string FinalFile = GetFinalFilename();
Complete = true;
// Handle the unzipd case
- string FileName = LookupTag(Message,"Alt-Filename");
+ std::string FileName = LookupTag(Message,"Alt-Filename");
if (FileName.empty() == false)
{
Stage = STAGE_DECOMPRESS_AND_VERIFY;
SetActiveSubprocess("copy");
return;
}
-
FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- }
// Methods like e.g. "file:" will give us a (compressed) FileName that is
// not the "DestFile" we set, in this case we uncompress from the local file
- if (FileName != DestFile)
+ if (FileName != DestFile && RealFileExists(DestFile) == false)
+ {
Local = true;
+ if (Target.KeepCompressed == true)
+ {
+ // but if we don't keep the uncompress we copy the compressed file first
+ Stage = STAGE_DOWNLOAD;
+ Desc.URI = "copy:" + FileName;
+ QueueURI(Desc);
+ SetActiveSubprocess("copy");
+ return;
+ }
+ }
else
EraseFileName = FileName;
return;
}
- // If we have compressed indexes enabled, queue for hash verification
- if (_config->FindB("Acquire::GzipIndexes",false))
- {
- DestFile = GetPartialFileNameFromURI(Target->URI + '.' + CurrentCompressionExtension);
- EraseFileName = "";
- Stage = STAGE_DECOMPRESS_AND_VERIFY;
- Desc.URI = "copy:" + FileName;
- QueueURI(Desc);
- SetActiveSubprocess("copy");
- return;
- }
-
// get the binary name for your used compression type
string decompProg;
if(CurrentCompressionExtension == "uncompressed")
return;
}
+ if (Target.KeepCompressed == true)
+ {
+ DestFile = "/dev/null";
+ EraseFileName.clear();
+ }
+ else
+ DestFile += ".decomp";
+
// queue uri for the next stage
Stage = STAGE_DECOMPRESS_AND_VERIFY;
- DestFile += ".decomp";
Desc.URI = decompProg + ":" + FileName;
QueueURI(Desc);
SetActiveSubprocess(decompProg);
HashStringList const &,
pkgAcquire::MethodConfig const * const)
{
+ if (Target.KeepCompressed == true && DestFile == "/dev/null")
+ DestFile = GetPartialFileNameFromURI(Target.URI + '.' + CurrentCompressionExtension);
+
// Done, queue for rename on transaction finished
TransactionManager->TransactionStageCopy(this, DestFile, GetFinalFilename());
return;
}
/*}}}*/
+pkgAcqIndex::~pkgAcqIndex() {}
// AcqArchive::AcqArchive - Constructor /*{{{*/
pkgAcqArchive::pkgAcqArchive(pkgAcquire * const Owner,pkgSourceList * const Sources,
pkgRecords * const Recs,pkgCache::VerIterator const &Version,
string &StoreFilename) :
- Item(Owner), LocalSource(false), Version(Version), Sources(Sources), Recs(Recs),
+ Item(Owner), d(NULL), LocalSource(false), Version(Version), Sources(Sources), Recs(Recs),
StoreFilename(StoreFilename), Vf(Version.FileList()),
Trusted(false)
{
// Skip not source sources, they do not have file fields.
for (; Vf.end() == false; ++Vf)
{
- if ((Vf.File()->Flags & pkgCache::Flag::NotSource) != 0)
+ if (Vf.File().Flagged(pkgCache::Flag::NotSource))
continue;
break;
}
{
pkgCache::PkgFileIterator const PkgF = Vf.File();
// Ignore not source sources
- if ((PkgF->Flags & pkgCache::Flag::NotSource) != 0)
+ if (PkgF.Flagged(pkgCache::Flag::NotSource))
continue;
// Try to cross match against the source list
pkgIndexFile *Index;
if (Sources->FindIndex(PkgF, Index) == false)
continue;
- LocalSource = (PkgF->Flags & pkgCache::Flag::LocalSource) == pkgCache::Flag::LocalSource;
+ LocalSource = PkgF.Flagged(pkgCache::Flag::LocalSource);
// only try to get a trusted package from another source if that source
// is also trusted
/* Hmm, we have a file and its size does not match, this means it is
an old style mismatched arch */
- unlink(FinalFile.c_str());
+ RemoveFile("pkgAcqArchive::QueueNext", FinalFile);
}
// Check it again using the new style output filenames
/* Hmm, we have a file and its size does not match, this shouldn't
happen.. */
- unlink(FinalFile.c_str());
+ RemoveFile("pkgAcqArchive::QueueNext", FinalFile);
}
DestFile = _config->FindDir("Dir::Cache::Archives") + "partial/" + flNotDir(StoreFilename);
{
// Hmm, the partial file is too big, erase it
if ((unsigned long long)Buf.st_size > Version->Size)
- unlink(DestFile.c_str());
+ RemoveFile("pkgAcqArchive::QueueNext", DestFile);
else
PartialSize = Buf.st_size;
}
Item::Done(Message, Hashes, Cfg);
// Grab the output filename
- string FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- return;
- }
-
- // Reference filename
- if (FileName != DestFile)
+ std::string const FileName = LookupTag(Message,"Filename");
+ if (DestFile != FileName && RealFileExists(DestFile) == false)
{
StoreFilename = DestFile = FileName;
Local = true;
return Desc.ShortDesc;
}
/*}}}*/
+pkgAcqArchive::~pkgAcqArchive() {}
+
+// AcqChangelog::pkgAcqChangelog - Constructors /*{{{*/
+pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::VerIterator const &Ver,
+ std::string const &DestDir, std::string const &DestFilename) :
+ pkgAcquire::Item(Owner), d(NULL), SrcName(Ver.SourcePkgName()), SrcVersion(Ver.SourceVerStr())
+{
+ Desc.URI = URI(Ver);
+ Init(DestDir, DestFilename);
+}
+// some parameters are char* here as they come likely from char* interfaces – which can also return NULL
+pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner, pkgCache::RlsFileIterator const &RlsFile,
+ char const * const Component, char const * const SrcName, char const * const SrcVersion,
+ const string &DestDir, const string &DestFilename) :
+ pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
+{
+ Desc.URI = URI(RlsFile, Component, SrcName, SrcVersion);
+ Init(DestDir, DestFilename);
+}
+pkgAcqChangelog::pkgAcqChangelog(pkgAcquire * const Owner,
+ std::string const &URI, char const * const SrcName, char const * const SrcVersion,
+ const string &DestDir, const string &DestFilename) :
+ pkgAcquire::Item(Owner), d(NULL), SrcName(SrcName), SrcVersion(SrcVersion)
+{
+ Desc.URI = URI;
+ Init(DestDir, DestFilename);
+}
+void pkgAcqChangelog::Init(std::string const &DestDir, std::string const &DestFilename)
+{
+ if (Desc.URI.empty())
+ {
+ Status = StatError;
+ // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
+ strprintf(ErrorText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
+ // Let the error message print something sensible rather than "Failed to fetch /"
+ if (DestFilename.empty())
+ DestFile = SrcName + ".changelog";
+ else
+ DestFile = DestFilename;
+ Desc.URI = "changelog:/" + DestFile;
+ return;
+ }
+
+ if (DestDir.empty())
+ {
+ std::string const SandboxUser = _config->Find("APT::Sandbox::User");
+ std::string const systemTemp = GetTempDir(SandboxUser);
+ char tmpname[100];
+ snprintf(tmpname, sizeof(tmpname), "%s/apt-changelog-XXXXXX", systemTemp.c_str());
+ if (NULL == mkdtemp(tmpname))
+ {
+ _error->Errno("mkdtemp", "mkdtemp failed in changelog acquire of %s %s", SrcName.c_str(), SrcVersion.c_str());
+ Status = StatError;
+ return;
+ }
+ DestFile = TemporaryDirectory = tmpname;
+
+ ChangeOwnerAndPermissionOfFile("Item::QueueURI", DestFile.c_str(),
+ SandboxUser.c_str(), "root", 0700);
+ }
+ else
+ DestFile = DestDir;
+
+ if (DestFilename.empty())
+ DestFile = flCombine(DestFile, SrcName + ".changelog");
+ else
+ DestFile = flCombine(DestFile, DestFilename);
+
+ Desc.ShortDesc = "Changelog";
+ strprintf(Desc.Description, "%s %s %s Changelog", URI::SiteOnly(Desc.URI).c_str(), SrcName.c_str(), SrcVersion.c_str());
+ Desc.Owner = this;
+ QueueURI(Desc);
+}
+ /*}}}*/
+std::string pkgAcqChangelog::URI(pkgCache::VerIterator const &Ver) /*{{{*/
+{
+ char const * const SrcName = Ver.SourcePkgName();
+ char const * const SrcVersion = Ver.SourceVerStr();
+ pkgCache::PkgFileIterator PkgFile;
+ // find the first source for this version which promises a changelog
+ for (pkgCache::VerFileIterator VF = Ver.FileList(); VF.end() == false; ++VF)
+ {
+ pkgCache::PkgFileIterator const PF = VF.File();
+ if (PF.Flagged(pkgCache::Flag::NotSource) || PF->Release == 0)
+ continue;
+ PkgFile = PF;
+ pkgCache::RlsFileIterator const RF = PF.ReleaseFile();
+ std::string const uri = URI(RF, PF.Component(), SrcName, SrcVersion);
+ if (uri.empty())
+ continue;
+ return uri;
+ }
+ return "";
+}
+std::string pkgAcqChangelog::URITemplate(pkgCache::RlsFileIterator const &Rls)
+{
+ if (Rls.end() == true || (Rls->Label == 0 && Rls->Origin == 0))
+ return "";
+ std::string const serverConfig = "Acquire::Changelogs::URI";
+ std::string server;
+#define APT_EMPTY_SERVER \
+ if (server.empty() == false) \
+ { \
+ if (server != "no") \
+ return server; \
+ return ""; \
+ }
+#define APT_CHECK_SERVER(X, Y) \
+ if (Rls->X != 0) \
+ { \
+ std::string const specialServerConfig = serverConfig + "::" + Y + #X + "::" + Rls.X(); \
+ server = _config->Find(specialServerConfig); \
+ APT_EMPTY_SERVER \
+ }
+ // this way e.g. Debian-Security can fallback to Debian
+ APT_CHECK_SERVER(Label, "Override::")
+ APT_CHECK_SERVER(Origin, "Override::")
+
+ if (RealFileExists(Rls.FileName()))
+ {
+ _error->PushToStack();
+ FileFd rf;
+ /* This can be costly. A caller wanting to get millions of URIs might
+ want to do this on its own once and use Override settings.
+ We don't do this here as Origin/Label are not as unique as they
+ should be so this could produce request order-dependent anomalies */
+ if (OpenMaybeClearSignedFile(Rls.FileName(), rf) == true)
+ {
+ pkgTagFile TagFile(&rf, rf.Size());
+ pkgTagSection Section;
+ if (TagFile.Step(Section) == true)
+ server = Section.FindS("Changelogs");
+ }
+ _error->RevertToStack();
+ APT_EMPTY_SERVER
+ }
+
+ APT_CHECK_SERVER(Label, "")
+ APT_CHECK_SERVER(Origin, "")
+#undef APT_CHECK_SERVER
+#undef APT_EMPTY_SERVER
+ return "";
+}
+std::string pkgAcqChangelog::URI(pkgCache::RlsFileIterator const &Rls,
+ char const * const Component, char const * const SrcName,
+ char const * const SrcVersion)
+{
+ return URI(URITemplate(Rls), Component, SrcName, SrcVersion);
+}
+std::string pkgAcqChangelog::URI(std::string const &Template,
+ char const * const Component, char const * const SrcName,
+ char const * const SrcVersion)
+{
+ if (Template.find("@CHANGEPATH@") == std::string::npos)
+ return "";
+
+ // the path is: COMPONENT/SRC/SRCNAME/SRCNAME_SRCVER, e.g. main/a/apt/1.1 or contrib/liba/libapt/2.0
+ std::string Src = SrcName;
+ std::string path = APT::String::Startswith(SrcName, "lib") ? Src.substr(0, 4) : Src.substr(0,1);
+ path.append("/").append(Src).append("/");
+ path.append(Src).append("_").append(StripEpoch(SrcVersion));
+ // we omit component for releases without one (= flat-style repositories)
+ if (Component != NULL && strlen(Component) != 0)
+ path = std::string(Component) + "/" + path;
+
+ return SubstVar(Template, "@CHANGEPATH@", path);
+}
+ /*}}}*/
+// AcqChangelog::Failed - Failure handler /*{{{*/
+void pkgAcqChangelog::Failed(string const &Message, pkgAcquire::MethodConfig const * const Cnf)
+{
+ Item::Failed(Message,Cnf);
+
+ std::string errText;
+ // TRANSLATOR: %s=%s is sourcename=sourceversion, e.g. apt=1.1
+ strprintf(errText, _("Changelog unavailable for %s=%s"), SrcName.c_str(), SrcVersion.c_str());
+
+ // Error is probably something techy like 404 Not Found
+ if (ErrorText.empty())
+ ErrorText = errText;
+ else
+ ErrorText = errText + " (" + ErrorText + ")";
+ return;
+}
+ /*}}}*/
+// AcqChangelog::Done - Item downloaded OK /*{{{*/
+void pkgAcqChangelog::Done(string const &Message,HashStringList const &CalcHashes,
+ pkgAcquire::MethodConfig const * const Cnf)
+{
+ Item::Done(Message,CalcHashes,Cnf);
+
+ Complete = true;
+}
+ /*}}}*/
+pkgAcqChangelog::~pkgAcqChangelog() /*{{{*/
+{
+ if (TemporaryDirectory.empty() == false)
+ {
+ RemoveFile("~pkgAcqChangelog", DestFile);
+ rmdir(TemporaryDirectory.c_str());
+ }
+}
+ /*}}}*/
// AcqFile::pkgAcqFile - Constructor /*{{{*/
pkgAcqFile::pkgAcqFile(pkgAcquire * const Owner,string const &URI, HashStringList const &Hashes,
unsigned long long const Size,string const &Dsc,string const &ShortDesc,
const string &DestDir, const string &DestFilename,
bool const IsIndexFile) :
- Item(Owner), IsIndexFile(IsIndexFile), ExpectedHashes(Hashes)
+ Item(Owner), d(NULL), IsIndexFile(IsIndexFile), ExpectedHashes(Hashes)
{
Retries = _config->FindI("Acquire::Retries",0);
{
// Hmm, the partial file is too big, erase it
if ((Size > 0) && (unsigned long long)Buf.st_size > Size)
- unlink(DestFile.c_str());
+ RemoveFile("pkgAcqFile", DestFile);
else
PartialSize = Buf.st_size;
}
{
Item::Done(Message,CalcHashes,Cnf);
- string FileName = LookupTag(Message,"Filename");
- if (FileName.empty() == true)
- {
- Status = StatError;
- ErrorText = "Method gave a blank filename";
- return;
- }
-
+ std::string const FileName = LookupTag(Message,"Filename");
Complete = true;
// The files timestamp matches
return;
// We have to copy it into place
- if (FileName != DestFile)
+ if (RealFileExists(DestFile.c_str()) == false)
{
Local = true;
if (_config->FindB("Acquire::Source-Symlinks",true) == false ||
if (lstat(DestFile.c_str(),&St) == 0)
{
if (S_ISLNK(St.st_mode) != 0)
- unlink(DestFile.c_str());
+ RemoveFile("pkgAcqFile::Done", DestFile);
}
// Symlink the file
_error->PushToStack();
_error->Errno("pkgAcqFile::Done", "Symlinking file %s failed", DestFile.c_str());
std::stringstream msg;
- _error->DumpErrors(msg);
+ _error->DumpErrors(msg, GlobalError::DEBUG, false);
_error->RevertToStack();
ErrorText = msg.str();
Status = StatError;
return "";
}
/*}}}*/
+pkgAcqFile::~pkgAcqFile() {}