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
];
522 while (*insertAt
!= 0 && Name
.compare(Cache
.ViewString((Cache
.GrpP
+ *insertAt
)->Name
)) > 0)
523 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
524 Grp
->Next
= *insertAt
;
527 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
531 // CacheGenerator::NewPackage - Add a new package /*{{{*/
532 // ---------------------------------------------------------------------
533 /* This creates a new package structure and adds it to the hash table */
534 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
536 pkgCache::GrpIterator Grp
;
537 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
538 if (unlikely(NewGroup(Grp
, Name
) == false))
541 Pkg
= Grp
.FindPkg(Arch
);
542 if (Pkg
.end() == false)
546 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
547 if (unlikely(Package
== 0))
549 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
551 // Set the name, arch and the ID
552 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
553 Pkg
->Group
= Grp
.Index();
554 // all is mapped to the native architecture
555 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
556 if (unlikely(idxArch
== 0))
559 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
561 // Insert the package into our package list
562 if (Grp
->FirstPackage
== 0) // the group is new
564 Grp
->FirstPackage
= Package
;
565 // Insert it into the hash table
566 map_id_t
const Hash
= Cache
.Hash(Name
);
567 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
568 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
569 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
570 Pkg
->NextPackage
= *insertAt
;
573 else // Group the Packages together
575 // but first get implicit provides done
576 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
578 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
579 if (M
.end() == false) {
580 pkgCache::PrvIterator Prv
;
581 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
582 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
584 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
586 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
587 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
588 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
589 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
590 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
591 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
597 pkgCache::PkgIterator P
;
598 pkgCache::VerIterator Ver
;
599 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
600 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
602 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
603 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
604 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
605 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
608 // and negative dependencies, don't forget negative dependencies
610 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
611 if (M
.end() == false) {
612 pkgCache::DepIterator Dep
;
613 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
614 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
616 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
618 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
619 Dep
->Type
!= pkgCache::Dep::Replaces
)
621 pkgCache::VerIterator Ver
= Dep
.ParentVer();
622 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
623 map_pointer_t
* unused
= NULL
;
624 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
630 // this package is the new last package
631 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
632 Pkg
->NextPackage
= LastPkg
->NextPackage
;
633 LastPkg
->NextPackage
= Package
;
635 Grp
->LastPackage
= Package
;
637 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
640 size_t const found
= Name
.find(':');
641 StringView
const NameA
= Name
.substr(0, found
);
642 StringView
const ArchA
= Name
.substr(found
+ 1);
643 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
644 if (PkgA
.end() == false)
646 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
647 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
648 for (; Prv
.end() == false; ++Prv
)
650 if (Prv
.IsMultiArchImplicit())
652 pkgCache::VerIterator V
= Prv
.OwnerVer();
653 if (ArchA
!= V
.ParentPkg().Arch())
655 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
658 pkgCache::VerIterator V
= PkgA
.VersionList();
659 Dynamic
<pkgCache::VerIterator
> DynV(V
);
660 for (; V
.end() == false; ++V
)
662 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
670 // CacheGenerator::AddImplicitDepends /*{{{*/
671 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
672 pkgCache::PkgIterator
&P
,
673 pkgCache::VerIterator
&V
)
675 // copy P.Arch() into a string here as a cache remap
676 // in NewDepends() later may alter the pointer location
677 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
678 map_pointer_t
*OldDepLast
= NULL
;
679 /* MultiArch handling introduces a lot of implicit Dependencies:
680 - MultiArch: same → Co-Installable if they have the same version
681 - All others conflict with all other group members */
682 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
683 pkgCache::PkgIterator D
= G
.PackageList();
684 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
685 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
686 for (; D
.end() != true; D
= G
.NextPkg(D
))
688 if (Arch
== D
.Arch() || D
->VersionList
== 0)
690 /* We allow only one installed arch at the time
691 per group, therefore each group member conflicts
692 with all other group members */
693 if (coInstall
== true)
695 // Replaces: ${self}:other ( << ${binary:Version})
696 NewDepends(D
, V
, VerStrIdx
,
697 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
699 // Breaks: ${self}:other (!= ${binary:Version})
700 NewDepends(D
, V
, VerStrIdx
,
701 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
704 // Conflicts: ${self}:other
706 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
712 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
713 pkgCache::PkgIterator
&D
)
715 /* MultiArch handling introduces a lot of implicit Dependencies:
716 - MultiArch: same → Co-Installable if they have the same version
717 - All others conflict with all other group members */
718 map_pointer_t
*OldDepLast
= NULL
;
719 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
720 if (coInstall
== true)
722 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
723 // Replaces: ${self}:other ( << ${binary:Version})
724 NewDepends(D
, V
, VerStrIdx
,
725 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
727 // Breaks: ${self}:other (!= ${binary:Version})
728 NewDepends(D
, V
, VerStrIdx
,
729 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
732 // Conflicts: ${self}:other
734 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
741 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
742 // ---------------------------------------------------------------------
744 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
747 if (CurrentFile
== 0)
751 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
755 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
756 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
758 // Link it to the end of the list
759 map_pointer_t
*Last
= &Ver
->FileList
;
760 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
762 VF
->NextFile
= *Last
;
765 VF
->Offset
= List
.Offset();
766 VF
->Size
= List
.Size();
767 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
768 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
769 Cache
.HeaderP
->VerFileCount
++;
774 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
775 // ---------------------------------------------------------------------
776 /* This puts a version structure in the linked list */
777 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
778 const string
&VerStr
,
779 map_pointer_t
const ParentPkg
,
780 unsigned short const Hash
,
781 map_pointer_t
const Next
)
784 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
789 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
790 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
792 Ver
->ParentPkg
= ParentPkg
;
794 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
796 // try to find the version string in the group for reuse
797 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
798 pkgCache::GrpIterator Grp
= Pkg
.Group();
799 if (Pkg
.end() == false && Grp
.end() == false)
801 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
805 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
807 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
810 Ver
->VerStr
= V
->VerStr
;
818 // haven't found the version string, so create
819 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
820 if (unlikely(idxVerStr
== 0))
822 Ver
->VerStr
= idxVerStr
;
826 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
827 // ---------------------------------------------------------------------
829 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
832 if (CurrentFile
== 0)
836 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
840 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
841 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
843 // Link it to the end of the list
844 map_pointer_t
*Last
= &Desc
->FileList
;
845 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
848 DF
->NextFile
= *Last
;
851 DF
->Offset
= List
.Offset();
852 DF
->Size
= List
.Size();
853 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
854 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
855 Cache
.HeaderP
->DescFileCount
++;
860 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
861 // ---------------------------------------------------------------------
862 /* This puts a description structure in the linked list */
863 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
865 const MD5SumValue
&md5sum
,
866 map_stringitem_t
const idxmd5str
)
869 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
870 if (Description
== 0)
874 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
875 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
876 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
877 if (unlikely(idxlanguage_code
== 0))
879 Desc
->language_code
= idxlanguage_code
;
882 Desc
->md5sum
= idxmd5str
;
885 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
886 if (unlikely(idxmd5sum
== 0))
888 Desc
->md5sum
= idxmd5sum
;
894 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
895 // ---------------------------------------------------------------------
896 /* This creates a dependency element in the tree. It is linked to the
897 version and to the package that it is pointing to. */
898 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
899 pkgCache::VerIterator
&Ver
,
900 map_pointer_t
const Version
,
903 map_pointer_t
* &OldDepLast
)
905 void const * const oldMap
= Map
.Data();
907 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
908 if (unlikely(Dependency
== 0))
911 bool isDuplicate
= false;
912 map_pointer_t DependencyData
= 0;
913 map_pointer_t PreviousData
= 0;
914 if (Pkg
->RevDepends
!= 0)
916 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
917 DependencyData
= L
->DependencyData
;
919 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
920 if (Version
> D
->Version
)
922 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
927 PreviousData
= DependencyData
;
928 DependencyData
= D
->NextData
;
929 } while (DependencyData
!= 0);
932 if (isDuplicate
== false)
934 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
935 if (unlikely(DependencyData
== 0))
939 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
940 Link
->ParentVer
= Ver
.Index();
941 Link
->DependencyData
= DependencyData
;
942 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
944 pkgCache::DepIterator
Dep(Cache
, Link
);
945 if (isDuplicate
== false)
949 Dep
->Version
= Version
;
950 Dep
->Package
= Pkg
.Index();
951 ++Cache
.HeaderP
->DependsDataCount
;
952 if (PreviousData
!= 0)
954 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
955 Dep
->NextData
= D
->NextData
;
956 D
->NextData
= DependencyData
;
958 else if (Pkg
->RevDepends
!= 0)
960 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
961 Dep
->NextData
= D
->DependencyData
;
965 if (isDuplicate
== true || PreviousData
!= 0)
967 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
968 Link
->NextRevDepends
= L
->NextRevDepends
;
969 L
->NextRevDepends
= Dependency
;
973 Link
->NextRevDepends
= Pkg
->RevDepends
;
974 Pkg
->RevDepends
= Dependency
;
978 // Do we know where to link the Dependency to?
979 if (OldDepLast
== NULL
)
981 OldDepLast
= &Ver
->DependsList
;
982 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
983 OldDepLast
= &D
->NextDepends
;
984 } else if (oldMap
!= Map
.Data())
985 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
987 Dep
->NextDepends
= *OldDepLast
;
988 *OldDepLast
= Dependency
;
989 OldDepLast
= &Dep
->NextDepends
;
993 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
994 // ---------------------------------------------------------------------
995 /* This creates a Group and the Package to link this dependency to if
996 needed and handles also the caching of the old endpoint */
997 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
998 StringView PackageName
,
1004 pkgCache::GrpIterator Grp
;
1005 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1006 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1009 map_stringitem_t idxVersion
= 0;
1010 if (Version
.empty() == false)
1012 int const CmpOp
= Op
& 0x0F;
1013 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1014 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1015 idxVersion
= Ver
->VerStr
;
1017 if (idxVersion
== 0)
1019 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1020 if (unlikely(idxVersion
== 0))
1025 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1026 Type
== pkgCache::Dep::Conflicts
||
1027 Type
== pkgCache::Dep::Replaces
);
1029 pkgCache::PkgIterator Pkg
;
1030 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1031 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1033 // Locate the target package
1034 Pkg
= Grp
.FindPkg(Arch
);
1035 if (Pkg
.end() == true) {
1036 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1040 /* Caching the old end point speeds up generation substantially */
1041 if (OldDepVer
!= Ver
) {
1046 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1050 /* Caching the old end point speeds up generation substantially */
1051 if (OldDepVer
!= Ver
) {
1056 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1058 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1065 // ListParser::NewProvides - Create a Provides element /*{{{*/
1066 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1070 uint8_t const Flags
)
1072 pkgCache
const &Cache
= Owner
->Cache
;
1074 // We do not add self referencing provides
1075 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1076 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1077 (Version
.empty() || Version
== Ver
.VerStr()))
1080 // Locate the target package
1081 pkgCache::PkgIterator Pkg
;
1082 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1083 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1086 map_stringitem_t idxProvideVersion
= 0;
1087 if (Version
.empty() == false) {
1088 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1089 if (unlikely(idxProvideVersion
== 0))
1092 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1094 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1095 pkgCache::PkgIterator
&Pkg
,
1096 map_pointer_t
const ProvideVersion
,
1097 uint8_t const Flags
)
1100 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1101 if (unlikely(Provides
== 0))
1103 ++Cache
.HeaderP
->ProvidesCount
;
1106 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1107 Prv
->Version
= Ver
.Index();
1108 Prv
->ProvideVersion
= ProvideVersion
;
1110 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1111 Ver
->ProvidesList
= Prv
.Index();
1113 // Link it to the package
1114 Prv
->ParentPkg
= Pkg
.Index();
1115 Prv
->NextProvides
= Pkg
->ProvidesList
;
1116 Pkg
->ProvidesList
= Prv
.Index();
1120 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1121 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1122 StringView Version
, uint8_t const Flags
) {
1123 pkgCache
&Cache
= Owner
->Cache
;
1124 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1125 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1127 if (Grp
.end() == true)
1128 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1131 map_stringitem_t idxProvideVersion
= 0;
1132 if (Version
.empty() == false) {
1133 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1134 if (unlikely(idxProvideVersion
== 0))
1138 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1139 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1140 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1141 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1142 pkgCache::PkgIterator Pkg
;
1143 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1144 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1146 if (isImplicit
&& OwnerPkg
== Pkg
)
1148 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1150 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1157 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1158 pkgCache::VerIterator
const &Ver
)
1160 return Hash
== Ver
->Hash
;
1163 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1164 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1165 unsigned long Flags
)
1167 if (File
.empty() && Site
.empty())
1169 CurrentRlsFile
= NULL
;
1173 // Get some space for the structure
1174 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1175 if (unlikely(idxFile
== 0))
1177 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1180 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1181 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1182 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1184 CurrentRlsFile
->FileName
= idxFileName
;
1185 CurrentRlsFile
->Site
= idxSite
;
1186 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1187 CurrentRlsFile
->Flags
= Flags
;
1188 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1190 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1191 Cache
.HeaderP
->ReleaseFileCount
++;
1196 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1197 // ---------------------------------------------------------------------
1198 /* This is used to select which file is to be associated with all newly
1199 added versions. The caller is responsible for setting the IMS fields. */
1200 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1201 pkgIndexFile
const &Index
,
1202 std::string
const &Architecture
,
1203 std::string
const &Component
,
1204 unsigned long const Flags
)
1206 // Get some space for the structure
1207 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1208 if (unlikely(idxFile
== 0))
1210 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1213 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1214 if (unlikely(idxFileName
== 0))
1216 CurrentFile
->FileName
= idxFileName
;
1217 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1218 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1219 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1220 if (unlikely(idxIndexType
== 0))
1222 CurrentFile
->IndexType
= idxIndexType
;
1223 if (Architecture
.empty())
1224 CurrentFile
->Architecture
= 0;
1227 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1228 if (unlikely(arch
== 0))
1230 CurrentFile
->Architecture
= arch
;
1232 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1233 if (unlikely(component
== 0))
1235 CurrentFile
->Component
= component
;
1236 CurrentFile
->Flags
= Flags
;
1237 if (CurrentRlsFile
!= NULL
)
1238 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1240 CurrentFile
->Release
= 0;
1242 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1243 Cache
.HeaderP
->PackageFileCount
++;
1246 Progress
->SubProgress(Index
.Size());
1250 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1251 // ---------------------------------------------------------------------
1252 /* This is used to create handles to strings. Given the same text it
1253 always returns the same number */
1254 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1257 auto strings
= &strMixed
;
1259 case MIXED
: strings
= &strMixed
; break;
1260 case PKGNAME
: strings
= &strPkgNames
; break;
1261 case VERSIONNUMBER
: strings
= &strVersions
; break;
1262 case SECTION
: strings
= &strSections
; break;
1263 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1266 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1267 if (item
!= strings
->end())
1270 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1271 strings
->insert({nullptr, Size
, this, idxString
});
1275 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1276 // ---------------------------------------------------------------------
1277 /* This just verifies that each file in the list of index files exists,
1278 has matching attributes with the cache and the cache does not have
1280 class APT_HIDDEN ScopedErrorRevert
{
1282 ScopedErrorRevert() { _error
->PushToStack(); }
1283 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1285 static bool CheckValidity(const string
&CacheFile
,
1286 pkgSourceList
&List
,
1287 FileIterator
const Start
,
1288 FileIterator
const End
,
1290 pkgCache
**OutCache
= 0)
1292 ScopedErrorRevert ser
;
1293 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1294 // No file, certainly invalid
1295 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1298 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1302 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1305 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1310 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1311 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1312 if (unlikely(Map
->validData()) == false)
1314 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1315 pkgCache
&Cache
= *CacheP
.get();
1316 if (_error
->PendingError() || Map
->Size() == 0)
1319 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1323 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1324 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1325 std::vector
<pkgIndexFile
*> Files
;
1326 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1329 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1330 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1331 if (RlsFile
.end() == true)
1334 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1338 RlsVisited
[RlsFile
->ID
] = true;
1340 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1342 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1343 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1344 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1346 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1347 if (RlsVisited
[I
] == false)
1350 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1354 std::copy(Start
, End
, std::back_inserter(Files
));
1356 /* Now we check every index file, see if it is in the cache,
1357 verify the IMS data and check that it is on the disk too.. */
1358 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1359 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1360 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1363 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1364 if ((*PkgFile
)->Exists() == false)
1367 std::clog
<< "file doesn't exist" << std::endl
;
1371 // FindInCache is also expected to do an IMS check.
1372 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1373 if (File
.end() == true)
1376 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1380 Visited
[File
->ID
] = true;
1382 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1385 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1386 if (Visited
[I
] == false)
1389 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1393 if (_error
->PendingError() == true)
1397 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1398 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1404 *OutMap
= Map
.release();
1406 *OutCache
= CacheP
.release();
1410 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1411 // ---------------------------------------------------------------------
1412 /* Size is kind of an abstract notion that is only used for the progress
1414 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1416 map_filesize_t TotalSize
= 0;
1419 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1421 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1422 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1423 if ((*j
)->HasPackages() == true)
1424 TotalSize
+= (*j
)->Size();
1428 for (; Start
< End
; ++Start
)
1430 if ((*Start
)->HasPackages() == false)
1432 TotalSize
+= (*Start
)->Size();
1437 // BuildCache - Merge the list of index files into the cache /*{{{*/
1438 static bool BuildCache(pkgCacheGenerator
&Gen
,
1439 OpProgress
* const Progress
,
1440 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1441 pkgSourceList
const * const List
,
1442 FileIterator
const Start
, FileIterator
const End
)
1444 bool mergeFailure
= false;
1446 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1447 if (I
->HasPackages() == false || mergeFailure
)
1450 if (I
->Exists() == false)
1453 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1455 _error
->Warning("Duplicate sources.list entry %s",
1456 I
->Describe().c_str());
1460 map_filesize_t
const Size
= I
->Size();
1461 if (Progress
!= NULL
)
1462 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1463 CurrentSize
+= Size
;
1465 if (I
->Merge(Gen
,Progress
) == false)
1466 mergeFailure
= true;
1471 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1473 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1475 _error
->Warning("Duplicate sources.list entry %s",
1476 (*i
)->Describe().c_str());
1480 if ((*i
)->Merge(Gen
, Progress
) == false)
1483 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1484 if (Indexes
!= NULL
)
1485 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1493 Gen
.SelectReleaseFile("", "");
1494 std::for_each(Start
, End
, indexFileMerge
);
1501 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1502 // ---------------------------------------------------------------------
1503 /* This makes sure that the status cache (the cache that has all
1504 index files from the sources list and all local ones) is ready
1505 to be mmaped. If OutMap is not zero then a MMap object representing
1506 the cache will be stored there. This is pretty much mandetory if you
1507 are using AllowMem. AllowMem lets the function be run as non-root
1508 where it builds the cache 'fast' into a memory buffer. */
1509 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1511 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1512 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1513 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1514 Flags
|= MMap::Moveable
;
1515 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1516 Flags
|= MMap::Fallback
;
1518 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1520 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1522 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1523 std::string
const &FileName
)
1525 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1526 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1529 fchmod(SCacheF
.Fd(),0644);
1531 // Write out the main data
1532 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1533 return _error
->Error(_("IO Error saving source cache"));
1535 // Write out the proper header
1536 Gen
->GetCache().HeaderP
->Dirty
= false;
1537 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1538 if (SCacheF
.Seek(0) == false ||
1539 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1540 return _error
->Error(_("IO Error saving source cache"));
1541 Gen
->GetCache().HeaderP
->Dirty
= true;
1544 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1545 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1547 Map
.reset(CreateDynamicMMap(NULL
, 0));
1548 if (unlikely(Map
->validData()) == false)
1550 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1551 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1553 _error
->PushToStack();
1554 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1555 bool const newError
= _error
->PendingError();
1556 _error
->MergeWithStack();
1557 if (alloc
== 0 && newError
)
1559 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1561 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1564 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1565 MMap
**OutMap
, bool AllowMem
)
1566 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1567 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1570 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1572 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1573 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1575 // FIXME: deprecate the ignored AllowMem parameter
1576 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1578 std::vector
<pkgIndexFile
*> Files
;
1579 if (_system
->AddStatusFiles(Files
) == false)
1582 // Decide if we can write to the files..
1583 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1584 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1586 // ensure the cache directory exists
1587 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1589 string dir
= _config
->FindDir("Dir::Cache");
1590 size_t const len
= dir
.size();
1591 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1592 dir
= dir
.substr(0, len
- 5);
1593 if (CacheFile
.empty() == false)
1594 CreateDirectory(dir
, flNotFile(CacheFile
));
1595 if (SrcCacheFile
.empty() == false)
1596 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1599 if (Progress
!= NULL
)
1600 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1602 bool pkgcache_fine
= false;
1603 bool srcpkgcache_fine
= false;
1604 bool volatile_fine
= List
.GetVolatileFiles().empty();
1606 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1607 volatile_fine
? OutCache
: NULL
) == true)
1610 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1611 pkgcache_fine
= true;
1612 srcpkgcache_fine
= true;
1614 if (pkgcache_fine
== false)
1616 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1619 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1620 srcpkgcache_fine
= true;
1624 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1626 if (Progress
!= NULL
)
1627 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1631 bool Writeable
= false;
1632 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1634 if (CacheFile
.empty() == false)
1635 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1636 else if (SrcCacheFile
.empty() == false)
1637 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1640 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1643 // At this point we know we need to construct something, so get storage ready
1644 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1645 if (unlikely(Map
->validData()) == false)
1648 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1650 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1651 map_filesize_t CurrentSize
= 0;
1652 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1653 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1654 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1657 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1658 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1660 srcpkgcache_fine
= true;
1661 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1663 else if (srcpkgcache_fine
== false)
1666 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1667 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1669 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1670 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1671 Files
.end(),Files
.end()) == false)
1674 if (Writeable
== true && SrcCacheFile
.empty() == false)
1675 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1679 if (pkgcache_fine
== false)
1682 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1683 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1684 Files
.begin(), Files
.end()) == false)
1687 if (Writeable
== true && CacheFile
.empty() == false)
1688 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1693 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1695 if (volatile_fine
== false)
1700 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1701 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1705 Files
= List
.GetVolatileFiles();
1706 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1707 Files
.begin(), Files
.end()) == false)
1711 if (OutMap
!= nullptr)
1712 *OutMap
= Map
.release();
1715 std::clog
<< "Everything is ready for shipping" << std::endl
;
1719 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1720 class APT_HIDDEN ScopedErrorMerge
{
1722 ScopedErrorMerge() { _error
->PushToStack(); }
1723 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1725 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1726 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1727 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1729 std::vector
<pkgIndexFile
*> Files
;
1730 if (_system
->AddStatusFiles(Files
) == false)
1733 ScopedErrorMerge sem
;
1734 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1735 if (unlikely(Map
->validData()) == false)
1737 map_filesize_t CurrentSize
= 0;
1738 map_filesize_t TotalSize
= 0;
1739 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1741 // Build the status cache
1742 if (Progress
!= NULL
)
1743 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1744 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1745 if (_error
->PendingError() == true)
1747 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1748 Files
.begin(), Files
.end()) == false)
1751 if (_error
->PendingError() == true)
1753 *OutMap
= Map
.release();
1758 // IsDuplicateDescription /*{{{*/
1759 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1760 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1762 // Descriptions in the same link-list have all the same md5
1763 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1765 for (; Desc
.end() == false; ++Desc
)
1766 if (Desc
.LanguageCode() == CurLang
)
1772 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1773 pkgCacheListParser::~pkgCacheListParser() {}