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
) {/*{{{*/
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 void const * const oldMap
= Map
.Data();
185 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
187 ReMap(oldMap
, Map
.Data());
191 // CacheGenerator::WriteStringInMap /*{{{*/
192 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
193 void const * const oldMap
= Map
.Data();
194 map_stringitem_t
const index
= Map
.WriteString(String
);
196 ReMap(oldMap
, Map
.Data());
200 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
201 void const * const oldMap
= Map
.Data();
202 map_pointer_t
const index
= Map
.Allocate(size
);
204 ReMap(oldMap
, Map
.Data());
208 // CacheGenerator::MergeList - Merge the package list /*{{{*/
209 // ---------------------------------------------------------------------
210 /* This provides the generation of the entries in the cache. Each loop
211 goes through a single package record from the underlying parse engine. */
212 bool pkgCacheGenerator::MergeList(ListParser
&List
,
213 pkgCache::VerIterator
*OutVer
)
217 unsigned int Counter
= 0;
218 while (List
.Step() == true)
220 string
const PackageName
= List
.Package();
221 if (PackageName
.empty() == true)
225 if (Counter
% 100 == 0 && Progress
!= 0)
226 Progress
->Progress(List
.Offset());
228 string Arch
= List
.Architecture();
229 string
const Version
= List
.Version();
230 if (Version
.empty() == true && Arch
.empty() == true)
232 // package descriptions
233 if (MergeListGroup(List
, PackageName
) == false)
238 // Get a pointer to the package structure
239 pkgCache::PkgIterator Pkg
;
240 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
241 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
242 // TRANSLATOR: The first placeholder is a package name,
243 // the other two should be copied verbatim as they include debug info
244 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
245 PackageName
.c_str(), "NewPackage", 1);
248 if (Version
.empty() == true)
250 if (MergeListPackage(List
, Pkg
) == false)
255 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
263 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
264 return _error
->Error(_("Wow, you exceeded the number of package "
265 "names this APT is capable of."));
266 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
267 return _error
->Error(_("Wow, you exceeded the number of versions "
268 "this APT is capable of."));
269 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
270 return _error
->Error(_("Wow, you exceeded the number of descriptions "
271 "this APT is capable of."));
272 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
273 return _error
->Error(_("Wow, you exceeded the number of dependencies "
274 "this APT is capable of."));
278 // CacheGenerator::MergeListGroup /*{{{*/
279 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
281 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
282 // a group has no data on it's own, only packages have it but these
283 // stanzas like this come from Translation- files to add descriptions,
284 // but without a version we don't need a description for it…
285 if (Grp
.end() == true)
287 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
289 pkgCache::PkgIterator Pkg
;
290 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
291 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
292 if (MergeListPackage(List
, Pkg
) == false)
298 // CacheGenerator::MergeListPackage /*{{{*/
299 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
301 // we first process the package, then the descriptions
302 // (for deb this package processing is in fact a no-op)
303 pkgCache::VerIterator
Ver(Cache
);
304 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
305 if (List
.UsePackage(Pkg
, Ver
) == false)
306 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
307 Pkg
.Name(), "UsePackage", 1);
309 // Find the right version to write the description
310 MD5SumValue CurMd5
= List
.Description_md5();
311 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
312 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
314 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
316 // a version can only have one md5 describing it
317 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
320 map_stringitem_t md5idx
= VerDesc
->md5sum
;
321 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
323 // don't add a new description if we have one for the given
325 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
328 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
331 // we can stop here as all "same" versions will share the description
338 // CacheGenerator::MergeListVersion /*{{{*/
339 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
340 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
342 pkgCache::VerIterator Ver
= Pkg
.VersionList();
343 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
344 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
345 void const * oldMap
= Map
.Data();
347 unsigned short const Hash
= List
.VersionHash();
348 if (Ver
.end() == false)
350 /* We know the list is sorted so we use that fact in the search.
351 Insertion of new versions is done with correct sorting */
353 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
355 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
356 // Version is higher as current version - insert here
359 // Versionstrings are equal - is hash also equal?
360 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
362 // proceed with the next till we have either the right
363 // or we found another version (which will be lower)
366 /* We already have a version for this item, record that we saw it */
367 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
369 if (List
.UsePackage(Pkg
,Ver
) == false)
370 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
371 Pkg
.Name(), "UsePackage", 2);
373 if (NewFileVer(Ver
,List
) == false)
374 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
375 Pkg
.Name(), "NewFileVer", 1);
377 // Read only a single record and return
389 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
390 if (unlikely(verindex
== 0))
391 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
392 Pkg
.Name(), "NewVersion", 1);
394 if (oldMap
!= Map
.Data())
395 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
398 if (unlikely(List
.NewVersion(Ver
) == false))
399 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
400 Pkg
.Name(), "NewVersion", 2);
402 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
403 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
404 Pkg
.Name(), "UsePackage", 3);
406 if (unlikely(NewFileVer(Ver
,List
) == false))
407 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
408 Pkg
.Name(), "NewFileVer", 2);
410 pkgCache::GrpIterator Grp
= Pkg
.Group();
411 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
413 /* If it is the first version of this package we need to add implicit
414 Multi-Arch dependencies to all other package versions in the group now -
415 otherwise we just add them for this new version */
416 if (Pkg
.VersionList()->NextVer
== 0)
418 pkgCache::PkgIterator P
= Grp
.PackageList();
419 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
420 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
422 if (P
->ID
== Pkg
->ID
)
424 pkgCache::VerIterator V
= P
.VersionList();
425 Dynamic
<pkgCache::VerIterator
> DynV(V
);
426 for (; V
.end() != true; ++V
)
427 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
428 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
429 Pkg
.Name(), "AddImplicitDepends", 1);
432 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
433 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
434 Pkg
.Name(), "AddImplicitDepends", 2);
436 // Read only a single record and return
443 /* Record the Description(s) based on their master md5sum */
444 MD5SumValue CurMd5
= List
.Description_md5();
446 /* Before we add a new description we first search in the group for
447 a version with a description of the same MD5 - if so we reuse this
448 description group instead of creating our own for this version */
449 for (pkgCache::PkgIterator P
= Grp
.PackageList();
450 P
.end() == false; P
= Grp
.NextPkg(P
))
452 for (pkgCache::VerIterator V
= P
.VersionList();
453 V
.end() == false; ++V
)
455 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
457 Ver
->DescriptionList
= V
->DescriptionList
;
461 // We haven't found reusable descriptions, so add the first description(s)
462 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
463 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
464 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
465 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
470 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
472 pkgCache::DescIterator Desc
;
473 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
475 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
476 if (unlikely(descindex
== 0))
477 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
478 Ver
.ParentPkg().Name(), "NewDescription", 1);
480 md5idx
= Desc
->md5sum
;
481 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
483 // we add at the end, so that the start is constant as we need
484 // that to be able to efficiently share these lists
485 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
486 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
487 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
488 *LastNextDesc
= descindex
;
490 if (NewFileDesc(Desc
,List
) == false)
491 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
492 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
498 // CacheGenerator::NewGroup - Add a new group /*{{{*/
499 // ---------------------------------------------------------------------
500 /* This creates a new group structure and adds it to the hash table */
501 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
503 Grp
= Cache
.FindGrp(Name
);
504 if (Grp
.end() == false)
508 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
509 if (unlikely(Group
== 0))
512 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
513 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
514 if (unlikely(idxName
== 0))
518 // Insert it into the hash table
519 unsigned long const Hash
= Cache
.Hash(Name
);
520 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
521 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
522 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
523 Grp
->Next
= *insertAt
;
526 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
530 // CacheGenerator::NewPackage - Add a new package /*{{{*/
531 // ---------------------------------------------------------------------
532 /* This creates a new package structure and adds it to the hash table */
533 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
535 pkgCache::GrpIterator Grp
;
536 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
537 if (unlikely(NewGroup(Grp
, Name
) == false))
540 Pkg
= Grp
.FindPkg(Arch
);
541 if (Pkg
.end() == false)
545 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
546 if (unlikely(Package
== 0))
548 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
550 // Set the name, arch and the ID
551 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
552 Pkg
->Group
= Grp
.Index();
553 // all is mapped to the native architecture
554 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
555 if (unlikely(idxArch
== 0))
558 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
560 // Insert the package into our package list
561 if (Grp
->FirstPackage
== 0) // the group is new
563 Grp
->FirstPackage
= Package
;
564 // Insert it into the hash table
565 map_id_t
const Hash
= Cache
.Hash(Name
);
566 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
567 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
568 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
569 Pkg
->NextPackage
= *insertAt
;
572 else // Group the Packages together
574 // but first get implicit provides done
575 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
577 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
578 if (M
.end() == false) {
579 pkgCache::PrvIterator Prv
;
580 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
581 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
583 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
585 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
586 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
587 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
588 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
589 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
590 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
596 pkgCache::PkgIterator P
;
597 pkgCache::VerIterator Ver
;
598 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
599 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
601 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
602 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
603 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
604 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
607 // and negative dependencies, don't forget negative dependencies
609 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
610 if (M
.end() == false) {
611 pkgCache::DepIterator Dep
;
612 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
613 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
615 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
617 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
618 Dep
->Type
!= pkgCache::Dep::Replaces
)
620 pkgCache::VerIterator Ver
= Dep
.ParentVer();
621 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
622 map_pointer_t
* unused
= NULL
;
623 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
629 // this package is the new last package
630 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
631 Pkg
->NextPackage
= LastPkg
->NextPackage
;
632 LastPkg
->NextPackage
= Package
;
634 Grp
->LastPackage
= Package
;
636 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
639 size_t const found
= Name
.find(':');
640 StringView
const NameA
= Name
.substr(0, found
);
641 StringView
const ArchA
= Name
.substr(found
+ 1);
642 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
643 if (PkgA
.end() == false)
645 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
646 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
647 for (; Prv
.end() == false; ++Prv
)
649 if (Prv
.IsMultiArchImplicit())
651 pkgCache::VerIterator V
= Prv
.OwnerVer();
652 if (ArchA
!= V
.ParentPkg().Arch())
654 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
657 pkgCache::VerIterator V
= PkgA
.VersionList();
658 Dynamic
<pkgCache::VerIterator
> DynV(V
);
659 for (; V
.end() == false; ++V
)
661 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
669 // CacheGenerator::AddImplicitDepends /*{{{*/
670 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
671 pkgCache::PkgIterator
&P
,
672 pkgCache::VerIterator
&V
)
674 // copy P.Arch() into a string here as a cache remap
675 // in NewDepends() later may alter the pointer location
676 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
677 map_pointer_t
*OldDepLast
= NULL
;
678 /* MultiArch handling introduces a lot of implicit Dependencies:
679 - MultiArch: same → Co-Installable if they have the same version
680 - All others conflict with all other group members */
681 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
682 pkgCache::PkgIterator D
= G
.PackageList();
683 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
684 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
685 for (; D
.end() != true; D
= G
.NextPkg(D
))
687 if (Arch
== D
.Arch() || D
->VersionList
== 0)
689 /* We allow only one installed arch at the time
690 per group, therefore each group member conflicts
691 with all other group members */
692 if (coInstall
== true)
694 // Replaces: ${self}:other ( << ${binary:Version})
695 NewDepends(D
, V
, VerStrIdx
,
696 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
698 // Breaks: ${self}:other (!= ${binary:Version})
699 NewDepends(D
, V
, VerStrIdx
,
700 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
703 // Conflicts: ${self}:other
705 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
711 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
712 pkgCache::PkgIterator
&D
)
714 /* MultiArch handling introduces a lot of implicit Dependencies:
715 - MultiArch: same → Co-Installable if they have the same version
716 - All others conflict with all other group members */
717 map_pointer_t
*OldDepLast
= NULL
;
718 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
719 if (coInstall
== true)
721 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
722 // Replaces: ${self}:other ( << ${binary:Version})
723 NewDepends(D
, V
, VerStrIdx
,
724 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
726 // Breaks: ${self}:other (!= ${binary:Version})
727 NewDepends(D
, V
, VerStrIdx
,
728 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
731 // Conflicts: ${self}:other
733 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
740 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
741 // ---------------------------------------------------------------------
743 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
746 if (CurrentFile
== 0)
750 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
754 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
755 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
757 // Link it to the end of the list
758 map_pointer_t
*Last
= &Ver
->FileList
;
759 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
761 VF
->NextFile
= *Last
;
764 VF
->Offset
= List
.Offset();
765 VF
->Size
= List
.Size();
766 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
767 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
768 Cache
.HeaderP
->VerFileCount
++;
773 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
774 // ---------------------------------------------------------------------
775 /* This puts a version structure in the linked list */
776 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
777 const string
&VerStr
,
778 map_pointer_t
const ParentPkg
,
779 unsigned short const Hash
,
780 map_pointer_t
const Next
)
783 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
788 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
789 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
791 Ver
->ParentPkg
= ParentPkg
;
793 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
795 // try to find the version string in the group for reuse
796 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
797 pkgCache::GrpIterator Grp
= Pkg
.Group();
798 if (Pkg
.end() == false && Grp
.end() == false)
800 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
804 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
806 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
809 Ver
->VerStr
= V
->VerStr
;
817 // haven't found the version string, so create
818 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
819 if (unlikely(idxVerStr
== 0))
821 Ver
->VerStr
= idxVerStr
;
825 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
826 // ---------------------------------------------------------------------
828 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
831 if (CurrentFile
== 0)
835 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
839 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
840 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
842 // Link it to the end of the list
843 map_pointer_t
*Last
= &Desc
->FileList
;
844 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
847 DF
->NextFile
= *Last
;
850 DF
->Offset
= List
.Offset();
851 DF
->Size
= List
.Size();
852 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
853 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
854 Cache
.HeaderP
->DescFileCount
++;
859 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
860 // ---------------------------------------------------------------------
861 /* This puts a description structure in the linked list */
862 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
864 const MD5SumValue
&md5sum
,
865 map_stringitem_t
const idxmd5str
)
868 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
869 if (Description
== 0)
873 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
874 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
875 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
876 if (unlikely(idxlanguage_code
== 0))
878 Desc
->language_code
= idxlanguage_code
;
881 Desc
->md5sum
= idxmd5str
;
884 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
885 if (unlikely(idxmd5sum
== 0))
887 Desc
->md5sum
= idxmd5sum
;
893 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
894 // ---------------------------------------------------------------------
895 /* This creates a dependency element in the tree. It is linked to the
896 version and to the package that it is pointing to. */
897 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
898 pkgCache::VerIterator
&Ver
,
899 map_pointer_t
const Version
,
902 map_pointer_t
* &OldDepLast
)
904 void const * const oldMap
= Map
.Data();
906 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
907 if (unlikely(Dependency
== 0))
910 bool isDuplicate
= false;
911 map_pointer_t DependencyData
= 0;
912 map_pointer_t PreviousData
= 0;
913 if (Pkg
->RevDepends
!= 0)
915 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
916 DependencyData
= L
->DependencyData
;
918 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
919 if (Version
> D
->Version
)
921 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
926 PreviousData
= DependencyData
;
927 DependencyData
= D
->NextData
;
928 } while (DependencyData
!= 0);
931 if (isDuplicate
== false)
933 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
934 if (unlikely(DependencyData
== 0))
938 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
939 Link
->ParentVer
= Ver
.Index();
940 Link
->DependencyData
= DependencyData
;
941 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
943 pkgCache::DepIterator
Dep(Cache
, Link
);
944 if (isDuplicate
== false)
948 Dep
->Version
= Version
;
949 Dep
->Package
= Pkg
.Index();
950 ++Cache
.HeaderP
->DependsDataCount
;
951 if (PreviousData
!= 0)
953 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
954 Dep
->NextData
= D
->NextData
;
955 D
->NextData
= DependencyData
;
957 else if (Pkg
->RevDepends
!= 0)
959 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
960 Dep
->NextData
= D
->DependencyData
;
964 if (isDuplicate
== true || PreviousData
!= 0)
966 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
967 Link
->NextRevDepends
= L
->NextRevDepends
;
968 L
->NextRevDepends
= Dependency
;
972 Link
->NextRevDepends
= Pkg
->RevDepends
;
973 Pkg
->RevDepends
= Dependency
;
977 // Do we know where to link the Dependency to?
978 if (OldDepLast
== NULL
)
980 OldDepLast
= &Ver
->DependsList
;
981 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
982 OldDepLast
= &D
->NextDepends
;
983 } else if (oldMap
!= Map
.Data())
984 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
986 Dep
->NextDepends
= *OldDepLast
;
987 *OldDepLast
= Dependency
;
988 OldDepLast
= &Dep
->NextDepends
;
992 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
993 // ---------------------------------------------------------------------
994 /* This creates a Group and the Package to link this dependency to if
995 needed and handles also the caching of the old endpoint */
996 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
997 StringView PackageName
,
1003 pkgCache::GrpIterator Grp
;
1004 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1005 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1008 map_stringitem_t idxVersion
= 0;
1009 if (Version
.empty() == false)
1011 int const CmpOp
= Op
& 0x0F;
1012 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1013 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1014 idxVersion
= Ver
->VerStr
;
1016 if (idxVersion
== 0)
1018 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1019 if (unlikely(idxVersion
== 0))
1024 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1025 Type
== pkgCache::Dep::Conflicts
||
1026 Type
== pkgCache::Dep::Replaces
);
1028 pkgCache::PkgIterator Pkg
;
1029 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1030 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1032 // Locate the target package
1033 Pkg
= Grp
.FindPkg(Arch
);
1034 if (Pkg
.end() == true) {
1035 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1039 /* Caching the old end point speeds up generation substantially */
1040 if (OldDepVer
!= Ver
) {
1045 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1049 /* Caching the old end point speeds up generation substantially */
1050 if (OldDepVer
!= Ver
) {
1055 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1057 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1064 // ListParser::NewProvides - Create a Provides element /*{{{*/
1065 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1069 uint8_t const Flags
)
1071 pkgCache
const &Cache
= Owner
->Cache
;
1073 // We do not add self referencing provides
1074 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1075 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1076 (Version
.empty() || Version
== Ver
.VerStr()))
1079 // Locate the target package
1080 pkgCache::PkgIterator Pkg
;
1081 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1082 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1085 map_stringitem_t idxProvideVersion
= 0;
1086 if (Version
.empty() == false) {
1087 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1088 if (unlikely(idxProvideVersion
== 0))
1091 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1093 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1094 pkgCache::PkgIterator
&Pkg
,
1095 map_pointer_t
const ProvideVersion
,
1096 uint8_t const Flags
)
1099 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1100 if (unlikely(Provides
== 0))
1102 ++Cache
.HeaderP
->ProvidesCount
;
1105 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1106 Prv
->Version
= Ver
.Index();
1107 Prv
->ProvideVersion
= ProvideVersion
;
1109 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1110 Ver
->ProvidesList
= Prv
.Index();
1112 // Link it to the package
1113 Prv
->ParentPkg
= Pkg
.Index();
1114 Prv
->NextProvides
= Pkg
->ProvidesList
;
1115 Pkg
->ProvidesList
= Prv
.Index();
1119 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1120 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1121 StringView Version
, uint8_t const Flags
) {
1122 pkgCache
&Cache
= Owner
->Cache
;
1123 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1124 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1126 if (Grp
.end() == true)
1127 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1130 map_stringitem_t idxProvideVersion
= 0;
1131 if (Version
.empty() == false) {
1132 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1133 if (unlikely(idxProvideVersion
== 0))
1137 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1138 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1139 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1140 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1141 pkgCache::PkgIterator Pkg
;
1142 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1143 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1145 if (isImplicit
&& OwnerPkg
== Pkg
)
1147 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1149 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1156 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1157 pkgCache::VerIterator
const &Ver
)
1159 return Hash
== Ver
->Hash
;
1162 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1163 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1164 unsigned long Flags
)
1166 if (File
.empty() && Site
.empty())
1168 CurrentRlsFile
= NULL
;
1172 // Get some space for the structure
1173 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1174 if (unlikely(idxFile
== 0))
1176 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1179 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1180 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1181 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1183 CurrentRlsFile
->FileName
= idxFileName
;
1184 CurrentRlsFile
->Site
= idxSite
;
1185 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1186 CurrentRlsFile
->Flags
= Flags
;
1187 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1189 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1190 Cache
.HeaderP
->ReleaseFileCount
++;
1195 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1196 // ---------------------------------------------------------------------
1197 /* This is used to select which file is to be associated with all newly
1198 added versions. The caller is responsible for setting the IMS fields. */
1199 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1200 pkgIndexFile
const &Index
,
1201 std::string
const &Architecture
,
1202 std::string
const &Component
,
1203 unsigned long const Flags
)
1205 // Get some space for the structure
1206 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1207 if (unlikely(idxFile
== 0))
1209 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1212 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1213 if (unlikely(idxFileName
== 0))
1215 CurrentFile
->FileName
= idxFileName
;
1216 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1217 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1218 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1219 if (unlikely(idxIndexType
== 0))
1221 CurrentFile
->IndexType
= idxIndexType
;
1222 if (Architecture
.empty())
1223 CurrentFile
->Architecture
= 0;
1226 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1227 if (unlikely(arch
== 0))
1229 CurrentFile
->Architecture
= arch
;
1231 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1232 if (unlikely(component
== 0))
1234 CurrentFile
->Component
= component
;
1235 CurrentFile
->Flags
= Flags
;
1236 if (CurrentRlsFile
!= NULL
)
1237 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1239 CurrentFile
->Release
= 0;
1241 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1242 Cache
.HeaderP
->PackageFileCount
++;
1245 Progress
->SubProgress(Index
.Size());
1249 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1250 // ---------------------------------------------------------------------
1251 /* This is used to create handles to strings. Given the same text it
1252 always returns the same number */
1253 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1256 auto strings
= &strMixed
;
1258 case MIXED
: strings
= &strMixed
; break;
1259 case PKGNAME
: strings
= &strPkgNames
; break;
1260 case VERSIONNUMBER
: strings
= &strVersions
; break;
1261 case SECTION
: strings
= &strSections
; break;
1262 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1265 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1266 if (item
!= strings
->end())
1269 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1270 strings
->insert({nullptr, Size
, this, idxString
});
1274 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1275 // ---------------------------------------------------------------------
1276 /* This just verifies that each file in the list of index files exists,
1277 has matching attributes with the cache and the cache does not have
1279 class APT_HIDDEN ScopedErrorRevert
{
1281 ScopedErrorRevert() { _error
->PushToStack(); }
1282 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1284 static bool CheckValidity(const string
&CacheFile
,
1285 pkgSourceList
&List
,
1286 FileIterator
const Start
,
1287 FileIterator
const End
,
1289 pkgCache
**OutCache
= 0)
1291 ScopedErrorRevert ser
;
1292 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1293 // No file, certainly invalid
1294 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1297 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1301 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1304 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1309 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1310 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1311 if (unlikely(Map
->validData()) == false)
1313 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1314 pkgCache
&Cache
= *CacheP
.get();
1315 if (_error
->PendingError() || Map
->Size() == 0)
1318 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1322 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1323 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1324 std::vector
<pkgIndexFile
*> Files
;
1325 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1328 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1329 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1330 if (RlsFile
.end() == true)
1333 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1337 RlsVisited
[RlsFile
->ID
] = true;
1339 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1341 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1342 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1343 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1345 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1346 if (RlsVisited
[I
] == false)
1349 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1353 std::copy(Start
, End
, std::back_inserter(Files
));
1355 /* Now we check every index file, see if it is in the cache,
1356 verify the IMS data and check that it is on the disk too.. */
1357 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1358 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1359 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1362 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1363 if ((*PkgFile
)->Exists() == false)
1366 std::clog
<< "file doesn't exist" << std::endl
;
1370 // FindInCache is also expected to do an IMS check.
1371 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1372 if (File
.end() == true)
1375 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1379 Visited
[File
->ID
] = true;
1381 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1384 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1385 if (Visited
[I
] == false)
1388 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1392 if (_error
->PendingError() == true)
1396 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1397 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1403 *OutMap
= Map
.release();
1405 *OutCache
= CacheP
.release();
1409 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1410 // ---------------------------------------------------------------------
1411 /* Size is kind of an abstract notion that is only used for the progress
1413 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1415 map_filesize_t TotalSize
= 0;
1418 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1420 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1421 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1422 if ((*j
)->HasPackages() == true)
1423 TotalSize
+= (*j
)->Size();
1427 for (; Start
< End
; ++Start
)
1429 if ((*Start
)->HasPackages() == false)
1431 TotalSize
+= (*Start
)->Size();
1436 // BuildCache - Merge the list of index files into the cache /*{{{*/
1437 static bool BuildCache(pkgCacheGenerator
&Gen
,
1438 OpProgress
* const Progress
,
1439 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1440 pkgSourceList
const * const List
,
1441 FileIterator
const Start
, FileIterator
const End
)
1443 bool mergeFailure
= false;
1445 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1446 if (I
->HasPackages() == false || mergeFailure
)
1449 if (I
->Exists() == false)
1452 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1454 _error
->Warning("Duplicate sources.list entry %s",
1455 I
->Describe().c_str());
1459 map_filesize_t
const Size
= I
->Size();
1460 if (Progress
!= NULL
)
1461 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1462 CurrentSize
+= Size
;
1464 if (I
->Merge(Gen
,Progress
) == false)
1465 mergeFailure
= true;
1470 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1472 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1474 _error
->Warning("Duplicate sources.list entry %s",
1475 (*i
)->Describe().c_str());
1479 if ((*i
)->Merge(Gen
, Progress
) == false)
1482 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1483 if (Indexes
!= NULL
)
1484 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1492 Gen
.SelectReleaseFile("", "");
1493 std::for_each(Start
, End
, indexFileMerge
);
1500 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1501 // ---------------------------------------------------------------------
1502 /* This makes sure that the status cache (the cache that has all
1503 index files from the sources list and all local ones) is ready
1504 to be mmaped. If OutMap is not zero then a MMap object representing
1505 the cache will be stored there. This is pretty much mandetory if you
1506 are using AllowMem. AllowMem lets the function be run as non-root
1507 where it builds the cache 'fast' into a memory buffer. */
1508 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1510 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1511 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1512 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1513 Flags
|= MMap::Moveable
;
1514 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1515 Flags
|= MMap::Fallback
;
1517 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1519 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1521 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1522 std::string
const &FileName
)
1524 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1525 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1528 fchmod(SCacheF
.Fd(),0644);
1530 // Write out the main data
1531 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1532 return _error
->Error(_("IO Error saving source cache"));
1534 // Write out the proper header
1535 Gen
->GetCache().HeaderP
->Dirty
= false;
1536 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1537 if (SCacheF
.Seek(0) == false ||
1538 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1539 return _error
->Error(_("IO Error saving source cache"));
1540 Gen
->GetCache().HeaderP
->Dirty
= true;
1543 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1544 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1546 Map
.reset(CreateDynamicMMap(NULL
, 0));
1547 if (unlikely(Map
->validData()) == false)
1549 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1550 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1552 _error
->PushToStack();
1553 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1554 bool const newError
= _error
->PendingError();
1555 _error
->MergeWithStack();
1556 if (alloc
== 0 && newError
)
1558 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1560 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1563 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1564 MMap
**OutMap
, bool AllowMem
)
1565 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1566 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1569 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1571 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1572 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1574 // FIXME: deprecate the ignored AllowMem parameter
1575 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1577 std::vector
<pkgIndexFile
*> Files
;
1578 if (_system
->AddStatusFiles(Files
) == false)
1581 // Decide if we can write to the files..
1582 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1583 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1585 // ensure the cache directory exists
1586 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1588 string dir
= _config
->FindDir("Dir::Cache");
1589 size_t const len
= dir
.size();
1590 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1591 dir
= dir
.substr(0, len
- 5);
1592 if (CacheFile
.empty() == false)
1593 CreateDirectory(dir
, flNotFile(CacheFile
));
1594 if (SrcCacheFile
.empty() == false)
1595 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1598 if (Progress
!= NULL
)
1599 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1601 bool pkgcache_fine
= false;
1602 bool srcpkgcache_fine
= false;
1603 bool volatile_fine
= List
.GetVolatileFiles().empty();
1605 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1606 volatile_fine
? OutCache
: NULL
) == true)
1609 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1610 pkgcache_fine
= true;
1611 srcpkgcache_fine
= true;
1613 if (pkgcache_fine
== false)
1615 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1618 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1619 srcpkgcache_fine
= true;
1623 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1625 if (Progress
!= NULL
)
1626 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1630 bool Writeable
= false;
1631 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1633 if (CacheFile
.empty() == false)
1634 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1635 else if (SrcCacheFile
.empty() == false)
1636 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1639 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1642 // At this point we know we need to construct something, so get storage ready
1643 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1644 if (unlikely(Map
->validData()) == false)
1647 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1649 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1650 map_filesize_t CurrentSize
= 0;
1651 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1652 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1653 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1656 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1657 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1659 srcpkgcache_fine
= true;
1660 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1662 else if (srcpkgcache_fine
== false)
1665 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1666 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1668 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1669 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1670 Files
.end(),Files
.end()) == false)
1673 if (Writeable
== true && SrcCacheFile
.empty() == false)
1674 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1678 if (pkgcache_fine
== false)
1681 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1682 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1683 Files
.begin(), Files
.end()) == false)
1686 if (Writeable
== true && CacheFile
.empty() == false)
1687 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1692 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1694 if (volatile_fine
== false)
1699 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1700 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1704 Files
= List
.GetVolatileFiles();
1705 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1706 Files
.begin(), Files
.end()) == false)
1710 if (OutMap
!= nullptr)
1711 *OutMap
= Map
.release();
1714 std::clog
<< "Everything is ready for shipping" << std::endl
;
1718 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1719 class APT_HIDDEN ScopedErrorMerge
{
1721 ScopedErrorMerge() { _error
->PushToStack(); }
1722 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1724 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1725 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1726 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1728 std::vector
<pkgIndexFile
*> Files
;
1729 if (_system
->AddStatusFiles(Files
) == false)
1732 ScopedErrorMerge sem
;
1733 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1734 if (unlikely(Map
->validData()) == false)
1736 map_filesize_t CurrentSize
= 0;
1737 map_filesize_t TotalSize
= 0;
1738 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1740 // Build the status cache
1741 if (Progress
!= NULL
)
1742 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1743 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1744 if (_error
->PendingError() == true)
1746 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1747 Files
.begin(), Files
.end()) == false)
1750 if (_error
->PendingError() == true)
1752 *OutMap
= Map
.release();
1757 // IsDuplicateDescription /*{{{*/
1758 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1759 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1761 // Descriptions in the same link-list have all the same md5
1762 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1764 for (; Desc
.end() == false; ++Desc
)
1765 if (Desc
.LanguageCode() == CurLang
)
1771 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1772 pkgCacheListParser::~pkgCacheListParser() {}