X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/99359751efb1ad84e877219639030feb47fb28f7..0f3150e7040f45565b459a1390606bc2f714f6a8:/apt-pkg/deb/deblistparser.cc diff --git a/apt-pkg/deb/deblistparser.cc b/apt-pkg/deb/deblistparser.cc index 28857176b..e87e7b5e4 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 /*{{{*/ // --------------------------------------------------------------------- @@ -95,44 +104,50 @@ 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; + if (MultiArch.empty() == true || MultiArch == "no") + 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 + unsigned long const idxSection = UniqFindTagWrite("Section"); + Ver->Section = idxSection; + Ver->MultiArch = ParseMultiArch(true); // Archive Size Ver->Size = Section.FindULL("Size"); // Unpacked Size (in K) @@ -246,7 +261,10 @@ bool debListParser::UsePackage(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) { if (Pkg->Section == 0) - Pkg->Section = UniqFindTagWrite("Section"); + { + unsigned long const idxSection = UniqFindTagWrite("Section"); + Pkg->Section = idxSection; + } string const static myArch = _config->Find("APT::Architecture"); // Possible values are: "all", "native", "installed" and "none" @@ -320,13 +338,9 @@ unsigned short debListParser::VersionHash() /* Status lines are of the form, Status: want flag status want = unknown, install, hold, deinstall, purge - flag = ok, reinstreq, hold, hold-reinstreq - status = not-installed, unpacked, half-configured, - half-installed, config-files, post-inst-failed, - removal-failed, installed - - Some of the above are obsolete (I think?) flag = hold-* and - status = post-inst-failed, removal-failed at least. + flag = ok, reinstreq + status = not-installed, config-files, half-installed, unpacked, + half-configured, triggers-awaited, triggers-pending, installed */ bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg, pkgCache::VerIterator &Ver) @@ -354,7 +368,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 +384,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"); @@ -383,16 +397,14 @@ bool debListParser::ParseStatus(pkgCache::PkgIterator &Pkg, // Process the flag field WordList StatusList[] = {{"not-installed",pkgCache::State::NotInstalled}, + {"config-files",pkgCache::State::ConfigFiles}, + {"half-installed",pkgCache::State::HalfInstalled}, {"unpacked",pkgCache::State::UnPacked}, {"half-configured",pkgCache::State::HalfConfigured}, - {"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}, - {}}; + {"installed",pkgCache::State::Installed}, + {NULL, 0}}; if (GrabWord(string(Start,I-Start),StatusList,Pkg->CurrentState) == false) return _error->Error("Malformed 3rd word in the Status line"); @@ -474,18 +486,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 +627,98 @@ const char *debListParser::ParseDepends(const char *Start,const char *Stop, for (;I != Stop && isspace(*I) != 0; I++); } + if (ParseRestrictionsList == true) + { + // Parse a restrictions formula which is in disjunctive normal form: + // (foo AND bar) OR (blub AND bla) + + std::vector const profiles = APT::Configuration::getBuildProfiles(); + + // if the next character is a restriction list, then by default the + // dependency does not apply and the conditions have to be checked + // if the next character is not a restriction list, then by default the + // dependency applies + bool applies1 = (*I != '<'); + while (I != Stop) + { + if (*I != '<') + break; + + ++I; + // malformed + if (unlikely(I == Stop)) + return 0; + + const char *End = I; + + // if of the prior restriction list is already fulfilled, then + // we can just skip to the end of the current list + if (applies1) { + for (;End != Stop && *End != '>'; ++End); + I = ++End; + // skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + } else { + bool applies2 = true; + // all the conditions inside a restriction list have to be + // met so once we find one that is not met, we can skip to + // the end of this list + while (I != Stop) + { + // look for whitespace or ending '>' + // End now points to the character after the current term + for (;End != Stop && !isspace(*End) && *End != '>'; ++End); + + if (unlikely(End == Stop)) + return 0; + + bool NegRestriction = false; + if (*I == '!') + { + NegRestriction = true; + ++I; + } + + std::string restriction(I, End); + + if (restriction.empty() == false && profiles.empty() == false && + std::find(profiles.begin(), profiles.end(), restriction) != profiles.end()) + { + if (NegRestriction) { + applies2 = false; + // since one of the terms does not apply we don't have to check the others + for (; End != Stop && *End != '>'; ++End); + } + } else { + if (!NegRestriction) { + applies2 = false; + // since one of the terms does not apply we don't have to check the others + for (; End != Stop && *End != '>'; ++End); + } + } + + if (*End++ == '>') { + I = End; + // skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + break; + } + + I = End; + // skip whitespace + for (;I != Stop && isspace(*I) != 0; I++); + } + if (applies2) { + applies1 = true; + } + } + } + + if (applies1 == false) { + Package = ""; //not for this restriction + } + } + if (I != Stop && *I == '|') Op |= pkgCache::Dep::Or; @@ -635,7 +752,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(':'); @@ -653,7 +770,7 @@ bool debListParser::ParseDepends(pkgCache::VerIterator &Ver, if (NewDepends(Ver,Package,"none",Version,Op,Type) == false) return false; } - else if (MultiArchEnabled == true && found != string::npos && + else if (found != string::npos && strcmp(Package.c_str() + found, ":any") != 0) { string Arch = Package.substr(found+1, string::npos); @@ -700,10 +817,16 @@ bool debListParser::ParseProvides(pkgCache::VerIterator &Ver) while (1) { Start = ParseDepends(Start,Stop,Package,Version,Op); + const size_t archfound = Package.rfind(':'); 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()); + if (Op != pkgCache::Dep::NoOp && Op != pkgCache::Dep::Equals) { + _error->Warning("Ignoring Provides line with non-equal DepCompareOp for package %s", Package.c_str()); + } else if (archfound != string::npos) { + string OtherArch = Package.substr(archfound+1, string::npos); + Package = Package.substr(0, archfound); + if (NewProvides(Ver, Package, OtherArch, Version) == false) + return false; } else if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign) { if (NewProvidesAllArch(Ver, Package, Version) == false) return false; @@ -717,9 +840,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 +881,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(); @@ -805,94 +926,28 @@ bool debListParser::LoadReleaseInfo(pkgCache::PkgFileIterator &FileI, map_ptrloc const storage = WriteUniqString(component); FileI->Component = storage; - // FIXME: should use FileFd and TagSection - FILE* release = fdopen(dup(File.Fd()), "r"); - if (release == NULL) + pkgTagFile TagFile(&File, File.Size()); + pkgTagSection Section; + if (_error->PendingError() == true || TagFile.Step(Section) == false) return false; - char buffer[101]; - while (fgets(buffer, sizeof(buffer), release) != NULL) - { - size_t len = 0; - - // Skip empty lines - for (; buffer[len] == '\r' && buffer[len] == '\n'; ++len) - /* nothing */ - ; - if (buffer[len] == '\0') - continue; - - // seperate the tag from the data - const char* dataStart = strchr(buffer + len, ':'); - if (dataStart == NULL) - continue; - len = dataStart - buffer; - for (++dataStart; *dataStart == ' '; ++dataStart) - /* nothing */ - ; - const char* dataEnd = (const char*)rawmemchr(dataStart, '\0'); - // The last char should be a newline, but we can never be sure: #633350 - const char* lineEnd = dataEnd; - for (--lineEnd; *lineEnd == '\r' || *lineEnd == '\n'; --lineEnd) - /* nothing */ - ; - ++lineEnd; - - // which datastorage need to be updated - enum { Suite, Component, Version, Origin, Codename, Label, None } writeTo = None; - if (buffer[0] == ' ') - ; - #define APT_PARSER_WRITETO(X) else if (strncmp(#X, buffer, len) == 0) writeTo = X; - APT_PARSER_WRITETO(Suite) - APT_PARSER_WRITETO(Component) - APT_PARSER_WRITETO(Version) - APT_PARSER_WRITETO(Origin) - APT_PARSER_WRITETO(Codename) - APT_PARSER_WRITETO(Label) - #undef APT_PARSER_WRITETO - #define APT_PARSER_FLAGIT(X) else if (strncmp(#X, buffer, len) == 0) \ - pkgTagSection::FindFlag(FileI->Flags, pkgCache::Flag:: X, dataStart, lineEnd); - APT_PARSER_FLAGIT(NotAutomatic) - APT_PARSER_FLAGIT(ButAutomaticUpgrades) - #undef APT_PARSER_FLAGIT - - // load all data from the line and save it - string data; - if (writeTo != None) - data.append(dataStart, dataEnd); - if (sizeof(buffer) - 1 == (dataEnd - buffer)) - { - while (fgets(buffer, sizeof(buffer), release) != NULL) - { - if (writeTo != None) - data.append(buffer); - if (strlen(buffer) != sizeof(buffer) - 1) - break; - } - } - if (writeTo != None) - { - // remove spaces and stuff from the end of the data line - for (std::string::reverse_iterator s = data.rbegin(); - s != data.rend(); ++s) - { - if (*s != '\r' && *s != '\n' && *s != ' ') - break; - *s = '\0'; - } - map_ptrloc const storage = WriteUniqString(data); - switch (writeTo) { - case Suite: FileI->Archive = storage; break; - case Component: FileI->Component = storage; break; - case Version: FileI->Version = storage; break; - case Origin: FileI->Origin = storage; break; - case Codename: FileI->Codename = storage; break; - case Label: FileI->Label = storage; break; - case None: break; - } - } + std::string data; + #define APT_INRELEASE(TAG, STORE) \ + data = Section.FindS(TAG); \ + if (data.empty() == false) \ + { \ + map_ptrloc const storage = WriteUniqString(data); \ + STORE = storage; \ } - fclose(release); + APT_INRELEASE("Suite", FileI->Archive) + APT_INRELEASE("Component", FileI->Component) + APT_INRELEASE("Version", FileI->Version) + APT_INRELEASE("Origin", FileI->Origin) + APT_INRELEASE("Codename", FileI->Codename) + APT_INRELEASE("Label", FileI->Label) + #undef APT_INRELEASE + Section.FindFlag("NotAutomatic", FileI->Flags, pkgCache::Flag::NotAutomatic); + Section.FindFlag("ButAutomaticUpgrades", FileI->Flags, pkgCache::Flag::ButAutomaticUpgrades); return !_error->PendingError(); } @@ -909,3 +964,24 @@ 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