1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
12 // Include Files /*{{{*/
15 #include <apt-pkg/pkgcachegen.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/version.h>
18 #include <apt-pkg/progress.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/pkgsystem.h>
22 #include <apt-pkg/macros.h>
23 #include <apt-pkg/metaindex.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/hashsum_template.h>
26 #include <apt-pkg/indexfile.h>
27 #include <apt-pkg/md5.h>
28 #include <apt-pkg/mmap.h>
29 #include <apt-pkg/pkgcache.h>
30 #include <apt-pkg/cacheiterators.h>
44 template<class T
> using Dynamic
= pkgCacheGenerator::Dynamic
<T
>; /*}}}*/
45 typedef std::vector
<pkgIndexFile
*>::iterator FileIterator
;
46 template <typename Iter
> std::vector
<Iter
*> pkgCacheGenerator::Dynamic
<Iter
>::toReMap
;
48 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
49 MD5SumValue
const &CurMd5
, std::string
const &CurLang
);
52 using APT::StringView
;
54 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
55 // ---------------------------------------------------------------------
56 /* We set the dirty flag and make sure that is written to the disk */
57 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
58 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
59 CurrentRlsFile(NULL
), CurrentFile(NULL
), d(NULL
)
63 // Setup the map interface..
64 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
65 _error
->PushToStack();
66 Map
.RawAllocate(sizeof(pkgCache::Header
));
67 bool const newError
= _error
->PendingError();
68 _error
->MergeWithStack();
72 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
75 *Cache
.HeaderP
= pkgCache::Header();
77 // make room for the hashtables for packages and groups
78 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
81 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
82 if (unlikely(idxVerSysName
== 0))
84 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
85 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
86 if (unlikely(idxArchitecture
== 0))
88 Cache
.HeaderP
->Architecture
= idxArchitecture
;
90 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
93 std::vector
<std::string
>::const_iterator a
= archs
.begin();
94 std::string list
= *a
;
95 for (++a
; a
!= archs
.end(); ++a
)
96 list
.append(",").append(*a
);
97 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
98 if (unlikely(idxArchitectures
== 0))
100 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
103 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
105 // Calculate the hash for the empty map, so ReMap does not fail
106 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
111 // Map directly from the existing file
113 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
114 if (Cache
.VS
!= _system
->VS
)
116 _error
->Error(_("Cache has an incompatible versioning system"));
121 Cache
.HeaderP
->Dirty
= true;
122 Map
.Sync(0,sizeof(pkgCache::Header
));
125 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
126 // ---------------------------------------------------------------------
127 /* We sync the data then unset the dirty flag in two steps so as to
128 advoid a problem during a crash */
129 pkgCacheGenerator::~pkgCacheGenerator()
131 if (_error
->PendingError() == true || Map
.validData() == false)
133 if (Map
.Sync() == false)
136 Cache
.HeaderP
->Dirty
= false;
137 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
139 if (_config
->FindB("Debug::pkgCacheGen", false))
140 std::clog
<< "Produced cache with hash " << Cache
.HeaderP
->CacheFileSize
<< std::endl
;
141 Map
.Sync(0,sizeof(pkgCache::Header
));
144 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
, size_t oldSize
) {/*{{{*/
145 if (oldMap
== newMap
)
148 if (_config
->FindB("Debug::pkgCacheGen", false))
149 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
153 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
154 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
156 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
157 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
158 (*i
)->ReMap(oldMap
, newMap
);
159 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
160 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
161 (*i
)->ReMap(oldMap
, newMap
);
162 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
163 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
164 (*i
)->ReMap(oldMap
, newMap
);
165 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
166 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
167 (*i
)->ReMap(oldMap
, newMap
);
168 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
169 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
170 (*i
)->ReMap(oldMap
, newMap
);
171 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
172 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
173 (*i
)->ReMap(oldMap
, newMap
);
174 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
175 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
176 (*i
)->ReMap(oldMap
, newMap
);
177 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
178 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
179 (*i
)->ReMap(oldMap
, newMap
);
181 // CacheGenerator::WriteStringInMap /*{{{*/
182 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
183 const unsigned long &Len
) {
184 size_t oldSize
= Map
.Size();
185 void const * const oldMap
= Map
.Data();
186 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
188 ReMap(oldMap
, Map
.Data(), oldSize
);
192 // CacheGenerator::WriteStringInMap /*{{{*/
193 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
194 size_t oldSize
= Map
.Size();
195 void const * const oldMap
= Map
.Data();
196 map_stringitem_t
const index
= Map
.WriteString(String
);
198 ReMap(oldMap
, Map
.Data(), oldSize
);
202 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
203 size_t oldSize
= Map
.Size();
204 void const * const oldMap
= Map
.Data();
205 map_pointer_t
const index
= Map
.Allocate(size
);
207 ReMap(oldMap
, Map
.Data(), oldSize
);
211 // CacheGenerator::MergeList - Merge the package list /*{{{*/
212 // ---------------------------------------------------------------------
213 /* This provides the generation of the entries in the cache. Each loop
214 goes through a single package record from the underlying parse engine. */
215 bool pkgCacheGenerator::MergeList(ListParser
&List
,
216 pkgCache::VerIterator
*OutVer
)
220 unsigned int Counter
= 0;
221 while (List
.Step() == true)
223 string
const PackageName
= List
.Package();
224 if (PackageName
.empty() == true)
228 if (Counter
% 100 == 0 && Progress
!= 0)
229 Progress
->Progress(List
.Offset());
231 string Arch
= List
.Architecture();
232 string
const Version
= List
.Version();
233 if (Version
.empty() == true && Arch
.empty() == true)
235 // package descriptions
236 if (MergeListGroup(List
, PackageName
) == false)
241 // Get a pointer to the package structure
242 pkgCache::PkgIterator Pkg
;
243 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
244 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
245 // TRANSLATOR: The first placeholder is a package name,
246 // the other two should be copied verbatim as they include debug info
247 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
248 PackageName
.c_str(), "NewPackage", 1);
251 if (Version
.empty() == true)
253 if (MergeListPackage(List
, Pkg
) == false)
258 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
266 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
267 return _error
->Error(_("Wow, you exceeded the number of package "
268 "names this APT is capable of."));
269 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
270 return _error
->Error(_("Wow, you exceeded the number of versions "
271 "this APT is capable of."));
272 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
273 return _error
->Error(_("Wow, you exceeded the number of descriptions "
274 "this APT is capable of."));
275 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
276 return _error
->Error(_("Wow, you exceeded the number of dependencies "
277 "this APT is capable of."));
281 // CacheGenerator::MergeListGroup /*{{{*/
282 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
284 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
285 // a group has no data on it's own, only packages have it but these
286 // stanzas like this come from Translation- files to add descriptions,
287 // but without a version we don't need a description for it…
288 if (Grp
.end() == true)
290 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
292 pkgCache::PkgIterator Pkg
;
293 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
294 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
295 if (MergeListPackage(List
, Pkg
) == false)
301 // CacheGenerator::MergeListPackage /*{{{*/
302 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
304 // we first process the package, then the descriptions
305 // (for deb this package processing is in fact a no-op)
306 pkgCache::VerIterator
Ver(Cache
);
307 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
308 if (List
.UsePackage(Pkg
, Ver
) == false)
309 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
310 Pkg
.Name(), "UsePackage", 1);
312 // Find the right version to write the description
313 MD5SumValue CurMd5
= List
.Description_md5();
314 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
315 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
317 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
319 // a version can only have one md5 describing it
320 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
323 map_stringitem_t md5idx
= VerDesc
->md5sum
;
324 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
326 // don't add a new description if we have one for the given
328 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
331 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
334 // we can stop here as all "same" versions will share the description
341 // CacheGenerator::MergeListVersion /*{{{*/
342 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
343 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
345 pkgCache::VerIterator Ver
= Pkg
.VersionList();
346 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
347 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
348 void const * oldMap
= Map
.Data();
350 unsigned short const Hash
= List
.VersionHash();
351 if (Ver
.end() == false)
353 /* We know the list is sorted so we use that fact in the search.
354 Insertion of new versions is done with correct sorting */
356 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
358 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
359 // Version is higher as current version - insert here
362 // Versionstrings are equal - is hash also equal?
363 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
365 // proceed with the next till we have either the right
366 // or we found another version (which will be lower)
369 /* We already have a version for this item, record that we saw it */
370 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
372 if (List
.UsePackage(Pkg
,Ver
) == false)
373 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
374 Pkg
.Name(), "UsePackage", 2);
376 if (NewFileVer(Ver
,List
) == false)
377 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
378 Pkg
.Name(), "NewFileVer", 1);
380 // Read only a single record and return
392 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
393 if (unlikely(verindex
== 0))
394 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
395 Pkg
.Name(), "NewVersion", 1);
397 if (oldMap
!= Map
.Data())
398 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
401 if (unlikely(List
.NewVersion(Ver
) == false))
402 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
403 Pkg
.Name(), "NewVersion", 2);
405 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
406 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
407 Pkg
.Name(), "UsePackage", 3);
409 if (unlikely(NewFileVer(Ver
,List
) == false))
410 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
411 Pkg
.Name(), "NewFileVer", 2);
413 pkgCache::GrpIterator Grp
= Pkg
.Group();
414 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
416 /* If it is the first version of this package we need to add implicit
417 Multi-Arch dependencies to all other package versions in the group now -
418 otherwise we just add them for this new version */
419 if (Pkg
.VersionList()->NextVer
== 0)
421 pkgCache::PkgIterator P
= Grp
.PackageList();
422 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
423 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
425 if (P
->ID
== Pkg
->ID
)
427 pkgCache::VerIterator V
= P
.VersionList();
428 Dynamic
<pkgCache::VerIterator
> DynV(V
);
429 for (; V
.end() != true; ++V
)
430 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
431 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
432 Pkg
.Name(), "AddImplicitDepends", 1);
435 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
436 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
437 Pkg
.Name(), "AddImplicitDepends", 2);
439 // Read only a single record and return
446 /* Record the Description(s) based on their master md5sum */
447 MD5SumValue CurMd5
= List
.Description_md5();
449 /* Before we add a new description we first search in the group for
450 a version with a description of the same MD5 - if so we reuse this
451 description group instead of creating our own for this version */
452 for (pkgCache::PkgIterator P
= Grp
.PackageList();
453 P
.end() == false; P
= Grp
.NextPkg(P
))
455 for (pkgCache::VerIterator V
= P
.VersionList();
456 V
.end() == false; ++V
)
458 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
460 Ver
->DescriptionList
= V
->DescriptionList
;
464 // We haven't found reusable descriptions, so add the first description(s)
465 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
466 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
467 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
468 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
473 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
475 pkgCache::DescIterator Desc
;
476 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
478 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
479 if (unlikely(descindex
== 0))
480 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
481 Ver
.ParentPkg().Name(), "NewDescription", 1);
483 md5idx
= Desc
->md5sum
;
484 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
486 // we add at the end, so that the start is constant as we need
487 // that to be able to efficiently share these lists
488 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
489 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
490 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
491 *LastNextDesc
= descindex
;
493 if (NewFileDesc(Desc
,List
) == false)
494 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
495 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
501 // CacheGenerator::NewGroup - Add a new group /*{{{*/
502 // ---------------------------------------------------------------------
503 /* This creates a new group structure and adds it to the hash table */
504 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
506 Grp
= Cache
.FindGrp(Name
);
507 if (Grp
.end() == false)
511 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
512 if (unlikely(Group
== 0))
515 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
516 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
517 if (unlikely(idxName
== 0))
521 // Insert it into the hash table
522 unsigned long const Hash
= Cache
.Hash(Name
);
523 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
525 while (*insertAt
!= 0 && Name
.compare(Cache
.ViewString((Cache
.GrpP
+ *insertAt
)->Name
)) > 0)
526 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
527 Grp
->Next
= *insertAt
;
530 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
534 // CacheGenerator::NewPackage - Add a new package /*{{{*/
535 // ---------------------------------------------------------------------
536 /* This creates a new package structure and adds it to the hash table */
537 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
539 pkgCache::GrpIterator Grp
;
540 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
541 if (unlikely(NewGroup(Grp
, Name
) == false))
544 Pkg
= Grp
.FindPkg(Arch
);
545 if (Pkg
.end() == false)
549 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
550 if (unlikely(Package
== 0))
552 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
554 // Set the name, arch and the ID
555 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
556 Pkg
->Group
= Grp
.Index();
557 // all is mapped to the native architecture
558 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
559 if (unlikely(idxArch
== 0))
562 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
564 // Insert the package into our package list
565 if (Grp
->FirstPackage
== 0) // the group is new
567 Grp
->FirstPackage
= Package
;
568 // Insert it into the hash table
569 map_id_t
const Hash
= Cache
.Hash(Name
);
570 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
571 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
572 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
573 Pkg
->NextPackage
= *insertAt
;
576 else // Group the Packages together
578 // if sibling is provided by another package, this one is too
580 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
581 if (M
.end() == false) {
582 pkgCache::PrvIterator Prv
;
583 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
584 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
586 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
588 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
589 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
590 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
591 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
592 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
594 if (APT::Configuration::checkArchitecture(Ver
.ParentPkg().Arch()) == false)
596 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
602 // let M-A:foreign package siblings provide this package
604 pkgCache::PkgIterator P
;
605 pkgCache::VerIterator Ver
;
606 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
607 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
609 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
611 if (APT::Configuration::checkArchitecture(P
.Arch()) == false)
613 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
614 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
615 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
619 // and negative dependencies, don't forget negative dependencies
621 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
622 if (M
.end() == false) {
623 pkgCache::DepIterator Dep
;
624 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
625 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
627 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
629 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
630 Dep
->Type
!= pkgCache::Dep::Replaces
)
632 pkgCache::VerIterator Ver
= Dep
.ParentVer();
633 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
634 map_pointer_t
* unused
= NULL
;
635 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
641 // this package is the new last package
642 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
643 Pkg
->NextPackage
= LastPkg
->NextPackage
;
644 LastPkg
->NextPackage
= Package
;
646 Grp
->LastPackage
= Package
;
648 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
651 size_t const found
= Name
.find(':');
652 StringView
const NameA
= Name
.substr(0, found
);
653 StringView
const ArchA
= Name
.substr(found
+ 1);
654 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
655 if (PkgA
.end() == false)
657 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
658 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
659 for (; Prv
.end() == false; ++Prv
)
661 if (Prv
.IsMultiArchImplicit())
663 pkgCache::VerIterator V
= Prv
.OwnerVer();
664 if (ArchA
!= V
.ParentPkg().Arch())
666 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
669 pkgCache::VerIterator V
= PkgA
.VersionList();
670 Dynamic
<pkgCache::VerIterator
> DynV(V
);
671 for (; V
.end() == false; ++V
)
673 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
681 // CacheGenerator::AddImplicitDepends /*{{{*/
682 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
683 pkgCache::PkgIterator
&P
,
684 pkgCache::VerIterator
&V
)
686 // copy P.Arch() into a string here as a cache remap
687 // in NewDepends() later may alter the pointer location
688 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
689 map_pointer_t
*OldDepLast
= NULL
;
690 /* MultiArch handling introduces a lot of implicit Dependencies:
691 - MultiArch: same → Co-Installable if they have the same version
692 - All others conflict with all other group members */
693 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
694 pkgCache::PkgIterator D
= G
.PackageList();
695 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
696 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
697 for (; D
.end() != true; D
= G
.NextPkg(D
))
699 if (Arch
== D
.Arch() || D
->VersionList
== 0)
701 /* We allow only one installed arch at the time
702 per group, therefore each group member conflicts
703 with all other group members */
704 if (coInstall
== true)
706 // Replaces: ${self}:other ( << ${binary:Version})
707 NewDepends(D
, V
, VerStrIdx
,
708 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
710 // Breaks: ${self}:other (!= ${binary:Version})
711 NewDepends(D
, V
, VerStrIdx
,
712 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
715 // Conflicts: ${self}:other
717 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
723 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
724 pkgCache::PkgIterator
&D
)
726 /* MultiArch handling introduces a lot of implicit Dependencies:
727 - MultiArch: same → Co-Installable if they have the same version
728 - All others conflict with all other group members */
729 map_pointer_t
*OldDepLast
= NULL
;
730 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
731 if (coInstall
== true)
733 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
734 // Replaces: ${self}:other ( << ${binary:Version})
735 NewDepends(D
, V
, VerStrIdx
,
736 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
738 // Breaks: ${self}:other (!= ${binary:Version})
739 NewDepends(D
, V
, VerStrIdx
,
740 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
743 // Conflicts: ${self}:other
745 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
752 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
753 // ---------------------------------------------------------------------
755 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
758 if (CurrentFile
== 0)
762 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
766 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
767 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
769 // Link it to the end of the list
770 map_pointer_t
*Last
= &Ver
->FileList
;
771 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
773 VF
->NextFile
= *Last
;
776 VF
->Offset
= List
.Offset();
777 VF
->Size
= List
.Size();
778 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
779 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
780 Cache
.HeaderP
->VerFileCount
++;
785 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
786 // ---------------------------------------------------------------------
787 /* This puts a version structure in the linked list */
788 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
789 const string
&VerStr
,
790 map_pointer_t
const ParentPkg
,
791 unsigned short const Hash
,
792 map_pointer_t
const Next
)
795 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
800 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
801 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
803 Ver
->ParentPkg
= ParentPkg
;
805 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
807 // try to find the version string in the group for reuse
808 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
809 pkgCache::GrpIterator Grp
= Pkg
.Group();
810 if (Pkg
.end() == false && Grp
.end() == false)
812 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
816 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
818 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
821 Ver
->VerStr
= V
->VerStr
;
829 // haven't found the version string, so create
830 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
831 if (unlikely(idxVerStr
== 0))
833 Ver
->VerStr
= idxVerStr
;
837 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
838 // ---------------------------------------------------------------------
840 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
843 if (CurrentFile
== 0)
847 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
851 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
852 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
854 // Link it to the end of the list
855 map_pointer_t
*Last
= &Desc
->FileList
;
856 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
859 DF
->NextFile
= *Last
;
862 DF
->Offset
= List
.Offset();
863 DF
->Size
= List
.Size();
864 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
865 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
866 Cache
.HeaderP
->DescFileCount
++;
871 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
872 // ---------------------------------------------------------------------
873 /* This puts a description structure in the linked list */
874 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
876 const MD5SumValue
&md5sum
,
877 map_stringitem_t
const idxmd5str
)
880 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
881 if (Description
== 0)
885 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
886 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
887 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
888 if (unlikely(idxlanguage_code
== 0))
890 Desc
->language_code
= idxlanguage_code
;
893 Desc
->md5sum
= idxmd5str
;
896 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
897 if (unlikely(idxmd5sum
== 0))
899 Desc
->md5sum
= idxmd5sum
;
905 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
906 // ---------------------------------------------------------------------
907 /* This creates a dependency element in the tree. It is linked to the
908 version and to the package that it is pointing to. */
909 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
910 pkgCache::VerIterator
&Ver
,
911 map_pointer_t
const Version
,
914 map_pointer_t
* &OldDepLast
)
916 void const * const oldMap
= Map
.Data();
918 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
919 if (unlikely(Dependency
== 0))
922 bool isDuplicate
= false;
923 map_pointer_t DependencyData
= 0;
924 map_pointer_t PreviousData
= 0;
925 if (Pkg
->RevDepends
!= 0)
927 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
928 DependencyData
= L
->DependencyData
;
930 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
931 if (Version
> D
->Version
)
933 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
938 PreviousData
= DependencyData
;
939 DependencyData
= D
->NextData
;
940 } while (DependencyData
!= 0);
943 if (isDuplicate
== false)
945 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
946 if (unlikely(DependencyData
== 0))
950 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
951 Link
->ParentVer
= Ver
.Index();
952 Link
->DependencyData
= DependencyData
;
953 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
955 pkgCache::DepIterator
Dep(Cache
, Link
);
956 if (isDuplicate
== false)
960 Dep
->Version
= Version
;
961 Dep
->Package
= Pkg
.Index();
962 ++Cache
.HeaderP
->DependsDataCount
;
963 if (PreviousData
!= 0)
965 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
966 Dep
->NextData
= D
->NextData
;
967 D
->NextData
= DependencyData
;
969 else if (Pkg
->RevDepends
!= 0)
971 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
972 Dep
->NextData
= D
->DependencyData
;
976 if (isDuplicate
== true || PreviousData
!= 0)
978 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
979 Link
->NextRevDepends
= L
->NextRevDepends
;
980 L
->NextRevDepends
= Dependency
;
984 Link
->NextRevDepends
= Pkg
->RevDepends
;
985 Pkg
->RevDepends
= Dependency
;
989 // Do we know where to link the Dependency to?
990 if (OldDepLast
== NULL
)
992 OldDepLast
= &Ver
->DependsList
;
993 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
994 OldDepLast
= &D
->NextDepends
;
995 } else if (oldMap
!= Map
.Data())
996 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
998 Dep
->NextDepends
= *OldDepLast
;
999 *OldDepLast
= Dependency
;
1000 OldDepLast
= &Dep
->NextDepends
;
1004 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1005 // ---------------------------------------------------------------------
1006 /* This creates a Group and the Package to link this dependency to if
1007 needed and handles also the caching of the old endpoint */
1008 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1009 StringView PackageName
,
1015 pkgCache::GrpIterator Grp
;
1016 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1017 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1020 map_stringitem_t idxVersion
= 0;
1021 if (Version
.empty() == false)
1023 int const CmpOp
= Op
& 0x0F;
1024 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1025 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1026 idxVersion
= Ver
->VerStr
;
1028 if (idxVersion
== 0)
1030 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1031 if (unlikely(idxVersion
== 0))
1036 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1037 Type
== pkgCache::Dep::Conflicts
||
1038 Type
== pkgCache::Dep::Replaces
);
1040 pkgCache::PkgIterator Pkg
;
1041 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1042 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1044 // Locate the target package
1045 Pkg
= Grp
.FindPkg(Arch
);
1046 if (Pkg
.end() == true) {
1047 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1051 /* Caching the old end point speeds up generation substantially */
1052 if (OldDepVer
!= Ver
) {
1057 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1061 /* Caching the old end point speeds up generation substantially */
1062 if (OldDepVer
!= Ver
) {
1067 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1069 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1076 // ListParser::NewProvides - Create a Provides element /*{{{*/
1077 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1081 uint8_t const Flags
)
1083 pkgCache
const &Cache
= Owner
->Cache
;
1085 // We do not add self referencing provides
1086 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1087 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1088 (Version
.empty() || Version
== Ver
.VerStr()))
1091 // Locate the target package
1092 pkgCache::PkgIterator Pkg
;
1093 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1094 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1097 map_stringitem_t idxProvideVersion
= 0;
1098 if (Version
.empty() == false) {
1099 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1100 if (unlikely(idxProvideVersion
== 0))
1103 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1105 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1106 pkgCache::PkgIterator
&Pkg
,
1107 map_pointer_t
const ProvideVersion
,
1108 uint8_t const Flags
)
1111 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1112 if (unlikely(Provides
== 0))
1114 ++Cache
.HeaderP
->ProvidesCount
;
1117 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1118 Prv
->Version
= Ver
.Index();
1119 Prv
->ProvideVersion
= ProvideVersion
;
1121 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1122 Ver
->ProvidesList
= Prv
.Index();
1124 // Link it to the package
1125 Prv
->ParentPkg
= Pkg
.Index();
1126 Prv
->NextProvides
= Pkg
->ProvidesList
;
1127 Pkg
->ProvidesList
= Prv
.Index();
1131 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1132 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1133 StringView Version
, uint8_t const Flags
) {
1134 pkgCache
&Cache
= Owner
->Cache
;
1135 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1136 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1138 if (Grp
.end() == true)
1139 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1142 map_stringitem_t idxProvideVersion
= 0;
1143 if (Version
.empty() == false) {
1144 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1145 if (unlikely(idxProvideVersion
== 0))
1149 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1150 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1151 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1152 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1153 pkgCache::PkgIterator Pkg
;
1154 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1155 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1157 if (isImplicit
&& OwnerPkg
== Pkg
)
1159 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1161 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1168 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1169 pkgCache::VerIterator
const &Ver
)
1171 return Hash
== Ver
->Hash
;
1174 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1175 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1176 unsigned long Flags
)
1178 if (File
.empty() && Site
.empty())
1180 CurrentRlsFile
= NULL
;
1184 // Get some space for the structure
1185 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1186 if (unlikely(idxFile
== 0))
1188 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1191 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1192 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1193 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1195 CurrentRlsFile
->FileName
= idxFileName
;
1196 CurrentRlsFile
->Site
= idxSite
;
1197 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1198 CurrentRlsFile
->Flags
= Flags
;
1199 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1201 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1202 Cache
.HeaderP
->ReleaseFileCount
++;
1207 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1208 // ---------------------------------------------------------------------
1209 /* This is used to select which file is to be associated with all newly
1210 added versions. The caller is responsible for setting the IMS fields. */
1211 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1212 pkgIndexFile
const &Index
,
1213 std::string
const &Architecture
,
1214 std::string
const &Component
,
1215 unsigned long const Flags
)
1217 // Get some space for the structure
1218 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1219 if (unlikely(idxFile
== 0))
1221 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1224 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1225 if (unlikely(idxFileName
== 0))
1227 CurrentFile
->FileName
= idxFileName
;
1228 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1229 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1230 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1231 if (unlikely(idxIndexType
== 0))
1233 CurrentFile
->IndexType
= idxIndexType
;
1234 if (Architecture
.empty())
1235 CurrentFile
->Architecture
= 0;
1238 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1239 if (unlikely(arch
== 0))
1241 CurrentFile
->Architecture
= arch
;
1243 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1244 if (unlikely(component
== 0))
1246 CurrentFile
->Component
= component
;
1247 CurrentFile
->Flags
= Flags
;
1248 if (CurrentRlsFile
!= NULL
)
1249 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1251 CurrentFile
->Release
= 0;
1253 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1254 Cache
.HeaderP
->PackageFileCount
++;
1257 Progress
->SubProgress(Index
.Size());
1261 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1262 // ---------------------------------------------------------------------
1263 /* This is used to create handles to strings. Given the same text it
1264 always returns the same number */
1265 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1268 auto strings
= &strMixed
;
1270 case MIXED
: strings
= &strMixed
; break;
1271 case PKGNAME
: strings
= &strPkgNames
; break;
1272 case VERSIONNUMBER
: strings
= &strVersions
; break;
1273 case SECTION
: strings
= &strSections
; break;
1274 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1277 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1278 if (item
!= strings
->end())
1281 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1282 strings
->insert({nullptr, Size
, this, idxString
});
1286 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1287 // ---------------------------------------------------------------------
1288 /* This just verifies that each file in the list of index files exists,
1289 has matching attributes with the cache and the cache does not have
1291 class APT_HIDDEN ScopedErrorRevert
{
1293 ScopedErrorRevert() { _error
->PushToStack(); }
1294 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1296 static bool CheckValidity(const string
&CacheFile
,
1297 pkgSourceList
&List
,
1298 FileIterator
const Start
,
1299 FileIterator
const End
,
1301 pkgCache
**OutCache
= 0)
1303 ScopedErrorRevert ser
;
1304 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1305 // No file, certainly invalid
1306 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1309 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1313 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1316 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1321 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1322 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1323 if (unlikely(Map
->validData()) == false)
1325 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1326 pkgCache
&Cache
= *CacheP
.get();
1327 if (_error
->PendingError() || Map
->Size() == 0)
1330 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1334 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1335 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1336 std::vector
<pkgIndexFile
*> Files
;
1337 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1340 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1341 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1342 if (RlsFile
.end() == true)
1345 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1349 RlsVisited
[RlsFile
->ID
] = true;
1351 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1353 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1354 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1355 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1357 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1358 if (RlsVisited
[I
] == false)
1361 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1365 std::copy(Start
, End
, std::back_inserter(Files
));
1367 /* Now we check every index file, see if it is in the cache,
1368 verify the IMS data and check that it is on the disk too.. */
1369 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1370 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1371 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1374 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1375 if ((*PkgFile
)->Exists() == false)
1378 std::clog
<< "file doesn't exist" << std::endl
;
1382 // FindInCache is also expected to do an IMS check.
1383 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1384 if (File
.end() == true)
1387 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1391 Visited
[File
->ID
] = true;
1393 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1396 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1397 if (Visited
[I
] == false)
1400 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1404 if (_error
->PendingError() == true)
1408 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1409 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1415 *OutMap
= Map
.release();
1417 *OutCache
= CacheP
.release();
1421 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1422 // ---------------------------------------------------------------------
1423 /* Size is kind of an abstract notion that is only used for the progress
1425 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1427 map_filesize_t TotalSize
= 0;
1430 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1432 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1433 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1434 if ((*j
)->HasPackages() == true)
1435 TotalSize
+= (*j
)->Size();
1439 for (; Start
< End
; ++Start
)
1441 if ((*Start
)->HasPackages() == false)
1443 TotalSize
+= (*Start
)->Size();
1448 // BuildCache - Merge the list of index files into the cache /*{{{*/
1449 static bool BuildCache(pkgCacheGenerator
&Gen
,
1450 OpProgress
* const Progress
,
1451 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1452 pkgSourceList
const * const List
,
1453 FileIterator
const Start
, FileIterator
const End
)
1455 bool mergeFailure
= false;
1457 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1458 if (I
->HasPackages() == false || mergeFailure
)
1461 if (I
->Exists() == false)
1464 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1466 _error
->Warning("Duplicate sources.list entry %s",
1467 I
->Describe().c_str());
1471 map_filesize_t
const Size
= I
->Size();
1472 if (Progress
!= NULL
)
1473 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1474 CurrentSize
+= Size
;
1476 if (I
->Merge(Gen
,Progress
) == false)
1477 mergeFailure
= true;
1482 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1484 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1486 _error
->Warning("Duplicate sources.list entry %s",
1487 (*i
)->Describe().c_str());
1491 if ((*i
)->Merge(Gen
, Progress
) == false)
1494 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1495 if (Indexes
!= NULL
)
1496 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1504 Gen
.SelectReleaseFile("", "");
1505 std::for_each(Start
, End
, indexFileMerge
);
1512 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1513 // ---------------------------------------------------------------------
1514 /* This makes sure that the status cache (the cache that has all
1515 index files from the sources list and all local ones) is ready
1516 to be mmaped. If OutMap is not zero then a MMap object representing
1517 the cache will be stored there. This is pretty much mandetory if you
1518 are using AllowMem. AllowMem lets the function be run as non-root
1519 where it builds the cache 'fast' into a memory buffer. */
1520 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1522 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1523 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1524 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1525 Flags
|= MMap::Moveable
;
1526 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1527 Flags
|= MMap::Fallback
;
1529 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1531 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1533 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1534 std::string
const &FileName
)
1536 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1537 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1540 fchmod(SCacheF
.Fd(),0644);
1542 // Write out the main data
1543 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1544 return _error
->Error(_("IO Error saving source cache"));
1546 // Write out the proper header
1547 Gen
->GetCache().HeaderP
->Dirty
= false;
1548 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1549 if (SCacheF
.Seek(0) == false ||
1550 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1551 return _error
->Error(_("IO Error saving source cache"));
1552 Gen
->GetCache().HeaderP
->Dirty
= true;
1555 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1556 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1558 Map
.reset(CreateDynamicMMap(NULL
, 0));
1559 if (unlikely(Map
->validData()) == false)
1561 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1562 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1564 _error
->PushToStack();
1565 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1566 bool const newError
= _error
->PendingError();
1567 _error
->MergeWithStack();
1568 if (alloc
== 0 && newError
)
1570 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1572 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1575 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1576 MMap
**OutMap
, bool AllowMem
)
1577 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1578 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1581 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1583 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1584 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1586 // FIXME: deprecate the ignored AllowMem parameter
1587 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1589 std::vector
<pkgIndexFile
*> Files
;
1590 if (_system
->AddStatusFiles(Files
) == false)
1593 // Decide if we can write to the files..
1594 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1595 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1597 // ensure the cache directory exists
1598 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1600 string dir
= _config
->FindDir("Dir::Cache");
1601 size_t const len
= dir
.size();
1602 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1603 dir
= dir
.substr(0, len
- 5);
1604 if (CacheFile
.empty() == false)
1605 CreateDirectory(dir
, flNotFile(CacheFile
));
1606 if (SrcCacheFile
.empty() == false)
1607 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1610 if (Progress
!= NULL
)
1611 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1613 bool pkgcache_fine
= false;
1614 bool srcpkgcache_fine
= false;
1615 bool volatile_fine
= List
.GetVolatileFiles().empty();
1617 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1618 volatile_fine
? OutCache
: NULL
) == true)
1621 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1622 pkgcache_fine
= true;
1623 srcpkgcache_fine
= true;
1625 if (pkgcache_fine
== false)
1627 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1630 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1631 srcpkgcache_fine
= true;
1635 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1637 if (Progress
!= NULL
)
1638 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1642 bool Writeable
= false;
1643 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1645 if (CacheFile
.empty() == false)
1646 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1647 else if (SrcCacheFile
.empty() == false)
1648 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1651 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1654 // At this point we know we need to construct something, so get storage ready
1655 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1656 if (unlikely(Map
->validData()) == false)
1659 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1661 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1662 map_filesize_t CurrentSize
= 0;
1663 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1664 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1665 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1668 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1669 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1671 srcpkgcache_fine
= true;
1672 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1674 else if (srcpkgcache_fine
== false)
1677 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1678 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1680 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1681 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1682 Files
.end(),Files
.end()) == false)
1685 if (Writeable
== true && SrcCacheFile
.empty() == false)
1686 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1690 if (pkgcache_fine
== false)
1693 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1694 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1695 Files
.begin(), Files
.end()) == false)
1698 if (Writeable
== true && CacheFile
.empty() == false)
1699 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1704 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1706 if (volatile_fine
== false)
1711 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1712 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1716 Files
= List
.GetVolatileFiles();
1717 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1718 Files
.begin(), Files
.end()) == false)
1722 if (OutMap
!= nullptr)
1723 *OutMap
= Map
.release();
1726 std::clog
<< "Everything is ready for shipping" << std::endl
;
1730 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1731 class APT_HIDDEN ScopedErrorMerge
{
1733 ScopedErrorMerge() { _error
->PushToStack(); }
1734 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1736 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1737 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1738 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1740 std::vector
<pkgIndexFile
*> Files
;
1741 if (_system
->AddStatusFiles(Files
) == false)
1744 ScopedErrorMerge sem
;
1745 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1746 if (unlikely(Map
->validData()) == false)
1748 map_filesize_t CurrentSize
= 0;
1749 map_filesize_t TotalSize
= 0;
1750 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1752 // Build the status cache
1753 if (Progress
!= NULL
)
1754 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1755 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1756 if (_error
->PendingError() == true)
1758 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1759 Files
.begin(), Files
.end()) == false)
1762 if (_error
->PendingError() == true)
1764 *OutMap
= Map
.release();
1769 // IsDuplicateDescription /*{{{*/
1770 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1771 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1773 // Descriptions in the same link-list have all the same md5
1774 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1776 for (; Desc
.end() == false; ++Desc
)
1777 if (Desc
.LanguageCode() == CurLang
)
1783 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1784 pkgCacheListParser::~pkgCacheListParser() {}