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 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
313 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
314 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
316 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
318 // a version can only have one md5 describing it
319 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
322 map_stringitem_t md5idx
= VerDesc
->md5sum
;
323 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
325 // don't add a new description if we have one for the given
327 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
330 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
333 // we can stop here as all "same" versions will share the description
340 // CacheGenerator::MergeListVersion /*{{{*/
341 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
342 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
344 pkgCache::VerIterator Ver
= Pkg
.VersionList();
345 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
346 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
347 void const * oldMap
= Map
.Data();
349 unsigned short const Hash
= List
.VersionHash();
350 if (Ver
.end() == false)
352 /* We know the list is sorted so we use that fact in the search.
353 Insertion of new versions is done with correct sorting */
355 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
357 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
358 // Version is higher as current version - insert here
361 // Versionstrings are equal - is hash also equal?
362 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
364 // proceed with the next till we have either the right
365 // or we found another version (which will be lower)
368 /* We already have a version for this item, record that we saw it */
369 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
371 if (List
.UsePackage(Pkg
,Ver
) == false)
372 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
373 Pkg
.Name(), "UsePackage", 2);
375 if (NewFileVer(Ver
,List
) == false)
376 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
377 Pkg
.Name(), "NewFileVer", 1);
379 // Read only a single record and return
391 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
392 if (unlikely(verindex
== 0))
393 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
394 Pkg
.Name(), "NewVersion", 1);
396 if (oldMap
!= Map
.Data())
397 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
400 if (unlikely(List
.NewVersion(Ver
) == false))
401 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
402 Pkg
.Name(), "NewVersion", 2);
404 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
405 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
406 Pkg
.Name(), "UsePackage", 3);
408 if (unlikely(NewFileVer(Ver
,List
) == false))
409 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
410 Pkg
.Name(), "NewFileVer", 2);
412 pkgCache::GrpIterator Grp
= Pkg
.Group();
413 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
415 /* If it is the first version of this package we need to add implicit
416 Multi-Arch dependencies to all other package versions in the group now -
417 otherwise we just add them for this new version */
418 if (Pkg
.VersionList()->NextVer
== 0)
420 pkgCache::PkgIterator P
= Grp
.PackageList();
421 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
422 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
424 if (P
->ID
== Pkg
->ID
)
426 pkgCache::VerIterator V
= P
.VersionList();
427 Dynamic
<pkgCache::VerIterator
> DynV(V
);
428 for (; V
.end() != true; ++V
)
429 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
430 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
431 Pkg
.Name(), "AddImplicitDepends", 1);
434 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
435 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
436 Pkg
.Name(), "AddImplicitDepends", 2);
438 // Read only a single record and return
445 /* Record the Description(s) based on their master md5sum */
446 MD5SumValue CurMd5
= List
.Description_md5();
447 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
450 /* Before we add a new description we first search in the group for
451 a version with a description of the same MD5 - if so we reuse this
452 description group instead of creating our own for this version */
453 for (pkgCache::PkgIterator P
= Grp
.PackageList();
454 P
.end() == false; P
= Grp
.NextPkg(P
))
456 for (pkgCache::VerIterator V
= P
.VersionList();
457 V
.end() == false; ++V
)
459 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
461 Ver
->DescriptionList
= V
->DescriptionList
;
465 // We haven't found reusable descriptions, so add the first description(s)
466 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
467 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
468 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
469 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
474 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
476 pkgCache::DescIterator Desc
;
477 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
479 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
480 if (unlikely(descindex
== 0))
481 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
482 Ver
.ParentPkg().Name(), "NewDescription", 1);
484 md5idx
= Desc
->md5sum
;
485 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
487 // we add at the end, so that the start is constant as we need
488 // that to be able to efficiently share these lists
489 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
490 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
491 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
492 *LastNextDesc
= descindex
;
494 if (NewFileDesc(Desc
,List
) == false)
495 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
496 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
502 // CacheGenerator::NewGroup - Add a new group /*{{{*/
503 // ---------------------------------------------------------------------
504 /* This creates a new group structure and adds it to the hash table */
505 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
507 Grp
= Cache
.FindGrp(Name
);
508 if (Grp
.end() == false)
512 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
513 if (unlikely(Group
== 0))
516 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
517 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
518 if (unlikely(idxName
== 0))
522 // Insert it into the hash table
523 unsigned long const Hash
= Cache
.Hash(Name
);
524 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
525 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
526 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
527 Grp
->Next
= *insertAt
;
530 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
534 // CacheGenerator::NewPackage - Add a new package /*{{{*/
535 // ---------------------------------------------------------------------
536 /* This creates a new package structure and adds it to the hash table */
537 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
539 pkgCache::GrpIterator Grp
;
540 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
541 if (unlikely(NewGroup(Grp
, Name
) == false))
544 Pkg
= Grp
.FindPkg(Arch
);
545 if (Pkg
.end() == false)
549 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
550 if (unlikely(Package
== 0))
552 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
554 // Set the name, arch and the ID
555 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
556 Pkg
->Group
= Grp
.Index();
557 // all is mapped to the native architecture
558 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
559 if (unlikely(idxArch
== 0))
562 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
564 // Insert the package into our package list
565 if (Grp
->FirstPackage
== 0) // the group is new
567 Grp
->FirstPackage
= Package
;
568 // Insert it into the hash table
569 map_id_t
const Hash
= Cache
.Hash(Name
);
570 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
571 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
572 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
573 Pkg
->NextPackage
= *insertAt
;
576 else // Group the Packages together
578 // but first get implicit provides done
579 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
581 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
582 if (M
.end() == false) {
583 pkgCache::PrvIterator Prv
;
584 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
585 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
587 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
589 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
590 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
591 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
592 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
593 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
594 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
600 pkgCache::PkgIterator P
;
601 pkgCache::VerIterator Ver
;
602 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
603 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
605 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
606 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
607 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
608 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
611 // and negative dependencies, don't forget negative dependencies
613 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
614 if (M
.end() == false) {
615 pkgCache::DepIterator Dep
;
616 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
617 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
619 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
621 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
622 Dep
->Type
!= pkgCache::Dep::Replaces
)
624 pkgCache::VerIterator Ver
= Dep
.ParentVer();
625 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
626 map_pointer_t
* unused
= NULL
;
627 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
633 // this package is the new last package
634 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
635 Pkg
->NextPackage
= LastPkg
->NextPackage
;
636 LastPkg
->NextPackage
= Package
;
638 Grp
->LastPackage
= Package
;
640 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
643 size_t const found
= Name
.find(':');
644 StringView
const NameA
= Name
.substr(0, found
);
645 StringView
const ArchA
= Name
.substr(found
+ 1);
646 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
647 if (PkgA
.end() == false)
649 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
650 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
651 for (; Prv
.end() == false; ++Prv
)
653 if (Prv
.IsMultiArchImplicit())
655 pkgCache::VerIterator V
= Prv
.OwnerVer();
656 if (ArchA
!= V
.ParentPkg().Arch())
658 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
661 pkgCache::VerIterator V
= PkgA
.VersionList();
662 Dynamic
<pkgCache::VerIterator
> DynV(V
);
663 for (; V
.end() == false; ++V
)
665 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
673 // CacheGenerator::AddImplicitDepends /*{{{*/
674 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
675 pkgCache::PkgIterator
&P
,
676 pkgCache::VerIterator
&V
)
678 // copy P.Arch() into a string here as a cache remap
679 // in NewDepends() later may alter the pointer location
680 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
681 map_pointer_t
*OldDepLast
= NULL
;
682 /* MultiArch handling introduces a lot of implicit Dependencies:
683 - MultiArch: same → Co-Installable if they have the same version
684 - All others conflict with all other group members */
685 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
686 pkgCache::PkgIterator D
= G
.PackageList();
687 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
688 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
689 for (; D
.end() != true; D
= G
.NextPkg(D
))
691 if (Arch
== D
.Arch() || D
->VersionList
== 0)
693 /* We allow only one installed arch at the time
694 per group, therefore each group member conflicts
695 with all other group members */
696 if (coInstall
== true)
698 // Replaces: ${self}:other ( << ${binary:Version})
699 NewDepends(D
, V
, VerStrIdx
,
700 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
702 // Breaks: ${self}:other (!= ${binary:Version})
703 NewDepends(D
, V
, VerStrIdx
,
704 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
707 // Conflicts: ${self}:other
709 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
715 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
716 pkgCache::PkgIterator
&D
)
718 /* MultiArch handling introduces a lot of implicit Dependencies:
719 - MultiArch: same → Co-Installable if they have the same version
720 - All others conflict with all other group members */
721 map_pointer_t
*OldDepLast
= NULL
;
722 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
723 if (coInstall
== true)
725 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
726 // Replaces: ${self}:other ( << ${binary:Version})
727 NewDepends(D
, V
, VerStrIdx
,
728 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
730 // Breaks: ${self}:other (!= ${binary:Version})
731 NewDepends(D
, V
, VerStrIdx
,
732 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
735 // Conflicts: ${self}:other
737 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
744 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
745 // ---------------------------------------------------------------------
747 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
750 if (CurrentFile
== 0)
754 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
758 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
759 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
761 // Link it to the end of the list
762 map_pointer_t
*Last
= &Ver
->FileList
;
763 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
765 VF
->NextFile
= *Last
;
768 VF
->Offset
= List
.Offset();
769 VF
->Size
= List
.Size();
770 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
771 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
772 Cache
.HeaderP
->VerFileCount
++;
777 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
778 // ---------------------------------------------------------------------
779 /* This puts a version structure in the linked list */
780 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
781 const string
&VerStr
,
782 map_pointer_t
const ParentPkg
,
783 unsigned short const Hash
,
784 map_pointer_t
const Next
)
787 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
792 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
793 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
795 Ver
->ParentPkg
= ParentPkg
;
797 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
799 // try to find the version string in the group for reuse
800 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
801 pkgCache::GrpIterator Grp
= Pkg
.Group();
802 if (Pkg
.end() == false && Grp
.end() == false)
804 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
808 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
810 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
813 Ver
->VerStr
= V
->VerStr
;
821 // haven't found the version string, so create
822 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
823 if (unlikely(idxVerStr
== 0))
825 Ver
->VerStr
= idxVerStr
;
829 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
830 // ---------------------------------------------------------------------
832 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
835 if (CurrentFile
== 0)
839 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
843 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
844 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
846 // Link it to the end of the list
847 map_pointer_t
*Last
= &Desc
->FileList
;
848 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
851 DF
->NextFile
= *Last
;
854 DF
->Offset
= List
.Offset();
855 DF
->Size
= List
.Size();
856 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
857 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
858 Cache
.HeaderP
->DescFileCount
++;
863 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
864 // ---------------------------------------------------------------------
865 /* This puts a description structure in the linked list */
866 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
868 const MD5SumValue
&md5sum
,
869 map_stringitem_t
const idxmd5str
)
872 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
873 if (Description
== 0)
877 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
878 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
879 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
880 if (unlikely(idxlanguage_code
== 0))
882 Desc
->language_code
= idxlanguage_code
;
885 Desc
->md5sum
= idxmd5str
;
888 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
889 if (unlikely(idxmd5sum
== 0))
891 Desc
->md5sum
= idxmd5sum
;
897 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
898 // ---------------------------------------------------------------------
899 /* This creates a dependency element in the tree. It is linked to the
900 version and to the package that it is pointing to. */
901 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
902 pkgCache::VerIterator
&Ver
,
903 map_pointer_t
const Version
,
906 map_pointer_t
* &OldDepLast
)
908 void const * const oldMap
= Map
.Data();
910 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
911 if (unlikely(Dependency
== 0))
914 bool isDuplicate
= false;
915 map_pointer_t DependencyData
= 0;
916 map_pointer_t PreviousData
= 0;
917 if (Pkg
->RevDepends
!= 0)
919 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
920 DependencyData
= L
->DependencyData
;
922 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
923 if (Version
> D
->Version
)
925 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
930 PreviousData
= DependencyData
;
931 DependencyData
= D
->NextData
;
932 } while (DependencyData
!= 0);
935 if (isDuplicate
== false)
937 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
938 if (unlikely(DependencyData
== 0))
942 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
943 Link
->ParentVer
= Ver
.Index();
944 Link
->DependencyData
= DependencyData
;
945 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
947 pkgCache::DepIterator
Dep(Cache
, Link
);
948 if (isDuplicate
== false)
952 Dep
->Version
= Version
;
953 Dep
->Package
= Pkg
.Index();
954 ++Cache
.HeaderP
->DependsDataCount
;
955 if (PreviousData
!= 0)
957 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
958 Dep
->NextData
= D
->NextData
;
959 D
->NextData
= DependencyData
;
961 else if (Pkg
->RevDepends
!= 0)
963 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
964 Dep
->NextData
= D
->DependencyData
;
968 if (isDuplicate
== true || PreviousData
!= 0)
970 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
971 Link
->NextRevDepends
= L
->NextRevDepends
;
972 L
->NextRevDepends
= Dependency
;
976 Link
->NextRevDepends
= Pkg
->RevDepends
;
977 Pkg
->RevDepends
= Dependency
;
981 // Do we know where to link the Dependency to?
982 if (OldDepLast
== NULL
)
984 OldDepLast
= &Ver
->DependsList
;
985 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
986 OldDepLast
= &D
->NextDepends
;
987 } else if (oldMap
!= Map
.Data())
988 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
990 Dep
->NextDepends
= *OldDepLast
;
991 *OldDepLast
= Dependency
;
992 OldDepLast
= &Dep
->NextDepends
;
996 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
997 // ---------------------------------------------------------------------
998 /* This creates a Group and the Package to link this dependency to if
999 needed and handles also the caching of the old endpoint */
1000 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1001 StringView PackageName
,
1007 pkgCache::GrpIterator Grp
;
1008 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1009 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1012 map_stringitem_t idxVersion
= 0;
1013 if (Version
.empty() == false)
1015 int const CmpOp
= Op
& 0x0F;
1016 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1017 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1018 idxVersion
= Ver
->VerStr
;
1020 if (idxVersion
== 0)
1022 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1023 if (unlikely(idxVersion
== 0))
1028 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1029 Type
== pkgCache::Dep::Conflicts
||
1030 Type
== pkgCache::Dep::Replaces
);
1032 pkgCache::PkgIterator Pkg
;
1033 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1034 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1036 // Locate the target package
1037 Pkg
= Grp
.FindPkg(Arch
);
1038 if (Pkg
.end() == true) {
1039 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1043 /* Caching the old end point speeds up generation substantially */
1044 if (OldDepVer
!= Ver
) {
1049 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1053 /* Caching the old end point speeds up generation substantially */
1054 if (OldDepVer
!= Ver
) {
1059 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1061 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1068 // ListParser::NewProvides - Create a Provides element /*{{{*/
1069 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1073 uint8_t const Flags
)
1075 pkgCache
const &Cache
= Owner
->Cache
;
1077 // We do not add self referencing provides
1078 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1079 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1080 (Version
.empty() || Version
== Ver
.VerStr()))
1083 // Locate the target package
1084 pkgCache::PkgIterator Pkg
;
1085 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1086 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1089 map_stringitem_t idxProvideVersion
= 0;
1090 if (Version
.empty() == false) {
1091 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1092 if (unlikely(idxProvideVersion
== 0))
1095 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1097 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1098 pkgCache::PkgIterator
&Pkg
,
1099 map_pointer_t
const ProvideVersion
,
1100 uint8_t const Flags
)
1103 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1104 if (unlikely(Provides
== 0))
1106 ++Cache
.HeaderP
->ProvidesCount
;
1109 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1110 Prv
->Version
= Ver
.Index();
1111 Prv
->ProvideVersion
= ProvideVersion
;
1113 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1114 Ver
->ProvidesList
= Prv
.Index();
1116 // Link it to the package
1117 Prv
->ParentPkg
= Pkg
.Index();
1118 Prv
->NextProvides
= Pkg
->ProvidesList
;
1119 Pkg
->ProvidesList
= Prv
.Index();
1123 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1124 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1125 StringView Version
, uint8_t const Flags
) {
1126 pkgCache
&Cache
= Owner
->Cache
;
1127 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1128 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1130 if (Grp
.end() == true)
1131 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1134 map_stringitem_t idxProvideVersion
= 0;
1135 if (Version
.empty() == false) {
1136 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1137 if (unlikely(idxProvideVersion
== 0))
1141 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1142 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1143 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1144 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1145 pkgCache::PkgIterator Pkg
;
1146 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1147 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1149 if (isImplicit
&& OwnerPkg
== Pkg
)
1151 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1153 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1160 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1161 pkgCache::VerIterator
const &Ver
)
1163 return Hash
== Ver
->Hash
;
1166 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1167 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1168 unsigned long Flags
)
1170 if (File
.empty() && Site
.empty())
1172 CurrentRlsFile
= NULL
;
1176 // Get some space for the structure
1177 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1178 if (unlikely(idxFile
== 0))
1180 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1183 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1184 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1185 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1187 CurrentRlsFile
->FileName
= idxFileName
;
1188 CurrentRlsFile
->Site
= idxSite
;
1189 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1190 CurrentRlsFile
->Flags
= Flags
;
1191 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1193 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1194 Cache
.HeaderP
->ReleaseFileCount
++;
1199 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1200 // ---------------------------------------------------------------------
1201 /* This is used to select which file is to be associated with all newly
1202 added versions. The caller is responsible for setting the IMS fields. */
1203 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1204 pkgIndexFile
const &Index
,
1205 std::string
const &Architecture
,
1206 std::string
const &Component
,
1207 unsigned long const Flags
)
1209 // Get some space for the structure
1210 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1211 if (unlikely(idxFile
== 0))
1213 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1216 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1217 if (unlikely(idxFileName
== 0))
1219 CurrentFile
->FileName
= idxFileName
;
1220 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1221 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1222 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1223 if (unlikely(idxIndexType
== 0))
1225 CurrentFile
->IndexType
= idxIndexType
;
1226 if (Architecture
.empty())
1227 CurrentFile
->Architecture
= 0;
1230 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1231 if (unlikely(arch
== 0))
1233 CurrentFile
->Architecture
= arch
;
1235 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1236 if (unlikely(component
== 0))
1238 CurrentFile
->Component
= component
;
1239 CurrentFile
->Flags
= Flags
;
1240 if (CurrentRlsFile
!= NULL
)
1241 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1243 CurrentFile
->Release
= 0;
1245 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1246 Cache
.HeaderP
->PackageFileCount
++;
1249 Progress
->SubProgress(Index
.Size());
1253 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1254 // ---------------------------------------------------------------------
1255 /* This is used to create handles to strings. Given the same text it
1256 always returns the same number */
1257 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1260 auto strings
= &strMixed
;
1262 case MIXED
: strings
= &strMixed
; break;
1263 case PKGNAME
: strings
= &strPkgNames
; break;
1264 case VERSIONNUMBER
: strings
= &strVersions
; break;
1265 case SECTION
: strings
= &strSections
; break;
1266 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1269 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1270 if (item
!= strings
->end())
1273 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1274 strings
->insert({nullptr, Size
, this, idxString
});
1278 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1279 // ---------------------------------------------------------------------
1280 /* This just verifies that each file in the list of index files exists,
1281 has matching attributes with the cache and the cache does not have
1283 class APT_HIDDEN ScopedErrorRevert
{
1285 ScopedErrorRevert() { _error
->PushToStack(); }
1286 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1288 static bool CheckValidity(const string
&CacheFile
,
1289 pkgSourceList
&List
,
1290 FileIterator
const Start
,
1291 FileIterator
const End
,
1293 pkgCache
**OutCache
= 0)
1295 ScopedErrorRevert ser
;
1296 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1297 // No file, certainly invalid
1298 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1301 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1305 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1308 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1313 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1314 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1315 if (unlikely(Map
->validData()) == false)
1317 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1318 pkgCache
&Cache
= *CacheP
.get();
1319 if (_error
->PendingError() || Map
->Size() == 0)
1322 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1326 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1327 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1328 std::vector
<pkgIndexFile
*> Files
;
1329 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1332 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1333 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1334 if (RlsFile
.end() == true)
1337 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1341 RlsVisited
[RlsFile
->ID
] = true;
1343 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1345 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1346 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1347 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1349 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1350 if (RlsVisited
[I
] == false)
1353 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1357 std::copy(Start
, End
, std::back_inserter(Files
));
1359 /* Now we check every index file, see if it is in the cache,
1360 verify the IMS data and check that it is on the disk too.. */
1361 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1362 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1363 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1366 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1367 if ((*PkgFile
)->Exists() == false)
1370 std::clog
<< "file doesn't exist" << std::endl
;
1374 // FindInCache is also expected to do an IMS check.
1375 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1376 if (File
.end() == true)
1379 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1383 Visited
[File
->ID
] = true;
1385 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1388 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1389 if (Visited
[I
] == false)
1392 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1396 if (_error
->PendingError() == true)
1400 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1401 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1407 *OutMap
= Map
.release();
1409 *OutCache
= CacheP
.release();
1413 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1414 // ---------------------------------------------------------------------
1415 /* Size is kind of an abstract notion that is only used for the progress
1417 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1419 map_filesize_t TotalSize
= 0;
1422 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1424 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1425 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1426 if ((*j
)->HasPackages() == true)
1427 TotalSize
+= (*j
)->Size();
1431 for (; Start
< End
; ++Start
)
1433 if ((*Start
)->HasPackages() == false)
1435 TotalSize
+= (*Start
)->Size();
1440 // BuildCache - Merge the list of index files into the cache /*{{{*/
1441 static bool BuildCache(pkgCacheGenerator
&Gen
,
1442 OpProgress
* const Progress
,
1443 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1444 pkgSourceList
const * const List
,
1445 FileIterator
const Start
, FileIterator
const End
)
1447 bool mergeFailure
= false;
1449 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1450 if (I
->HasPackages() == false || mergeFailure
)
1453 if (I
->Exists() == false)
1456 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1458 _error
->Warning("Duplicate sources.list entry %s",
1459 I
->Describe().c_str());
1463 map_filesize_t
const Size
= I
->Size();
1464 if (Progress
!= NULL
)
1465 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1466 CurrentSize
+= Size
;
1468 if (I
->Merge(Gen
,Progress
) == false)
1469 mergeFailure
= true;
1474 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1476 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1478 _error
->Warning("Duplicate sources.list entry %s",
1479 (*i
)->Describe().c_str());
1483 if ((*i
)->Merge(Gen
, Progress
) == false)
1486 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1487 if (Indexes
!= NULL
)
1488 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1496 Gen
.SelectReleaseFile("", "");
1497 std::for_each(Start
, End
, indexFileMerge
);
1504 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1505 // ---------------------------------------------------------------------
1506 /* This makes sure that the status cache (the cache that has all
1507 index files from the sources list and all local ones) is ready
1508 to be mmaped. If OutMap is not zero then a MMap object representing
1509 the cache will be stored there. This is pretty much mandetory if you
1510 are using AllowMem. AllowMem lets the function be run as non-root
1511 where it builds the cache 'fast' into a memory buffer. */
1512 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1514 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1515 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1516 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1517 Flags
|= MMap::Moveable
;
1518 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1519 Flags
|= MMap::Fallback
;
1521 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1523 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1525 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1526 std::string
const &FileName
)
1528 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1529 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1532 fchmod(SCacheF
.Fd(),0644);
1534 // Write out the main data
1535 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1536 return _error
->Error(_("IO Error saving source cache"));
1538 // Write out the proper header
1539 Gen
->GetCache().HeaderP
->Dirty
= false;
1540 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1541 if (SCacheF
.Seek(0) == false ||
1542 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1543 return _error
->Error(_("IO Error saving source cache"));
1544 Gen
->GetCache().HeaderP
->Dirty
= true;
1547 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1548 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1550 Map
.reset(CreateDynamicMMap(NULL
, 0));
1551 if (unlikely(Map
->validData()) == false)
1553 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1554 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1556 _error
->PushToStack();
1557 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1558 bool const newError
= _error
->PendingError();
1559 _error
->MergeWithStack();
1560 if (alloc
== 0 && newError
)
1562 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1564 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1567 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1568 MMap
**OutMap
, bool AllowMem
)
1569 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1570 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1573 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1575 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1576 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1578 // FIXME: deprecate the ignored AllowMem parameter
1579 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1581 std::vector
<pkgIndexFile
*> Files
;
1582 if (_system
->AddStatusFiles(Files
) == false)
1585 // Decide if we can write to the files..
1586 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1587 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1589 // ensure the cache directory exists
1590 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1592 string dir
= _config
->FindDir("Dir::Cache");
1593 size_t const len
= dir
.size();
1594 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1595 dir
= dir
.substr(0, len
- 5);
1596 if (CacheFile
.empty() == false)
1597 CreateDirectory(dir
, flNotFile(CacheFile
));
1598 if (SrcCacheFile
.empty() == false)
1599 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1602 if (Progress
!= NULL
)
1603 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1605 bool pkgcache_fine
= false;
1606 bool srcpkgcache_fine
= false;
1607 bool volatile_fine
= List
.GetVolatileFiles().empty();
1609 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1610 volatile_fine
? OutCache
: NULL
) == true)
1613 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1614 pkgcache_fine
= true;
1615 srcpkgcache_fine
= true;
1617 if (pkgcache_fine
== false)
1619 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1622 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1623 srcpkgcache_fine
= true;
1627 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1629 if (Progress
!= NULL
)
1630 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1634 bool Writeable
= false;
1635 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1637 if (CacheFile
.empty() == false)
1638 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1639 else if (SrcCacheFile
.empty() == false)
1640 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1643 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1646 // At this point we know we need to construct something, so get storage ready
1647 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1648 if (unlikely(Map
->validData()) == false)
1651 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1653 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1654 map_filesize_t CurrentSize
= 0;
1655 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1656 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1657 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1660 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1661 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1663 srcpkgcache_fine
= true;
1664 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1666 else if (srcpkgcache_fine
== false)
1669 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1670 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1672 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1673 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1674 Files
.end(),Files
.end()) == false)
1677 if (Writeable
== true && SrcCacheFile
.empty() == false)
1678 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1682 if (pkgcache_fine
== false)
1685 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1686 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1687 Files
.begin(), Files
.end()) == false)
1690 if (Writeable
== true && CacheFile
.empty() == false)
1691 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1696 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1698 if (volatile_fine
== false)
1703 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1704 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1708 Files
= List
.GetVolatileFiles();
1709 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1710 Files
.begin(), Files
.end()) == false)
1714 if (OutMap
!= nullptr)
1715 *OutMap
= Map
.release();
1718 std::clog
<< "Everything is ready for shipping" << std::endl
;
1722 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1723 class APT_HIDDEN ScopedErrorMerge
{
1725 ScopedErrorMerge() { _error
->PushToStack(); }
1726 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1728 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1729 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1730 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1732 std::vector
<pkgIndexFile
*> Files
;
1733 if (_system
->AddStatusFiles(Files
) == false)
1736 ScopedErrorMerge sem
;
1737 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1738 if (unlikely(Map
->validData()) == false)
1740 map_filesize_t CurrentSize
= 0;
1741 map_filesize_t TotalSize
= 0;
1742 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1744 // Build the status cache
1745 if (Progress
!= NULL
)
1746 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1747 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1748 if (_error
->PendingError() == true)
1750 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1751 Files
.begin(), Files
.end()) == false)
1754 if (_error
->PendingError() == true)
1756 *OutMap
= Map
.release();
1761 // IsDuplicateDescription /*{{{*/
1762 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1763 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1765 // Descriptions in the same link-list have all the same md5
1766 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1768 for (; Desc
.end() == false; ++Desc
)
1769 if (Desc
.LanguageCode() == CurLang
)
1775 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1776 pkgCacheListParser::~pkgCacheListParser() {}