X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/e9737c7f6a3e03b2975927ef9b04c1194026ed9c..e5fefea6ec93746376bf42733ee84a9fafeab764:/apt-pkg/deb/deblistparser.cc diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index c2707d0a5..192a281db 100644 --- a/apt-pkg/deb/deblistparser.cc +++ b/apt-pkg/deb/deblistparser.cc @@ -21,8 +21,17 @@ #include #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include +#include #include /*}}}*/ @@ -34,7 +43,7 @@ static debListParser::WordList PrioList[] = { {"standard",pkgCache::State::Standard}, {"optional",pkgCache::State::Optional}, {"extra",pkgCache::State::Extra}, - {}}; + {NULL, 0}}; // ListParser::debListParser - Constructor /*{{{*/ // --------------------------------------------------------------------- @@ -52,7 +61,7 @@ debListParser::debListParser(FileFd *File, string const &Arch) : Tags(File), // ListParser::UniqFindTagWrite - Find the tag and write a unq string /*{{{*/ // --------------------------------------------------------------------- /* */ -unsigned long debListParser::UniqFindTagWrite(const char *Tag) +map_stringitem_t debListParser::UniqFindTagWrite(const char *Tag) { const char *Start; const char *Stop; @@ -95,44 +104,49 @@ string debListParser::Version() return Section.FindS("Version"); } /*}}}*/ -// ListParser::NewVersion - Fill in the version structure /*{{{*/ -// --------------------------------------------------------------------- -/* */ -bool debListParser::NewVersion(pkgCache::VerIterator &Ver) +unsigned char debListParser::ParseMultiArch(bool const showErrors) /*{{{*/ { - // Parse the section - Ver->Section = UniqFindTagWrite("Section"); - - // Parse multi-arch + unsigned char MA; string const MultiArch = Section.FindS("Multi-Arch"); if (MultiArch.empty() == true) - Ver->MultiArch = pkgCache::Version::None; + MA = pkgCache::Version::None; else if (MultiArch == "same") { - // Parse multi-arch if (ArchitectureAll() == true) { - /* Arch all packages can't be Multi-Arch: same */ - _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same", - Section.FindS("Package").c_str()); - Ver->MultiArch = pkgCache::Version::None; + if (showErrors == true) + _error->Warning("Architecture: all package '%s' can't be Multi-Arch: same", + Section.FindS("Package").c_str()); + MA = pkgCache::Version::None; } else - Ver->MultiArch = pkgCache::Version::Same; + MA = pkgCache::Version::Same; } else if (MultiArch == "foreign") - Ver->MultiArch = pkgCache::Version::Foreign; + MA = pkgCache::Version::Foreign; else if (MultiArch == "allowed") - Ver->MultiArch = pkgCache::Version::Allowed; + MA = 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; + if (showErrors == true) + _error->Warning("Unknown Multi-Arch type '%s' for package '%s'", + MultiArch.c_str(), Section.FindS("Package").c_str()); + MA = pkgCache::Version::None; } if (ArchitectureAll() == true) - Ver->MultiArch |= pkgCache::Version::All; + MA |= pkgCache::Version::All; + return MA; +} + /*}}}*/ +// ListParser::NewVersion - Fill in the version structure /*{{{*/ +// --------------------------------------------------------------------- +/* */ +bool debListParser::NewVersion(pkgCache::VerIterator &Ver) +{ + // Parse the section + Ver->Section = UniqFindTagWrite("Section"); + Ver->MultiArch = ParseMultiArch(true); // Archive Size Ver->Size = Section.FindULL("Size"); // Unpacked Size (in K) @@ -180,35 +194,31 @@ bool debListParser::NewVersion(pkgCache::VerIterator &Ver) /* 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 debListParser::Description(std::string const &lang) { - 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() + /*}}}*/ +// ListParser::AvailableDescriptionLanguages /*{{{*/ +std::vector debListParser::AvailableDescriptionLanguages() { - if (Section.FindS("Description").empty() == false) - return ""; - - std::vector const lang = APT::Configuration::getLanguages(true); - for (std::vector::const_iterator l = lang.begin(); - l != lang.end(); ++l) - if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false) - return *l; - - return ""; + std::vector const understood = APT::Configuration::getLanguages(); + std::vector avail; + if (Section.Exists("Description") == true) + avail.push_back(""); + for (std::vector::const_iterator lang = understood.begin(); lang != understood.end(); ++lang) + { + std::string const tagname = "Description-" + *lang; + if (Section.Exists(tagname.c_str()) == true) + avail.push_back(*lang); + } + return avail; } - /*}}}*/ -// ListParser::Description - Return the description_md5 MD5SumValue /*{{{*/ + /*}}}*/ +// ListParser::Description_md5 - 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 @@ -219,7 +229,7 @@ MD5SumValue debListParser::Description_md5() string const value = Section.FindS("Description-md5"); if (value.empty() == true) { - std::string const desc = Description() + "\n"; + std::string const desc = Description("") + "\n"; if (desc == "\n") return MD5SumValue(); @@ -245,9 +255,6 @@ MD5SumValue debListParser::Description_md5() bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) { - if (Pkg->Section == 0) - Pkg->Section = UniqFindTagWrite("Section"); - string const static myArch = _config->Find("APT::Architecture"); // Possible values are: "all", "native", "installed" and "none" // The "installed" mode is handled by ParseStatus(), See #544481 and friends. @@ -354,7 +361,7 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg, {"hold",pkgCache::State::Hold}, {"deinstall",pkgCache::State::DeInstall}, {"purge",pkgCache::State::Purge}, - {}}; + {NULL, 0}}; if (GrabWord(string(Start,I-Start),WantList,Pkg->SelectedState) == false) return _error->Error("Malformed 1st word in the Status line"); @@ -370,7 +377,7 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg, {"reinstreq",pkgCache::State::ReInstReq}, {"hold",pkgCache::State::HoldInst}, {"hold-reinstreq",pkgCache::State::HoldReInstReq}, - {}}; + {NULL, 0}}; if (GrabWord(string(Start,I-Start),FlagList,Pkg->InstState) == false) return _error->Error("Malformed 2nd word in the Status line"); @@ -392,7 +399,7 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg, {"triggers-pending",pkgCache::State::TriggersPending}, {"post-inst-failed",pkgCache::State::HalfConfigured}, {"removal-failed",pkgCache::State::HalfInstalled}, - {}}; + {NULL, 0}}; if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false) return _error->Error("Malformed 3rd word in the Status line"); @@ -474,18 +481,31 @@ const char *debListParser::ConvertRelation(const char *I,unsigned int &Op) // --------------------------------------------------------------------- /* This parses the dependency elements out of a standard string in place, bit by bit. */ +const char *debListParser::ParseDepends(const char *Start,const char *Stop, + std::string &Package,std::string &Ver,unsigned int &Op) + { return ParseDepends(Start, Stop, Package, Ver, Op, false, true, false); } +const char *debListParser::ParseDepends(const char *Start,const char *Stop, + std::string &Package,std::string &Ver,unsigned int &Op, + bool const &ParseArchFlags) + { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, true, false); } +const char *debListParser::ParseDepends(const char *Start,const char *Stop, + std::string &Package,std::string &Ver,unsigned int &Op, + bool const &ParseArchFlags, bool const &StripMultiArch) + { return ParseDepends(Start, Stop, Package, Ver, Op, ParseArchFlags, StripMultiArch, false); } const char *debListParser::ParseDepends(const char *Start,const char *Stop, string &Package,string &Ver, unsigned int &Op, bool const &ParseArchFlags, - bool const &StripMultiArch) + bool const &StripMultiArch, + bool const &ParseRestrictionsList) { // Strip off leading space - for (;Start != Stop && isspace(*Start) != 0; Start++); + for (;Start != Stop && isspace(*Start) != 0; ++Start); // Parse off the package name const char *I = Start; for (;I != Stop && isspace(*I) == 0 && *I != '(' && *I != ')' && - *I != ',' && *I != '|' && *I != '[' && *I != ']'; I++); + *I != ',' && *I != '|' && *I != '[' && *I != ']' && + *I != '<' && *I != '>'; ++I); // Malformed, no '(' if (I != Stop && *I == ')') @@ -602,6 +622,76 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop, for (;I != Stop && isspace(*I) != 0; I++); } + if (ParseRestrictionsList == true) + { + // Parse a restrictions list + if (I != Stop && *I == '<') + { + ++I; + // malformed + if (unlikely(I == Stop)) + return 0; + + std::vector const profiles = APT::Configuration::getBuildProfiles(); + + const char *End = I; + bool Found = false; + bool NegRestriction = false; + while (I != Stop) + { + // look for whitespace or ending '>' + for (;End != Stop && !isspace(*End) && *End != '>'; ++End); + + if (unlikely(End == Stop)) + return 0; + + if (*I == '!') + { + NegRestriction = true; + ++I; + } + + std::string restriction(I, End); + + std::string prefix = "profile."; + // only support for "profile" prefix, ignore others + if (restriction.size() > prefix.size() && + restriction.substr(0, prefix.size()) == prefix) + { + // get the name of the profile + restriction = restriction.substr(prefix.size()); + + if (restriction.empty() == false && profiles.empty() == false && + std::find(profiles.begin(), profiles.end(), restriction) != profiles.end()) + { + Found = true; + if (I[-1] != '!') + NegRestriction = false; + // we found a match, so fast-forward to the end of the wildcards + for (; End != Stop && *End != '>'; ++End); + } + } + + if (*End++ == '>') { + I = End; + break; + } + + I = End; + for (;I != Stop && isspace(*I) != 0; I++); + } + + if (NegRestriction == true) + Found = !Found; + + if (Found == false) + Package = ""; /* not for this restriction */ + } + + // Skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + } + if (I != Stop && *I == '|') Op |= pkgCache::Dep::Or; @@ -635,7 +725,7 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver, string Version; unsigned int Op; - Start = ParseDepends(Start,Stop,Package,Version,Op,false,!MultiArchEnabled); + Start = ParseDepends(Start, Stop, Package, Version, Op, false, false, false); if (Start == 0) return _error->Error("Problem parsing dependency %s",Tag); size_t const found = Package.rfind(':'); @@ -717,9 +807,7 @@ bool debListParser::ParseProvides(pkgCache::VerIterator &Ver) } } - if (MultiArchEnabled == false) - return true; - else if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed) + if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed) { string const Package = string(Ver.ParentPkg().Name()).append(":").append("any"); return NewProvidesAllArch(Ver, Package, Ver.VerStr()); @@ -760,7 +848,7 @@ bool debListParser::GrabWord(string Word,WordList *List,unsigned char &Out) /*}}}*/ // ListParser::Step - Move to the next section in the file /*{{{*/ // --------------------------------------------------------------------- -/* This has to be carefull to only process the correct architecture */ +/* This has to be careful to only process the correct architecture */ bool debListParser::Step() { iOffset = Tags.Offset(); @@ -802,10 +890,10 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI, { // apt-secure does no longer download individual (per-section) Release // file. to provide Component pinning we use the section name now - map_ptrloc const storage = WriteUniqString(component); + map_stringitem_t const storage = WriteUniqString(component); FileI->Component = storage; - pkgTagFile TagFile(&File); + pkgTagFile TagFile(&File, File.Size()); pkgTagSection Section; if (_error->PendingError() == true || TagFile.Step(Section) == false) return false; @@ -815,7 +903,7 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI, data = Section.FindS(TAG); \ if (data.empty() == false) \ { \ - map_ptrloc const storage = WriteUniqString(data); \ + map_stringitem_t const storage = WriteUniqString(data); \ STORE = storage; \ } APT_INRELEASE("Suite", FileI->Archive) @@ -843,3 +931,44 @@ unsigned char debListParser::GetPrio(string Str) return Out; } /*}}}*/ +#if (APT_PKG_MAJOR >= 4 && APT_PKG_MINOR >= 13) +bool debListParser::SameVersion(unsigned short const Hash, /*{{{*/ + pkgCache::VerIterator const &Ver) +{ + if (pkgCacheGenerator::ListParser::SameVersion(Hash, Ver) == false) + return false; + // status file has no (Download)Size, but all others are fair game + // status file is parsed last, so the first version we encounter is + // probably also the version we have downloaded + unsigned long long const Size = Section.FindULL("Size"); + if (Size != 0 && Size != Ver->Size) + return false; + // available everywhere, but easier to check here than to include in VersionHash + unsigned char MultiArch = ParseMultiArch(false); + if (MultiArch != Ver->MultiArch) + return false; + // for all practical proposes (we can check): same version + return true; +} + /*}}}*/ +#endif + + +debDebFileParser::debDebFileParser(FileFd *File, std::string const &DebFile) + : debListParser(File, ""), DebFile(DebFile) +{ +} + +bool debDebFileParser::UsePackage(pkgCache::PkgIterator &Pkg, + pkgCache::VerIterator &Ver) +{ + bool res = debListParser::UsePackage(Pkg, Ver); + // we use the full file path as a provides so that the file is found + // by its name + if(NewProvidesAllArch(Ver, DebFile, Ver.VerStr()) == false) + return false; + return res; +} + + +