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
.compare(Ver
.VerStr()) == 0)
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 std::string
key(S
, Size
);
1262 std::unordered_map
<std::string
,map_stringitem_t
> * strings
;
1264 case MIXED
: strings
= &strMixed
; break;
1265 case PKGNAME
: strings
= &strPkgNames
; break;
1266 case VERSIONNUMBER
: strings
= &strVersions
; break;
1267 case SECTION
: strings
= &strSections
; break;
1268 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1271 std::unordered_map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1272 if (item
!= strings
->end())
1273 return item
->second
;
1275 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1276 strings
->insert(std::make_pair(std::move(key
), idxString
));
1280 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1281 // ---------------------------------------------------------------------
1282 /* This just verifies that each file in the list of index files exists,
1283 has matching attributes with the cache and the cache does not have
1285 class APT_HIDDEN ScopedErrorRevert
{
1287 ScopedErrorRevert() { _error
->PushToStack(); }
1288 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1290 static bool CheckValidity(const string
&CacheFile
,
1291 pkgSourceList
&List
,
1292 FileIterator
const Start
,
1293 FileIterator
const End
,
1295 pkgCache
**OutCache
= 0)
1297 ScopedErrorRevert ser
;
1298 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1299 // No file, certainly invalid
1300 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1303 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1307 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1310 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1315 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1316 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1317 if (unlikely(Map
->validData()) == false)
1319 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1320 pkgCache
&Cache
= *CacheP
.get();
1321 if (_error
->PendingError() || Map
->Size() == 0)
1324 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1328 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1329 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1330 std::vector
<pkgIndexFile
*> Files
;
1331 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1334 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1335 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1336 if (RlsFile
.end() == true)
1339 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1343 RlsVisited
[RlsFile
->ID
] = true;
1345 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1347 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1348 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1349 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1351 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1352 if (RlsVisited
[I
] == false)
1355 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1359 std::copy(Start
, End
, std::back_inserter(Files
));
1361 /* Now we check every index file, see if it is in the cache,
1362 verify the IMS data and check that it is on the disk too.. */
1363 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1364 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1365 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1368 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1369 if ((*PkgFile
)->Exists() == false)
1372 std::clog
<< "file doesn't exist" << std::endl
;
1376 // FindInCache is also expected to do an IMS check.
1377 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1378 if (File
.end() == true)
1381 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1385 Visited
[File
->ID
] = true;
1387 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1390 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1391 if (Visited
[I
] == false)
1394 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1398 if (_error
->PendingError() == true)
1402 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1403 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1409 *OutMap
= Map
.release();
1411 *OutCache
= CacheP
.release();
1415 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1416 // ---------------------------------------------------------------------
1417 /* Size is kind of an abstract notion that is only used for the progress
1419 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1421 map_filesize_t TotalSize
= 0;
1424 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1426 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1427 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1428 if ((*j
)->HasPackages() == true)
1429 TotalSize
+= (*j
)->Size();
1433 for (; Start
< End
; ++Start
)
1435 if ((*Start
)->HasPackages() == false)
1437 TotalSize
+= (*Start
)->Size();
1442 // BuildCache - Merge the list of index files into the cache /*{{{*/
1443 static bool BuildCache(pkgCacheGenerator
&Gen
,
1444 OpProgress
* const Progress
,
1445 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1446 pkgSourceList
const * const List
,
1447 FileIterator
const Start
, FileIterator
const End
)
1449 bool mergeFailure
= false;
1451 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1452 if (I
->HasPackages() == false || mergeFailure
)
1455 if (I
->Exists() == false)
1458 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1460 _error
->Warning("Duplicate sources.list entry %s",
1461 I
->Describe().c_str());
1465 map_filesize_t
const Size
= I
->Size();
1466 if (Progress
!= NULL
)
1467 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1468 CurrentSize
+= Size
;
1470 if (I
->Merge(Gen
,Progress
) == false)
1471 mergeFailure
= true;
1476 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1478 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1480 _error
->Warning("Duplicate sources.list entry %s",
1481 (*i
)->Describe().c_str());
1485 if ((*i
)->Merge(Gen
, Progress
) == false)
1488 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1489 if (Indexes
!= NULL
)
1490 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1498 Gen
.SelectReleaseFile("", "");
1499 std::for_each(Start
, End
, indexFileMerge
);
1506 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1507 // ---------------------------------------------------------------------
1508 /* This makes sure that the status cache (the cache that has all
1509 index files from the sources list and all local ones) is ready
1510 to be mmaped. If OutMap is not zero then a MMap object representing
1511 the cache will be stored there. This is pretty much mandetory if you
1512 are using AllowMem. AllowMem lets the function be run as non-root
1513 where it builds the cache 'fast' into a memory buffer. */
1514 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1516 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1517 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1518 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1519 Flags
|= MMap::Moveable
;
1520 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1521 Flags
|= MMap::Fallback
;
1523 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1525 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1527 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1528 std::string
const &FileName
)
1530 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1531 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1534 fchmod(SCacheF
.Fd(),0644);
1536 // Write out the main data
1537 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1538 return _error
->Error(_("IO Error saving source cache"));
1540 // Write out the proper header
1541 Gen
->GetCache().HeaderP
->Dirty
= false;
1542 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1543 if (SCacheF
.Seek(0) == false ||
1544 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1545 return _error
->Error(_("IO Error saving source cache"));
1546 Gen
->GetCache().HeaderP
->Dirty
= true;
1549 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1550 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1552 Map
.reset(CreateDynamicMMap(NULL
, 0));
1553 if (unlikely(Map
->validData()) == false)
1555 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1556 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1558 _error
->PushToStack();
1559 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1560 bool const newError
= _error
->PendingError();
1561 _error
->MergeWithStack();
1562 if (alloc
== 0 && newError
)
1564 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1566 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1569 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1570 MMap
**OutMap
, bool AllowMem
)
1571 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1572 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1575 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1577 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1578 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1580 // FIXME: deprecate the ignored AllowMem parameter
1581 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1583 std::vector
<pkgIndexFile
*> Files
;
1584 if (_system
->AddStatusFiles(Files
) == false)
1587 // Decide if we can write to the files..
1588 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1589 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1591 // ensure the cache directory exists
1592 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1594 string dir
= _config
->FindDir("Dir::Cache");
1595 size_t const len
= dir
.size();
1596 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1597 dir
= dir
.substr(0, len
- 5);
1598 if (CacheFile
.empty() == false)
1599 CreateDirectory(dir
, flNotFile(CacheFile
));
1600 if (SrcCacheFile
.empty() == false)
1601 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1604 if (Progress
!= NULL
)
1605 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1607 bool pkgcache_fine
= false;
1608 bool srcpkgcache_fine
= false;
1609 bool volatile_fine
= List
.GetVolatileFiles().empty();
1611 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1612 volatile_fine
? OutCache
: NULL
) == true)
1615 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1616 pkgcache_fine
= true;
1617 srcpkgcache_fine
= true;
1619 if (pkgcache_fine
== false)
1621 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1624 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1625 srcpkgcache_fine
= true;
1629 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1631 if (Progress
!= NULL
)
1632 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1636 bool Writeable
= false;
1637 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1639 if (CacheFile
.empty() == false)
1640 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1641 else if (SrcCacheFile
.empty() == false)
1642 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1645 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1648 // At this point we know we need to construct something, so get storage ready
1649 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1650 if (unlikely(Map
->validData()) == false)
1653 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1655 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1656 map_filesize_t CurrentSize
= 0;
1657 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1658 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1659 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1662 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1663 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1665 srcpkgcache_fine
= true;
1666 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1668 else if (srcpkgcache_fine
== false)
1671 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1672 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1674 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1675 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1676 Files
.end(),Files
.end()) == false)
1679 if (Writeable
== true && SrcCacheFile
.empty() == false)
1680 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1684 if (pkgcache_fine
== false)
1687 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1688 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1689 Files
.begin(), Files
.end()) == false)
1692 if (Writeable
== true && CacheFile
.empty() == false)
1693 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1698 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1700 if (volatile_fine
== false)
1705 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1706 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1710 Files
= List
.GetVolatileFiles();
1711 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1712 Files
.begin(), Files
.end()) == false)
1716 if (OutMap
!= nullptr)
1717 *OutMap
= Map
.release();
1720 std::clog
<< "Everything is ready for shipping" << std::endl
;
1724 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1725 class APT_HIDDEN ScopedErrorMerge
{
1727 ScopedErrorMerge() { _error
->PushToStack(); }
1728 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1730 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1731 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1732 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1734 std::vector
<pkgIndexFile
*> Files
;
1735 if (_system
->AddStatusFiles(Files
) == false)
1738 ScopedErrorMerge sem
;
1739 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1740 if (unlikely(Map
->validData()) == false)
1742 map_filesize_t CurrentSize
= 0;
1743 map_filesize_t TotalSize
= 0;
1744 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1746 // Build the status cache
1747 if (Progress
!= NULL
)
1748 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1749 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1750 if (_error
->PendingError() == true)
1752 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1753 Files
.begin(), Files
.end()) == false)
1756 if (_error
->PendingError() == true)
1758 *OutMap
= Map
.release();
1763 // IsDuplicateDescription /*{{{*/
1764 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1765 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1767 // Descriptions in the same link-list have all the same md5
1768 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1770 for (; Desc
.end() == false; ++Desc
)
1771 if (Desc
.LanguageCode() == CurLang
)
1777 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1778 pkgCacheListParser::~pkgCacheListParser() {}