#include <apt-pkg/deblistparser.h>
#include <apt-pkg/error.h>
#include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
#include <apt-pkg/strutl.h>
#include <apt-pkg/crc-16.h>
+#include <apt-pkg/md5.h>
+#include <apt-pkg/macros.h>
#include <ctype.h>
-
-#include <system.h>
/*}}}*/
static debListParser::WordList PrioList[] = {{"important",pkgCache::State::Important},
// ListParser::debListParser - Constructor /*{{{*/
// ---------------------------------------------------------------------
-/* */
-debListParser::debListParser(FileFd *File) : Tags(File)
-{
- Arch = _config->Find("APT::architecture");
+/* Provide an architecture and only this one and "all" will be accepted
+ in Step(), if no Architecture is given we will accept every arch
+ we would accept in general with checkArchitecture() */
+debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File),
+ Arch(Arch) {
+ if (Arch == "native")
+ this->Arch = _config->Find("APT::Architecture");
}
/*}}}*/
// ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/
// ListParser::Package - Return the package name /*{{{*/
// ---------------------------------------------------------------------
/* This is to return the name of the package this section describes */
-string debListParser::Package()
-{
- string Result = Section.FindS("Package");
- if (Result.empty() == true)
- _error->Error("Encountered a section with no Package: header");
- return Result;
+string debListParser::Package() {
+ string const Result = Section.FindS("Package");
+ if(unlikely(Result.empty() == true))
+ _error->Error("Encountered a section with no Package: header");
+ return Result;
+}
+ /*}}}*/
+// ListParser::Architecture - Return the package arch /*{{{*/
+// ---------------------------------------------------------------------
+/* This will return the Architecture of the package this section describes
+ Note that architecture "all" packages will get the architecture of the
+ Packages file parsed here. */
+string debListParser::Architecture() {
+ string const Result = Section.FindS("Architecture");
+ if (Result.empty() == true || Result == "all") {
+ if (Arch.empty() == true)
+ /* FIXME: this is a problem for installed arch all
+ packages as we don't know from which arch this
+ package was installed - and therefore which
+ dependency this package resolves. */
+ return _config->Find("APT::Architecture");
+ else
+ return Arch;
+ }
+ return Result;
+}
+ /*}}}*/
+// ListParser::ArchitectureAll /*{{{*/
+// ---------------------------------------------------------------------
+/* */
+bool debListParser::ArchitectureAll() {
+ return Section.FindS("Architecture") == "all";
}
/*}}}*/
// ListParser::Version - Return the version string /*{{{*/
{
// Parse the section
Ver->Section = UniqFindTagWrite("Section");
- Ver->Arch = UniqFindTagWrite("Architecture");
-
+
+ // Parse multi-arch
+ if (Section.FindS("Architecture") == "all")
+ /* Arch all packages can't have a Multi-Arch field,
+ but we need a special treatment for them nonetheless */
+ Ver->MultiArch = pkgCache::Version::All;
+ else
+ {
+ string const MultiArch = Section.FindS("Multi-Arch");
+ if (MultiArch.empty() == true)
+ Ver->MultiArch = pkgCache::Version::None;
+ else if (MultiArch == "same")
+ Ver->MultiArch = pkgCache::Version::Same;
+ else if (MultiArch == "foreign")
+ Ver->MultiArch = pkgCache::Version::Foreign;
+ else if (MultiArch == "allowed")
+ Ver->MultiArch = pkgCache::Version::Allowed;
+ else
+ {
+ _error->Warning("Unknown Multi-Arch type »%s« for package »%s«",
+ MultiArch.c_str(), Section.FindS("Package").c_str());
+ Ver->MultiArch = pkgCache::Version::None;
+ }
+ }
+
// Archive Size
Ver->Size = (unsigned)Section.FindI("Size");
Ver->Priority = pkgCache::State::Extra;
}
+ if (Ver->MultiArch == pkgCache::Version::All)
+ {
+ /* We maintain a "pseudo" arch=all package for architecture all versions
+ on which these versions can depend on. This pseudo package is many used
+ for downloading/installing: The other pseudo-packages will degenerate
+ to a NOP in the download/install step - this package will ensure that
+ it is downloaded only one time and installed only one time -- even if
+ the architecture bound versions coming in and out on regular basis. */
+ bool const static multiArch = APT::Configuration::getArchitectures().size() > 1;
+ if (strcmp(Ver.Arch(true),"all") == 0)
+ return true;
+ else if (multiArch == true)
+ {
+ // our pseudo packages have no size to not confuse the fetcher
+ Ver->Size = 0;
+ Ver->InstalledSize = 0;
+ }
+ }
+
if (ParseDepends(Ver,"Depends",pkgCache::Dep::Depends) == false)
return false;
if (ParseDepends(Ver,"Pre-Depends",pkgCache::Dep::PreDepends) == false)
return false;
if (ParseDepends(Ver,"Conflicts",pkgCache::Dep::Conflicts) == false)
return false;
+ if (ParseDepends(Ver,"Breaks",pkgCache::Dep::DpkgBreaks) == false)
+ return false;
if (ParseDepends(Ver,"Replaces",pkgCache::Dep::Replaces) == false)
return false;
+ if (ParseDepends(Ver,"Enhances",pkgCache::Dep::Enhances) == false)
+ return false;
// Obsolete.
if (ParseDepends(Ver,"Optional",pkgCache::Dep::Suggests) == false)
return true;
}
/*}}}*/
+// ListParser::Description - Return the description string /*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the string describing the package in debian
+ form. If this returns the blank string then the entry is assumed to
+ only describe package properties */
+string debListParser::Description()
+{
+ string const lang = DescriptionLanguage();
+ if (lang.empty())
+ return Section.FindS("Description");
+ else
+ return Section.FindS(string("Description-").append(lang).c_str());
+}
+ /*}}}*/
+// ListParser::DescriptionLanguage - Return the description lang string /*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the string describing the language of
+ description. If this returns the blank string then the entry is
+ assumed to describe original description. */
+string debListParser::DescriptionLanguage()
+{
+ if (Section.FindS("Description").empty() == false)
+ return "";
+
+ std::vector<string> const lang = APT::Configuration::getLanguages();
+ for (std::vector<string>::const_iterator l = lang.begin();
+ l != lang.end(); l++)
+ if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false)
+ return *l;
+
+ return "";
+}
+ /*}}}*/
+// ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/
+// ---------------------------------------------------------------------
+/* This is to return the md5 string to allow the check if it is the right
+ description. If no Description-md5 is found in the section it will be
+ calculated.
+ */
+MD5SumValue debListParser::Description_md5()
+{
+ string value = Section.FindS("Description-md5");
+
+ if (value.empty())
+ {
+ MD5Summation md5;
+ md5.Add((Description() + "\n").c_str());
+ return md5.Result();
+ } else
+ return MD5SumValue(value);
+}
+ /*}}}*/
// ListParser::UsePackage - Update a package structure /*{{{*/
// ---------------------------------------------------------------------
/* This is called to update the package with any new information
{
if (Pkg->Section == 0)
Pkg->Section = UniqFindTagWrite("Section");
- if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
- return false;
+
+ // Packages which are not from "our" arch doesn't get the essential flag
+ string const static myArch = _config->Find("APT::Architecture");
+ if (Pkg->Arch != 0 && myArch == Pkg.Arch())
+ if (Section.FindFlag("Essential",Pkg->Flags,pkgCache::Flag::Essential) == false)
+ return false;
if (Section.FindFlag("Important",Pkg->Flags,pkgCache::Flag::Important) == false)
return false;
// "Suggests",
// "Recommends",
"Conflicts",
+ "Breaks",
"Replaces",0};
unsigned long Result = INIT_FCS;
char S[1024];
for (; Start != End; Start++)
{
if (isspace(*Start) == 0)
- *I++ = tolower(*Start);
+ *I++ = tolower_ascii(*Start);
if (*Start == '<' && Start[1] != '<' && Start[1] != '=')
*I++ = '=';
if (*Start == '>' && Start[1] != '>' && Start[1] != '=')
{"installed",pkgCache::State::Installed},
{"half-installed",pkgCache::State::HalfInstalled},
{"config-files",pkgCache::State::ConfigFiles},
+ {"triggers-awaited",pkgCache::State::TriggersAwaited},
+ {"triggers-pending",pkgCache::State::TriggersPending},
{"post-inst-failed",pkgCache::State::HalfConfigured},
{"removal-failed",pkgCache::State::HalfInstalled},
{}};
bit by bit. */
const char *debListParser::ParseDepends(const char *Start,const char *Stop,
string &Package,string &Ver,
- unsigned int &Op, bool ParseArchFlags)
+ unsigned int &Op, bool const &ParseArchFlags,
+ bool const &StripMultiArch)
{
// Strip off leading space
for (;Start != Stop && isspace(*Start) != 0; Start++);
// Stash the package name
Package.assign(Start,I - Start);
-
+
+ // We don't want to confuse library users which can't handle MultiArch
+ if (StripMultiArch == true) {
+ size_t const found = Package.rfind(':');
+ if (found != string::npos)
+ Package = Package.substr(0,found);
+ }
+
// Skip white space to the '('
for (;I != Stop && isspace(*I) != 0 ; I++);
return true;
string Package;
+ string const pkgArch = Ver.Arch(true);
string Version;
unsigned int Op;
if (Start == 0)
return _error->Error("Problem parsing dependency %s",Tag);
- if (NewDepends(Ver,Package,Version,Op,Type) == false)
+ if (NewDepends(Ver,Package,pkgArch,Version,Op,Type) == false)
return false;
if (Start == Stop)
break;
{
const char *Start;
const char *Stop;
- if (Section.Find("Provides",Start,Stop) == false)
- return true;
-
- string Package;
- string Version;
- unsigned int Op;
-
- while (1)
+ if (Section.Find("Provides",Start,Stop) == true)
{
- Start = ParseDepends(Start,Stop,Package,Version,Op);
- if (Start == 0)
- return _error->Error("Problem parsing Provides line");
- if (Op != pkgCache::Dep::NoOp) {
- _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
- } else {
- if (NewProvides(Ver,Package,Version) == false)
- return false;
+ string Package;
+ string Version;
+ string const Arch = Ver.Arch(true);
+ unsigned int Op;
+
+ while (1)
+ {
+ Start = ParseDepends(Start,Stop,Package,Version,Op);
+ if (Start == 0)
+ return _error->Error("Problem parsing Provides line");
+ if (Op != pkgCache::Dep::NoOp) {
+ _error->Warning("Ignoring Provides line with DepCompareOp for package %s", Package.c_str());
+ } else {
+ if (NewProvides(Ver, Package, Arch, Version) == false)
+ return false;
+ }
+
+ if (Start == Stop)
+ break;
}
+ }
- if (Start == Stop)
- break;
+ if (Ver->MultiArch == pkgCache::Version::Allowed)
+ {
+ string const Package = string(Ver.ParentPkg().Name()).append(":").append("any");
+ NewProvides(Ver, Package, "any", Ver.VerStr());
}
-
+
+ if (Ver->MultiArch != pkgCache::Version::Foreign)
+ return true;
+
+ std::vector<string> const archs = APT::Configuration::getArchitectures();
+ if (archs.size() <= 1)
+ return true;
+
+ string const Package = Ver.ParentPkg().Name();
+ string const Version = Ver.VerStr();
+ for (std::vector<string>::const_iterator a = archs.begin();
+ a != archs.end(); ++a)
+ {
+ if (NewProvides(Ver, Package, *a, Version) == false)
+ return false;
+ }
+
return true;
}
/*}}}*/
/* See if this is the correct Architecture, if it isn't then we
drop the whole section. A missing arch tag only happens (in theory)
inside the Status file, so that is a positive return */
- const char *Start;
- const char *Stop;
- if (Section.Find("Architecture",Start,Stop) == false)
+ string const Architecture = Section.FindS("Architecture");
+ if (Architecture.empty() == true)
return true;
- if (stringcmp(Arch,Start,Stop) == 0)
- return true;
+ if (Arch.empty() == true)
+ {
+ if (APT::Configuration::checkArchitecture(Architecture) == true)
+ return true;
+ }
+ else
+ {
+ if (Architecture == Arch)
+ return true;
- if (stringcmp(Start,Stop,"all") == 0)
- return true;
+ if (Architecture == "all")
+ return true;
+ }
iOffset = Tags.Offset();
}
if (Tags.Step(Section) == false)
return false;
- //mvo: I don't think we need to fill that in (it's unused since apt-0.6)
- //FileI->Architecture = WriteUniqString(Arch);
+ // FIXME: Do we need it now for multi-arch?
+ // mvo: I don't think we need to fill that in (it's unused since apt-0.6)
+// FileI->Architecture = WriteUniqString(Arch);
// apt-secure does no longer download individual (per-section) Release
// file. to provide Component pinning we use the section name now
FileI->Version = WriteUniqString(Start,Stop - Start);
if (Section.Find("Origin",Start,Stop) == true)
FileI->Origin = WriteUniqString(Start,Stop - Start);
+ if (Section.Find("Codename",Start,Stop) == true)
+ FileI->Codename = WriteUniqString(Start,Stop - Start);
if (Section.Find("Label",Start,Stop) == true)
FileI->Label = WriteUniqString(Start,Stop - Start);
if (Section.Find("Architecture",Start,Stop) == true)