X-Git-Url: https://git.saurik.com/apt.git/blobdiff_plain/32b9a14cb4c6bdcddfe84c4451c225ced1a34bb7..c307a4f0aa29c9c52a0e028524d21b448a53d09b:/apt-pkg/pkgcachegen.cc diff --git a/apt-pkg/pkgcachegen.cc b/apt-pkg/pkgcachegen.cc index 62e457734..ec072fddd 100644 --- a/apt-pkg/pkgcachegen.cc +++ b/apt-pkg/pkgcachegen.cc @@ -10,7 +10,7 @@ ##################################################################### */ /*}}}*/ // Include Files /*{{{*/ -#define APT_COMPATIBILITY 986 +#include #include #include @@ -23,19 +23,25 @@ #include #include #include - #include - -#include +#include +#include #include - #include #include #include #include + +#include /*}}}*/ -typedef vector::iterator FileIterator; +typedef std::vector::iterator FileIterator; +template std::vector pkgCacheGenerator::Dynamic::toReMap; + +bool IsDuplicateDescription(pkgCache::DescIterator Desc, + MD5SumValue const &CurMd5, std::string const &CurLang); + +using std::string; // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/ // --------------------------------------------------------------------- @@ -61,8 +67,12 @@ pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) : // Starting header *Cache.HeaderP = pkgCache::Header(); - Cache.HeaderP->VerSysName = WriteStringInMap(_system->VS->Label); - Cache.HeaderP->Architecture = WriteStringInMap(_config->Find("APT::Architecture")); + map_ptrloc const idxVerSysName = WriteStringInMap(_system->VS->Label); + Cache.HeaderP->VerSysName = idxVerSysName; + map_ptrloc const idxArchitecture = WriteStringInMap(_config->Find("APT::Architecture")); + Cache.HeaderP->Architecture = idxArchitecture; + if (unlikely(idxVerSysName == 0 || idxArchitecture == 0)) + return; Cache.ReMap(); } else @@ -93,22 +103,72 @@ pkgCacheGenerator::~pkgCacheGenerator() return; Cache.HeaderP->Dirty = false; + Cache.HeaderP->CacheFileSize = Map.Size(); Map.Sync(0,sizeof(pkgCache::Header)); } /*}}}*/ +void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newMap) {/*{{{*/ + if (oldMap == newMap) + return; + + if (_config->FindB("Debug::pkgCacheGen", false)) + std::clog << "Remaping from " << oldMap << " to " << newMap << std::endl; + + Cache.ReMap(false); + + CurrentFile += (pkgCache::PackageFile*) newMap - (pkgCache::PackageFile*) oldMap; + + for (size_t i = 0; i < _count(UniqHash); ++i) + if (UniqHash[i] != 0) + UniqHash[i] += (pkgCache::StringItem*) newMap - (pkgCache::StringItem*) oldMap; + + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); + for (std::vector::const_iterator i = Dynamic::toReMap.begin(); + i != Dynamic::toReMap.end(); ++i) + (*i)->ReMap(oldMap, newMap); +} /*}}}*/ // CacheGenerator::WriteStringInMap /*{{{*/ -unsigned long pkgCacheGenerator::WriteStringInMap(const char *String, +map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String, const unsigned long &Len) { - return Map.WriteString(String, Len); + void const * const oldMap = Map.Data(); + map_ptrloc const index = Map.WriteString(String, Len); + if (index != 0) + ReMap(oldMap, Map.Data()); + return index; } /*}}}*/ // CacheGenerator::WriteStringInMap /*{{{*/ -unsigned long pkgCacheGenerator::WriteStringInMap(const char *String) { - return Map.WriteString(String); +map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String) { + void const * const oldMap = Map.Data(); + map_ptrloc const index = Map.WriteString(String); + if (index != 0) + ReMap(oldMap, Map.Data()); + return index; } /*}}}*/ -unsigned long pkgCacheGenerator::AllocateInMap(const unsigned long &size) {/*{{{*/ - return Map.Allocate(size); +map_ptrloc pkgCacheGenerator::AllocateInMap(const unsigned long &size) {/*{{{*/ + void const * const oldMap = Map.Data(); + map_ptrloc const index = Map.Allocate(size); + if (index != 0) + ReMap(oldMap, Map.Data()); + return index; } /*}}}*/ // CacheGenerator::MergeList - Merge the package list /*{{{*/ @@ -127,85 +187,154 @@ bool pkgCacheGenerator::MergeList(ListParser &List, if (PackageName.empty() == true) return false; - /* As we handle Arch all packages as architecture bounded - we add all information to every (simulated) arch package */ - std::vector genArch; - if (List.ArchitectureAll() == true) { - genArch = APT::Configuration::getArchitectures(); - if (genArch.size() != 1) - genArch.push_back("all"); - } else - genArch.push_back(List.Architecture()); - - for (std::vector::const_iterator arch = genArch.begin(); - arch != genArch.end(); ++arch) - { - // Get a pointer to the package structure - pkgCache::PkgIterator Pkg; - if (NewPackage(Pkg, PackageName, *arch) == false) - return _error->Error(_("Error occurred while processing %s (NewPackage)"),PackageName.c_str()); Counter++; if (Counter % 100 == 0 && Progress != 0) Progress->Progress(List.Offset()); - /* Get a pointer to the version structure. We know the list is sorted - so we use that fact in the search. Insertion of new versions is - done with correct sorting */ - string Version = List.Version(); + string Arch = List.Architecture(); + string const Version = List.Version(); + if (Version.empty() == true && Arch.empty() == true) + { + if (MergeListGroup(List, PackageName) == false) + return false; + } + + if (Arch.empty() == true) + Arch = _config->Find("APT::Architecture"); + + // Get a pointer to the package structure + pkgCache::PkgIterator Pkg; + Dynamic DynPkg(Pkg); + if (NewPackage(Pkg, PackageName, Arch) == false) + // TRANSLATOR: The first placeholder is a package name, + // the other two should be copied verbatim as they include debug info + return _error->Error(_("Error occurred while processing %s (%s%d)"), + PackageName.c_str(), "NewPackage", 1); + + if (Version.empty() == true) { - // we first process the package, then the descriptions - // (this has the bonus that we get MMap error when we run out - // of MMap space) - pkgCache::VerIterator Ver(Cache); - if (List.UsePackage(Pkg, Ver) == false) - return _error->Error(_("Error occurred while processing %s (UsePackage1)"), - PackageName.c_str()); - - // Find the right version to write the description - MD5SumValue CurMd5 = List.Description_md5(); - Ver = Pkg.VersionList(); - map_ptrloc *LastVer = &Pkg->VersionList; - - for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++) - { - pkgCache::DescIterator Desc = Ver.DescriptionList(); - map_ptrloc *LastDesc = &Ver->DescriptionList; - bool duplicate=false; - - // don't add a new description if we have one for the given - // md5 && language - for ( ; Desc.end() == false; Desc++) - if (MD5SumValue(Desc.md5()) == CurMd5 && - Desc.LanguageCode() == List.DescriptionLanguage()) - duplicate=true; - if(duplicate) - continue; - - for (Desc = Ver.DescriptionList(); - Desc.end() == false; - LastDesc = &Desc->NextDesc, Desc++) - { - if (MD5SumValue(Desc.md5()) == CurMd5) - { - // Add new description - *LastDesc = NewDescription(Desc, List.DescriptionLanguage(), CurMd5, *LastDesc); - Desc->ParentPkg = Pkg.Index(); - - if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false) - return _error->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName.c_str()); - break; - } - } - } + if (MergeListPackage(List, Pkg) == false) + return false; + } + else + { + if (MergeListVersion(List, Pkg, Version, OutVer) == false) + return false; + } - continue; + if (OutVer != 0) + { + FoundFileDeps |= List.HasFileDeps(); + return true; } + } - pkgCache::VerIterator Ver = Pkg.VersionList(); - map_ptrloc *LastVer = &Pkg->VersionList; + if (Cache.HeaderP->PackageCount >= (1ULL<ID)*8)-1) + return _error->Error(_("Wow, you exceeded the number of package " + "names this APT is capable of.")); + if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1) + return _error->Error(_("Wow, you exceeded the number of versions " + "this APT is capable of.")); + if (Cache.HeaderP->DescriptionCount >= (1ULL<<(sizeof(Cache.DescP->ID)*8))-1) + return _error->Error(_("Wow, you exceeded the number of descriptions " + "this APT is capable of.")); + if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL) + return _error->Error(_("Wow, you exceeded the number of dependencies " + "this APT is capable of.")); + + FoundFileDeps |= List.HasFileDeps(); + return true; +} +// CacheGenerator::MergeListGroup /*{{{*/ +bool pkgCacheGenerator::MergeListGroup(ListParser &List, std::string const &GrpName) +{ + pkgCache::GrpIterator Grp = Cache.FindGrp(GrpName); + // a group has no data on it's own, only packages have it but these + // stanzas like this come from Translation- files to add descriptions, + // but without a version we don't need a description for it… + if (Grp.end() == true) + return true; + Dynamic DynGrp(Grp); + + pkgCache::PkgIterator Pkg; + Dynamic DynPkg(Pkg); + for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg)) + if (MergeListPackage(List, Pkg) == false) + return false; + + return true; +} + /*}}}*/ +// CacheGenerator::MergeListPackage /*{{{*/ +bool pkgCacheGenerator::MergeListPackage(ListParser &List, pkgCache::PkgIterator &Pkg) +{ + // we first process the package, then the descriptions + // (for deb this package processing is in fact a no-op) + pkgCache::VerIterator Ver(Cache); + Dynamic DynVer(Ver); + if (List.UsePackage(Pkg, Ver) == false) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "UsePackage", 1); + + // Find the right version to write the description + MD5SumValue CurMd5 = List.Description_md5(); + std::string CurLang = List.DescriptionLanguage(); + + for (Ver = Pkg.VersionList(); Ver.end() == false; ++Ver) + { + pkgCache::DescIterator Desc = Ver.DescriptionList(); + + // a version can only have one md5 describing it + if (MD5SumValue(Desc.md5()) != CurMd5) + continue; + + // don't add a new description if we have one for the given + // md5 && language + if (IsDuplicateDescription(Desc, CurMd5, CurLang) == true) + continue; + + Dynamic DynDesc(Desc); + // we add at the end, so that the start is constant as we need + // that to be able to efficiently share these lists + map_ptrloc *LastDesc = &Ver->DescriptionList; + for (;Desc.end() == false && Desc->NextDesc != 0; ++Desc); + if (Desc.end() == false) + LastDesc = &Desc->NextDesc; + + void const * const oldMap = Map.Data(); + map_ptrloc const descindex = NewDescription(Desc, CurLang, CurMd5, *LastDesc); + if (oldMap != Map.Data()) + LastDesc += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap; + *LastDesc = descindex; + Desc->ParentPkg = Pkg.Index(); + + if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "NewFileDesc", 1); + + // we can stop here as all "same" versions will share the description + break; + } + + return true; +} + /*}}}*/ +// CacheGenerator::MergeListVersion /*{{{*/ +bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator &Pkg, + std::string const &Version, pkgCache::VerIterator* &OutVer) +{ + pkgCache::VerIterator Ver = Pkg.VersionList(); + Dynamic DynVer(Ver); + map_ptrloc *LastVer = &Pkg->VersionList; + void const * oldMap = Map.Data(); + + unsigned long const Hash = List.VersionHash(); + if (Ver.end() == false) + { + /* We know the list is sorted so we use that fact in the search. + Insertion of new versions is done with correct sorting */ int Res = 1; - unsigned long const Hash = List.VersionHash(); for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++) { Res = Cache.VS->CmpVersion(Version,Ver.VerStr()); @@ -223,83 +352,123 @@ bool pkgCacheGenerator::MergeList(ListParser &List, if (Res == 0 && Ver.end() == false && Ver->Hash == Hash) { if (List.UsePackage(Pkg,Ver) == false) - return _error->Error(_("Error occurred while processing %s (UsePackage2)"), - PackageName.c_str()); + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "UsePackage", 2); if (NewFileVer(Ver,List) == false) - return _error->Error(_("Error occurred while processing %s (NewFileVer1)"), - PackageName.c_str()); - + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "NewFileVer", 1); + // Read only a single record and return if (OutVer != 0) { *OutVer = Ver; - FoundFileDeps |= List.HasFileDeps(); return true; } - - continue; + + return true; } + } - // Add a new version - *LastVer = NewVersion(Ver,Version,*LastVer); - Ver->ParentPkg = Pkg.Index(); - Ver->Hash = Hash; + // Add a new version + map_ptrloc const verindex = NewVersion(Ver,Version,*LastVer); + if (verindex == 0 && _error->PendingError()) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "NewVersion", 1); + + if (oldMap != Map.Data()) + LastVer += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap; + *LastVer = verindex; + Ver->ParentPkg = Pkg.Index(); + Ver->Hash = Hash; + + if (unlikely(List.NewVersion(Ver) == false)) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "NewVersion", 2); + + if (unlikely(List.UsePackage(Pkg,Ver) == false)) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "UsePackage", 3); + + if (unlikely(NewFileVer(Ver,List) == false)) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "NewFileVer", 2); + + pkgCache::GrpIterator Grp = Pkg.Group(); + Dynamic DynGrp(Grp); + + /* If it is the first version of this package we need to add implicit + Multi-Arch dependencies to all other package versions in the group now - + otherwise we just add them for this new version */ + if (Pkg.VersionList()->NextVer == 0) + { + pkgCache::PkgIterator P = Grp.PackageList(); + Dynamic DynP(P); + for (; P.end() != true; P = Grp.NextPkg(P)) + { + if (P->ID == Pkg->ID) + continue; + pkgCache::VerIterator V = P.VersionList(); + Dynamic DynV(V); + for (; V.end() != true; ++V) + if (unlikely(AddImplicitDepends(V, Pkg) == false)) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "AddImplicitDepends", 1); + } + } + if (unlikely(AddImplicitDepends(Grp, Pkg, Ver) == false)) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "AddImplicitDepends", 2); - if ((*LastVer == 0 && _error->PendingError()) || List.NewVersion(Ver) == false) - return _error->Error(_("Error occurred while processing %s (NewVersion1)"), - PackageName.c_str()); + // Read only a single record and return + if (OutVer != 0) + { + *OutVer = Ver; + return true; + } - if (List.UsePackage(Pkg,Ver) == false) - return _error->Error(_("Error occurred while processing %s (UsePackage3)"), - PackageName.c_str()); - - if (NewFileVer(Ver,List) == false) - return _error->Error(_("Error occurred while processing %s (NewVersion2)"), - PackageName.c_str()); + /* Record the Description (it is not translated) */ + MD5SumValue CurMd5 = List.Description_md5(); + if (CurMd5.Value().empty() == true) + return true; + std::string CurLang = List.DescriptionLanguage(); - // Read only a single record and return - if (OutVer != 0) + /* Before we add a new description we first search in the group for + a version with a description of the same MD5 - if so we reuse this + description group instead of creating our own for this version */ + for (pkgCache::PkgIterator P = Grp.PackageList(); + P.end() == false; P = Grp.NextPkg(P)) + { + for (pkgCache::VerIterator V = P.VersionList(); + V.end() == false; ++V) { - *OutVer = Ver; - FoundFileDeps |= List.HasFileDeps(); + if (IsDuplicateDescription(V.DescriptionList(), CurMd5, "") == false) + continue; + Ver->DescriptionList = V->DescriptionList; return true; - } - - /* Record the Description data. Description data always exist in - Packages and Translation-* files. */ - pkgCache::DescIterator Desc = Ver.DescriptionList(); - map_ptrloc *LastDesc = &Ver->DescriptionList; - - // Skip to the end of description set - for (; Desc.end() == false; LastDesc = &Desc->NextDesc, Desc++); - - // Add new description - *LastDesc = NewDescription(Desc, List.DescriptionLanguage(), List.Description_md5(), *LastDesc); - Desc->ParentPkg = Pkg.Index(); - - if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false) - return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str()); } } - FoundFileDeps |= List.HasFileDeps(); + // We haven't found reusable descriptions, so add the first description + pkgCache::DescIterator Desc = Ver.DescriptionList(); + Dynamic DynDesc(Desc); + map_ptrloc *LastDesc = &Ver->DescriptionList; + + oldMap = Map.Data(); + map_ptrloc const descindex = NewDescription(Desc, CurLang, CurMd5, *LastDesc); + if (oldMap != Map.Data()) + LastDesc += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap; + *LastDesc = descindex; + Desc->ParentPkg = Pkg.Index(); + + if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false) + return _error->Error(_("Error occurred while processing %s (%s%d)"), + Pkg.Name(), "NewFileDesc", 2); - if (Cache.HeaderP->PackageCount >= (1ULL<ID)*8)-1) - return _error->Error(_("Wow, you exceeded the number of package " - "names this APT is capable of.")); - if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1) - return _error->Error(_("Wow, you exceeded the number of versions " - "this APT is capable of.")); - if (Cache.HeaderP->DescriptionCount >= (1ULL<<(sizeof(Cache.DescP->ID)*8))-1) - return _error->Error(_("Wow, you exceeded the number of descriptions " - "this APT is capable of.")); - if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL) - return _error->Error(_("Wow, you exceeded the number of dependencies " - "this APT is capable of.")); return true; } /*}}}*/ + /*}}}*/ // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/ // --------------------------------------------------------------------- /* If we found any file depends while parsing the main list we need to @@ -322,21 +491,24 @@ bool pkgCacheGenerator::MergeFileProvides(ListParser &List) continue; pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName); + Dynamic DynPkg(Pkg); if (Pkg.end() == true) - return _error->Error(_("Error occurred while processing %s (FindPkg)"), - PackageName.c_str()); + return _error->Error(_("Error occurred while processing %s (%s%d)"), + PackageName.c_str(), "FindPkg", 1); Counter++; if (Counter % 100 == 0 && Progress != 0) Progress->Progress(List.Offset()); unsigned long Hash = List.VersionHash(); pkgCache::VerIterator Ver = Pkg.VersionList(); - for (; Ver.end() == false; Ver++) + Dynamic DynVer(Ver); + for (; Ver.end() == false; ++Ver) { if (Ver->Hash == Hash && Version.c_str() == Ver.VerStr()) { if (List.CollectFileProvides(Cache,Ver) == false) - return _error->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName.c_str()); + return _error->Error(_("Error occurred while processing %s (%s%d)"), + PackageName.c_str(), "CollectFileProvides", 1); break; } } @@ -358,14 +530,15 @@ bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name) return true; // Get a structure - unsigned long const Group = AllocateInMap(sizeof(pkgCache::Group)); + map_ptrloc const Group = AllocateInMap(sizeof(pkgCache::Group)); if (unlikely(Group == 0)) return false; Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group); - Grp->Name = WriteStringInMap(Name); - if (unlikely(Grp->Name == 0)) + map_ptrloc const idxName = WriteStringInMap(Name); + if (unlikely(idxName == 0)) return false; + Grp->Name = idxName; // Insert it into the hash table unsigned long const Hash = Cache.Hash(Name); @@ -382,6 +555,7 @@ bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name) bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name, const string &Arch) { pkgCache::GrpIterator Grp; + Dynamic DynGrp(Grp); if (unlikely(NewGroup(Grp, Name) == false)) return false; @@ -390,7 +564,7 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name return true; // Get a structure - unsigned long const Package = AllocateInMap(sizeof(pkgCache::Package)); + map_ptrloc const Package = AllocateInMap(sizeof(pkgCache::Package)); if (unlikely(Package == 0)) return false; Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package); @@ -416,13 +590,84 @@ bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name // Set the name, arch and the ID Pkg->Name = Grp->Name; Pkg->Group = Grp.Index(); - Pkg->Arch = WriteUniqString(Arch.c_str()); - if (unlikely(Pkg->Arch == 0)) + // all is mapped to the native architecture + map_ptrloc const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : WriteUniqString(Arch.c_str()); + if (unlikely(idxArch == 0)) return false; + Pkg->Arch = idxArch; Pkg->ID = Cache.HeaderP->PackageCount++; return true; } + /*}}}*/ +// CacheGenerator::AddImplicitDepends /*{{{*/ +bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator &G, + pkgCache::PkgIterator &P, + pkgCache::VerIterator &V) +{ + // copy P.Arch() into a string here as a cache remap + // in NewDepends() later may alter the pointer location + string Arch = P.Arch() == NULL ? "" : P.Arch(); + map_ptrloc *OldDepLast = NULL; + /* MultiArch handling introduces a lot of implicit Dependencies: + - MultiArch: same → Co-Installable if they have the same version + - All others conflict with all other group members */ + bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same); + pkgCache::PkgIterator D = G.PackageList(); + Dynamic DynD(D); + for (; D.end() != true; D = G.NextPkg(D)) + { + if (Arch == D.Arch() || D->VersionList == 0) + continue; + /* We allow only one installed arch at the time + per group, therefore each group member conflicts + with all other group members */ + if (coInstall == true) + { + // Replaces: ${self}:other ( << ${binary:Version}) + NewDepends(D, V, V.VerStr(), + pkgCache::Dep::Less, pkgCache::Dep::Replaces, + OldDepLast); + // Breaks: ${self}:other (!= ${binary:Version}) + NewDepends(D, V, V.VerStr(), + pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks, + OldDepLast); + } else { + // Conflicts: ${self}:other + NewDepends(D, V, "", + pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts, + OldDepLast); + } + } + return true; +} +bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator &V, + pkgCache::PkgIterator &D) +{ + /* MultiArch handling introduces a lot of implicit Dependencies: + - MultiArch: same → Co-Installable if they have the same version + - All others conflict with all other group members */ + map_ptrloc *OldDepLast = NULL; + bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same); + if (coInstall == true) + { + // Replaces: ${self}:other ( << ${binary:Version}) + NewDepends(D, V, V.VerStr(), + pkgCache::Dep::Less, pkgCache::Dep::Replaces, + OldDepLast); + // Breaks: ${self}:other (!= ${binary:Version}) + NewDepends(D, V, V.VerStr(), + pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks, + OldDepLast); + } else { + // Conflicts: ${self}:other + NewDepends(D, V, "", + pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts, + OldDepLast); + } + return true; +} + /*}}}*/ // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/ // --------------------------------------------------------------------- @@ -434,7 +679,7 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver, return true; // Get a structure - unsigned long VerFile = AllocateInMap(sizeof(pkgCache::VerFile)); + map_ptrloc const VerFile = AllocateInMap(sizeof(pkgCache::VerFile)); if (VerFile == 0) return 0; @@ -443,7 +688,7 @@ bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver, // Link it to the end of the list map_ptrloc *Last = &Ver->FileList; - for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++) + for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; ++V) Last = &V->NextFile; VF->NextFile = *Last; *Last = VF.Index(); @@ -465,7 +710,7 @@ unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver, unsigned long Next) { // Get a structure - unsigned long Version = AllocateInMap(sizeof(pkgCache::Version)); + map_ptrloc const Version = AllocateInMap(sizeof(pkgCache::Version)); if (Version == 0) return 0; @@ -473,9 +718,10 @@ unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver, Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version); Ver->NextVer = Next; Ver->ID = Cache.HeaderP->VersionCount++; - Ver->VerStr = WriteStringInMap(VerStr); - if (Ver->VerStr == 0) + map_ptrloc const idxVerStr = WriteStringInMap(VerStr); + if (unlikely(idxVerStr == 0)) return 0; + Ver->VerStr = idxVerStr; return Version; } @@ -490,7 +736,7 @@ bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc, return true; // Get a structure - unsigned long DescFile = AllocateInMap(sizeof(pkgCache::DescFile)); + map_ptrloc const DescFile = AllocateInMap(sizeof(pkgCache::DescFile)); if (DescFile == 0) return false; @@ -499,7 +745,7 @@ bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc, // Link it to the end of the list map_ptrloc *Last = &Desc->FileList; - for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; D++) + for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; ++D) Last = &D->NextFile; DF->NextFile = *Last; @@ -523,7 +769,7 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc, map_ptrloc Next) { // Get a structure - map_ptrloc Description = AllocateInMap(sizeof(pkgCache::Description)); + map_ptrloc const Description = AllocateInMap(sizeof(pkgCache::Description)); if (Description == 0) return 0; @@ -531,86 +777,16 @@ map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc, Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description); Desc->NextDesc = Next; Desc->ID = Cache.HeaderP->DescriptionCount++; - Desc->language_code = WriteStringInMap(Lang); - Desc->md5sum = WriteStringInMap(md5sum.Value()); - if (Desc->language_code == 0 || Desc->md5sum == 0) + map_ptrloc const idxlanguage_code = WriteStringInMap(Lang); + map_ptrloc const idxmd5sum = WriteStringInMap(md5sum.Value()); + if (unlikely(idxlanguage_code == 0 || idxmd5sum == 0)) return 0; + Desc->language_code = idxlanguage_code; + Desc->md5sum = idxmd5sum; return Description; } /*}}}*/ -// CacheGenerator::FinishCache - do various finish operations /*{{{*/ -// --------------------------------------------------------------------- -/* This prepares the Cache for delivery */ -bool pkgCacheGenerator::FinishCache(OpProgress *Progress) -{ - // FIXME: add progress reporting for this operation - // Do we have different architectures in your groups ? - vector archs = APT::Configuration::getArchitectures(); - if (archs.size() > 1) - { - // Create Conflicts in between the group - for (pkgCache::GrpIterator G = GetCache().GrpBegin(); G.end() != true; G++) - { - string const PkgName = G.Name(); - for (pkgCache::PkgIterator P = G.PackageList(); P.end() != true; P = G.NextPkg(P)) - { - if (strcmp(P.Arch(),"all") == 0) - continue; - pkgCache::PkgIterator allPkg; - for (pkgCache::VerIterator V = P.VersionList(); V.end() != true; V++) - { - string const Arch = V.Arch(true); - map_ptrloc *OldDepLast = NULL; - /* MultiArch handling introduces a lot of implicit Dependencies: - - MultiArch: same → Co-Installable if they have the same version - - Architecture: all → Need to be Co-Installable for internal reasons - - All others conflict with all other group members */ - bool const coInstall = (V->MultiArch == pkgCache::Version::All || - V->MultiArch == pkgCache::Version::Same); - if (V->MultiArch == pkgCache::Version::All && allPkg.end() == true) - allPkg = G.FindPkg("all"); - for (vector::const_iterator A = archs.begin(); A != archs.end(); ++A) - { - if (*A == Arch) - continue; - /* We allow only one installed arch at the time - per group, therefore each group member conflicts - with all other group members */ - pkgCache::PkgIterator D = G.FindPkg(*A); - if (D.end() == true) - continue; - if (coInstall == true) - { - // Replaces: ${self}:other ( << ${binary:Version}) - NewDepends(D, V, V.VerStr(), - pkgCache::Dep::Less, pkgCache::Dep::Replaces, - OldDepLast); - // Breaks: ${self}:other (!= ${binary:Version}) - NewDepends(D, V, V.VerStr(), - pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks, - OldDepLast); - if (V->MultiArch == pkgCache::Version::All) - { - // Depend on ${self}:all which does depend on nothing - NewDepends(allPkg, V, V.VerStr(), - pkgCache::Dep::Equals, pkgCache::Dep::Depends, - OldDepLast); - } - } else { - // Conflicts: ${self}:other - NewDepends(D, V, "", - pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts, - OldDepLast); - } - } - } - } - } - } - return true; -} - /*}}}*/ // CacheGenerator::NewDepends - Create a dependency element /*{{{*/ // --------------------------------------------------------------------- /* This creates a dependency element in the tree. It is linked to the @@ -620,15 +796,17 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, string const &Version, unsigned int const &Op, unsigned int const &Type, - map_ptrloc *OldDepLast) + map_ptrloc* &OldDepLast) { + void const * const oldMap = Map.Data(); // Get a structure - unsigned long const Dependency = AllocateInMap(sizeof(pkgCache::Dependency)); + map_ptrloc const Dependency = AllocateInMap(sizeof(pkgCache::Dependency)); if (unlikely(Dependency == 0)) return false; // Fill it in pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency); + Dynamic DynDep(Dep); Dep->ParentVer = Ver.Index(); Dep->Type = Type; Dep->CompareOp = Op; @@ -640,9 +818,12 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++) if (I->Version != 0 && I.TargetVer() == Version) Dep->Version = I->Version;*/ - if (Dep->Version == 0) - if (unlikely((Dep->Version = WriteStringInMap(Version)) == 0)) + if (Dep->Version == 0) { + map_ptrloc const index = WriteStringInMap(Version); + if (unlikely(index == 0)) return false; + Dep->Version = index; + } } // Link it to the package @@ -654,9 +835,10 @@ bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg, if (OldDepLast == NULL) { OldDepLast = &Ver->DependsList; - for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++) + for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D) OldDepLast = &D->NextDepends; - } + } else if (oldMap != Map.Data()) + OldDepLast += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap; Dep->NextDepends = *OldDepLast; *OldDepLast = Dep.Index(); @@ -677,11 +859,13 @@ bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver, unsigned int Type) { pkgCache::GrpIterator Grp; + Dynamic DynGrp(Grp); if (unlikely(Owner->NewGroup(Grp, PackageName) == false)) return false; // Locate the target package pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch); + Dynamic DynPkg(Pkg); if (Pkg.end() == true) { if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false)) return false; @@ -711,17 +895,19 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver, pkgCache &Cache = Owner->Cache; // We do not add self referencing provides - if (Ver.ParentPkg().Name() == PkgName && PkgArch == Ver.Arch(true)) + if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() || + (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0))) return true; // Get a structure - unsigned long const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides)); + map_ptrloc const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides)); if (unlikely(Provides == 0)) return false; Cache.HeaderP->ProvidesCount++; // Fill it in pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP); + Dynamic DynPrv(Prv); Prv->Version = Ver.Index(); Prv->NextPkgProv = Ver->ProvidesList; Ver->ProvidesList = Prv.Index(); @@ -730,6 +916,7 @@ bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver, // Locate the target package pkgCache::PkgIterator Pkg; + Dynamic DynPkg(Pkg); if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false)) return false; @@ -750,24 +937,29 @@ bool pkgCacheGenerator::SelectFile(const string &File,const string &Site, unsigned long Flags) { // Get some space for the structure - CurrentFile = Cache.PkgFileP + AllocateInMap(sizeof(*CurrentFile)); - if (CurrentFile == Cache.PkgFileP) + map_ptrloc const idxFile = AllocateInMap(sizeof(*CurrentFile)); + if (unlikely(idxFile == 0)) return false; - + CurrentFile = Cache.PkgFileP + idxFile; + // Fill it in - CurrentFile->FileName = WriteStringInMap(File); - CurrentFile->Site = WriteUniqString(Site); + map_ptrloc const idxFileName = WriteStringInMap(File); + map_ptrloc const idxSite = WriteUniqString(Site); + if (unlikely(idxFileName == 0 || idxSite == 0)) + return false; + CurrentFile->FileName = idxFileName; + CurrentFile->Site = idxSite; CurrentFile->NextFile = Cache.HeaderP->FileList; CurrentFile->Flags = Flags; CurrentFile->ID = Cache.HeaderP->PackageFileCount; - CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label); + map_ptrloc const idxIndexType = WriteUniqString(Index.GetType()->Label); + if (unlikely(idxIndexType == 0)) + return false; + CurrentFile->IndexType = idxIndexType; PkgFileName = File; Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP; Cache.HeaderP->PackageFileCount++; - if (CurrentFile->FileName == 0) - return false; - if (Progress != 0) Progress->SubProgress(Index.Size()); return true; @@ -807,18 +999,25 @@ unsigned long pkgCacheGenerator::WriteUniqString(const char *S, } // Get a structure - unsigned long Item = AllocateInMap(sizeof(pkgCache::StringItem)); + void const * const oldMap = Map.Data(); + map_ptrloc const Item = AllocateInMap(sizeof(pkgCache::StringItem)); if (Item == 0) return 0; + map_ptrloc const idxString = WriteStringInMap(S,Size); + if (unlikely(idxString == 0)) + return 0; + if (oldMap != Map.Data()) { + Last += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap; + I += (pkgCache::StringItem*) Map.Data() - (pkgCache::StringItem*) oldMap; + } + *Last = Item; + // Fill in the structure pkgCache::StringItem *ItemP = Cache.StringItemP + Item; ItemP->NextItem = I - Cache.StringItemP; - *Last = Item; - ItemP->String = WriteStringInMap(S,Size); - if (ItemP->String == 0) - return 0; - + ItemP->String = idxString; + Bucket = ItemP; return ItemP->String; } @@ -828,8 +1027,11 @@ unsigned long pkgCacheGenerator::WriteUniqString(const char *S, /* This just verifies that each file in the list of index files exists, has matching attributes with the cache and the cache does not have any extra files. */ -static bool CheckValidity(const string &CacheFile, FileIterator Start, - FileIterator End,MMap **OutMap = 0) +static bool CheckValidity(const string &CacheFile, + pkgSourceList &List, + FileIterator Start, + FileIterator End, + MMap **OutMap = 0) { bool const Debug = _config->FindB("Debug::pkgCacheGen", false); // No file, certainly invalid @@ -840,6 +1042,13 @@ static bool CheckValidity(const string &CacheFile, FileIterator Start, return false; } + if (List.GetLastModifiedTime() > GetModificationTime(CacheFile)) + { + if (Debug == true) + std::clog << "sources.list is newer than the cache" << std::endl; + return false; + } + // Map it FileFd CacheF(CacheFile,FileFd::ReadOnly); SPtr Map = new MMap(CacheF,0); @@ -856,7 +1065,7 @@ static bool CheckValidity(const string &CacheFile, FileIterator Start, verify the IMS data and check that it is on the disk too.. */ SPtrArray Visited = new bool[Cache.HeaderP->PackageFileCount]; memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount); - for (; Start != End; Start++) + for (; Start != End; ++Start) { if (Debug == true) std::clog << "Checking PkgFile " << (*Start)->Describe() << ": "; @@ -923,7 +1132,7 @@ static bool CheckValidity(const string &CacheFile, FileIterator Start, static unsigned long ComputeSize(FileIterator Start,FileIterator End) { unsigned long TotalSize = 0; - for (; Start != End; Start++) + for (; Start != End; ++Start) { if ((*Start)->HasPackages() == false) continue; @@ -941,7 +1150,7 @@ static bool BuildCache(pkgCacheGenerator &Gen, FileIterator Start, FileIterator End) { FileIterator I; - for (I = Start; I != End; I++) + for (I = Start; I != End; ++I) { if ((*I)->HasPackages() == false) continue; @@ -971,7 +1180,7 @@ static bool BuildCache(pkgCacheGenerator &Gen, Progress->Done(); TotalSize = ComputeSize(Start, End); CurrentSize = 0; - for (I = Start; I != End; I++) + for (I = Start; I != End; ++I) { unsigned long Size = (*I)->Size(); if (Progress != NULL) @@ -985,6 +1194,20 @@ static bool BuildCache(pkgCacheGenerator &Gen, return true; } /*}}}*/ +// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/ +DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) { + unsigned long const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024); + unsigned long const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024); + unsigned long const MapLimit = _config->FindI("APT::Cache-Limit", 0); + Flags |= MMap::Moveable; + if (_config->FindB("APT::Cache-Fallback", false) == true) + Flags |= MMap::Fallback; + if (CacheF != NULL) + return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit); + else + return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit); +} + /*}}}*/ // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/ // --------------------------------------------------------------------- /* This makes sure that the status cache (the cache that has all @@ -1000,17 +1223,16 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress MMap **OutMap,bool AllowMem) { bool const Debug = _config->FindB("Debug::pkgCacheGen", false); - unsigned long const MapSize = _config->FindI("APT::Cache-Limit",24*1024*1024); - - vector Files; - for (vector::const_iterator i = List.begin(); + + std::vector Files; + for (std::vector::const_iterator i = List.begin(); i != List.end(); - i++) + ++i) { - vector *Indexes = (*i)->GetIndexFiles(); - for (vector::const_iterator j = Indexes->begin(); + std::vector *Indexes = (*i)->GetIndexFiles(); + for (std::vector::const_iterator j = Indexes->begin(); j != Indexes->end(); - j++) + ++j) Files.push_back (*j); } @@ -1052,7 +1274,7 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress Progress->OverallProgress(0,1,1,_("Reading package lists")); // Cache is OK, Fin. - if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true) + if (CheckValidity(CacheFile, List, Files.begin(),Files.end(),OutMap) == true) { if (Progress != NULL) Progress->OverallProgress(1,1,1,_("Reading package lists")); @@ -1069,19 +1291,35 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress SPtr Map; if (Writeable == true && CacheFile.empty() == false) { + _error->PushToStack(); unlink(CacheFile.c_str()); - CacheF = new FileFd(CacheFile,FileFd::WriteEmpty); + CacheF = new FileFd(CacheFile,FileFd::WriteAtomic); fchmod(CacheF->Fd(),0644); - Map = new DynamicMMap(*CacheF,MMap::Public,MapSize); + Map = CreateDynamicMMap(CacheF, MMap::Public); if (_error->PendingError() == true) - return false; - if (Debug == true) + { + delete CacheF.UnGuard(); + delete Map.UnGuard(); + if (Debug == true) + std::clog << "Open filebased MMap FAILED" << std::endl; + Writeable = false; + if (AllowMem == false) + { + _error->MergeWithStack(); + return false; + } + _error->RevertToStack(); + } + else if (Debug == true) + { + _error->MergeWithStack(); std::clog << "Open filebased MMap" << std::endl; + } } - else + if (Writeable == false || CacheFile.empty() == true) { // Just build it in memory.. - Map = new DynamicMMap(0,MapSize); + Map = CreateDynamicMMap(NULL); if (Debug == true) std::clog << "Open memory Map (not filebased)" << std::endl; } @@ -1089,7 +1327,7 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress // Lets try the source cache. unsigned long CurrentSize = 0; unsigned long TotalSize = 0; - if (CheckValidity(SrcCacheFile,Files.begin(), + if (CheckValidity(SrcCacheFile, List, Files.begin(), Files.begin()+EndOfSource) == true) { if (Debug == true) @@ -1111,9 +1349,6 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress if (BuildCache(Gen,Progress,CurrentSize,TotalSize, Files.begin()+EndOfSource,Files.end()) == false) return false; - - // FIXME: move me to a better place - Gen.FinishCache(Progress); } else { @@ -1132,7 +1367,7 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress // Write it back if (Writeable == true && SrcCacheFile.empty() == false) { - FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty); + FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic); if (_error->PendingError() == true) return false; @@ -1156,9 +1391,6 @@ bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress if (BuildCache(Gen,Progress,CurrentSize,TotalSize, Files.begin()+EndOfSource,Files.end()) == false) return false; - - // FIXME: move me to a better place - Gen.FinishCache(Progress); } if (Debug == true) std::clog << "Caches are ready for shipping" << std::endl; @@ -1188,13 +1420,12 @@ __deprecated bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutM { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); } bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap) { - unsigned long MapSize = _config->FindI("APT::Cache-Limit",20*1024*1024); - vector Files; + std::vector Files; unsigned long EndOfSource = Files.size(); if (_system->AddStatusFiles(Files) == false) return false; - - SPtr Map = new DynamicMMap(0,MapSize); + + SPtr Map = CreateDynamicMMap(NULL); unsigned long CurrentSize = 0; unsigned long TotalSize = 0; @@ -1210,9 +1441,6 @@ bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **O Files.begin()+EndOfSource,Files.end()) == false) return false; - // FIXME: move me to a better place - Gen.FinishCache(Progress); - if (_error->PendingError() == true) return false; *OutMap = Map.UnGuard(); @@ -1220,3 +1448,22 @@ bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **O return true; } /*}}}*/ +// IsDuplicateDescription /*{{{*/ +bool IsDuplicateDescription(pkgCache::DescIterator Desc, + MD5SumValue const &CurMd5, std::string const &CurLang) +{ + // Descriptions in the same link-list have all the same md5 + if (MD5SumValue(Desc.md5()) != CurMd5) + return false; + for (; Desc.end() == false; ++Desc) + if (Desc.LanguageCode() == CurLang) + return true; + return false; +} + /*}}}*/ +// CacheGenerator::FinishCache /*{{{*/ +bool pkgCacheGenerator::FinishCache(OpProgress *Progress) +{ + return true; +} + /*}}}*/