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
);
53 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
54 // ---------------------------------------------------------------------
55 /* We set the dirty flag and make sure that is written to the disk */
56 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
57 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
58 CurrentRlsFile(NULL
), CurrentFile(NULL
), d(NULL
)
62 // Setup the map interface..
63 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
64 _error
->PushToStack();
65 Map
.RawAllocate(sizeof(pkgCache::Header
));
66 bool const newError
= _error
->PendingError();
67 _error
->MergeWithStack();
71 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
74 *Cache
.HeaderP
= pkgCache::Header();
76 // make room for the hashtables for packages and groups
77 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
80 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
81 if (unlikely(idxVerSysName
== 0))
83 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
84 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
85 if (unlikely(idxArchitecture
== 0))
87 Cache
.HeaderP
->Architecture
= idxArchitecture
;
89 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
92 std::vector
<std::string
>::const_iterator a
= archs
.begin();
93 std::string list
= *a
;
94 for (++a
; a
!= archs
.end(); ++a
)
95 list
.append(",").append(*a
);
96 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
97 if (unlikely(idxArchitectures
== 0))
99 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
102 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
108 // Map directly from the existing file
110 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
111 if (Cache
.VS
!= _system
->VS
)
113 _error
->Error(_("Cache has an incompatible versioning system"));
118 Cache
.HeaderP
->Dirty
= true;
119 Map
.Sync(0,sizeof(pkgCache::Header
));
122 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
123 // ---------------------------------------------------------------------
124 /* We sync the data then unset the dirty flag in two steps so as to
125 advoid a problem during a crash */
126 pkgCacheGenerator::~pkgCacheGenerator()
128 if (_error
->PendingError() == true || Map
.validData() == false)
130 if (Map
.Sync() == false)
133 Cache
.HeaderP
->Dirty
= false;
134 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
135 Map
.Sync(0,sizeof(pkgCache::Header
));
138 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
139 if (oldMap
== newMap
)
142 if (_config
->FindB("Debug::pkgCacheGen", false))
143 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
147 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
148 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
150 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
151 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
152 (*i
)->ReMap(oldMap
, newMap
);
153 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
154 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
155 (*i
)->ReMap(oldMap
, newMap
);
156 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
157 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
158 (*i
)->ReMap(oldMap
, newMap
);
159 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
160 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
161 (*i
)->ReMap(oldMap
, newMap
);
162 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
163 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
164 (*i
)->ReMap(oldMap
, newMap
);
165 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
166 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
167 (*i
)->ReMap(oldMap
, newMap
);
168 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
169 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
170 (*i
)->ReMap(oldMap
, newMap
);
171 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
172 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
173 (*i
)->ReMap(oldMap
, newMap
);
175 // CacheGenerator::WriteStringInMap /*{{{*/
176 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
177 const unsigned long &Len
) {
178 void const * const oldMap
= Map
.Data();
179 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
181 ReMap(oldMap
, Map
.Data());
185 // CacheGenerator::WriteStringInMap /*{{{*/
186 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
187 void const * const oldMap
= Map
.Data();
188 map_stringitem_t
const index
= Map
.WriteString(String
);
190 ReMap(oldMap
, Map
.Data());
194 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
195 void const * const oldMap
= Map
.Data();
196 map_pointer_t
const index
= Map
.Allocate(size
);
198 ReMap(oldMap
, Map
.Data());
202 // CacheGenerator::MergeList - Merge the package list /*{{{*/
203 // ---------------------------------------------------------------------
204 /* This provides the generation of the entries in the cache. Each loop
205 goes through a single package record from the underlying parse engine. */
206 bool pkgCacheGenerator::MergeList(ListParser
&List
,
207 pkgCache::VerIterator
*OutVer
)
211 unsigned int Counter
= 0;
212 while (List
.Step() == true)
214 string
const PackageName
= List
.Package();
215 if (PackageName
.empty() == true)
219 if (Counter
% 100 == 0 && Progress
!= 0)
220 Progress
->Progress(List
.Offset());
222 string Arch
= List
.Architecture();
223 string
const Version
= List
.Version();
224 if (Version
.empty() == true && Arch
.empty() == true)
226 // package descriptions
227 if (MergeListGroup(List
, PackageName
) == false)
232 // Get a pointer to the package structure
233 pkgCache::PkgIterator Pkg
;
234 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
235 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
236 // TRANSLATOR: The first placeholder is a package name,
237 // the other two should be copied verbatim as they include debug info
238 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
239 PackageName
.c_str(), "NewPackage", 1);
242 if (Version
.empty() == true)
244 if (MergeListPackage(List
, Pkg
) == false)
249 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
257 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
258 return _error
->Error(_("Wow, you exceeded the number of package "
259 "names this APT is capable of."));
260 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
261 return _error
->Error(_("Wow, you exceeded the number of versions "
262 "this APT is capable of."));
263 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
264 return _error
->Error(_("Wow, you exceeded the number of descriptions "
265 "this APT is capable of."));
266 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
267 return _error
->Error(_("Wow, you exceeded the number of dependencies "
268 "this APT is capable of."));
272 // CacheGenerator::MergeListGroup /*{{{*/
273 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
275 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
276 // a group has no data on it's own, only packages have it but these
277 // stanzas like this come from Translation- files to add descriptions,
278 // but without a version we don't need a description for it…
279 if (Grp
.end() == true)
281 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
283 pkgCache::PkgIterator Pkg
;
284 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
285 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
286 if (MergeListPackage(List
, Pkg
) == false)
292 // CacheGenerator::MergeListPackage /*{{{*/
293 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
295 // we first process the package, then the descriptions
296 // (for deb this package processing is in fact a no-op)
297 pkgCache::VerIterator
Ver(Cache
);
298 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
299 if (List
.UsePackage(Pkg
, Ver
) == false)
300 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
301 Pkg
.Name(), "UsePackage", 1);
303 // Find the right version to write the description
304 MD5SumValue CurMd5
= List
.Description_md5();
305 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
307 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
308 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
310 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
312 // a version can only have one md5 describing it
313 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
316 map_stringitem_t md5idx
= VerDesc
->md5sum
;
317 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
319 // don't add a new description if we have one for the given
321 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
324 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
327 // we can stop here as all "same" versions will share the description
334 // CacheGenerator::MergeListVersion /*{{{*/
335 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
336 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
338 pkgCache::VerIterator Ver
= Pkg
.VersionList();
339 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
340 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
341 void const * oldMap
= Map
.Data();
343 unsigned short const Hash
= List
.VersionHash();
344 if (Ver
.end() == false)
346 /* We know the list is sorted so we use that fact in the search.
347 Insertion of new versions is done with correct sorting */
349 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
351 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
352 // Version is higher as current version - insert here
355 // Versionstrings are equal - is hash also equal?
356 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
358 // proceed with the next till we have either the right
359 // or we found another version (which will be lower)
362 /* We already have a version for this item, record that we saw it */
363 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
365 if (List
.UsePackage(Pkg
,Ver
) == false)
366 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
367 Pkg
.Name(), "UsePackage", 2);
369 if (NewFileVer(Ver
,List
) == false)
370 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
371 Pkg
.Name(), "NewFileVer", 1);
373 // Read only a single record and return
385 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
386 if (unlikely(verindex
== 0))
387 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
388 Pkg
.Name(), "NewVersion", 1);
390 if (oldMap
!= Map
.Data())
391 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
394 if (unlikely(List
.NewVersion(Ver
) == false))
395 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
396 Pkg
.Name(), "NewVersion", 2);
398 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
399 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
400 Pkg
.Name(), "UsePackage", 3);
402 if (unlikely(NewFileVer(Ver
,List
) == false))
403 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
404 Pkg
.Name(), "NewFileVer", 2);
406 pkgCache::GrpIterator Grp
= Pkg
.Group();
407 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
409 /* If it is the first version of this package we need to add implicit
410 Multi-Arch dependencies to all other package versions in the group now -
411 otherwise we just add them for this new version */
412 if (Pkg
.VersionList()->NextVer
== 0)
414 pkgCache::PkgIterator P
= Grp
.PackageList();
415 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
416 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
418 if (P
->ID
== Pkg
->ID
)
420 pkgCache::VerIterator V
= P
.VersionList();
421 Dynamic
<pkgCache::VerIterator
> DynV(V
);
422 for (; V
.end() != true; ++V
)
423 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
424 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
425 Pkg
.Name(), "AddImplicitDepends", 1);
428 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
429 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
430 Pkg
.Name(), "AddImplicitDepends", 2);
432 // Read only a single record and return
439 /* Record the Description(s) based on their master md5sum */
440 MD5SumValue CurMd5
= List
.Description_md5();
441 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
444 /* Before we add a new description we first search in the group for
445 a version with a description of the same MD5 - if so we reuse this
446 description group instead of creating our own for this version */
447 for (pkgCache::PkgIterator P
= Grp
.PackageList();
448 P
.end() == false; P
= Grp
.NextPkg(P
))
450 for (pkgCache::VerIterator V
= P
.VersionList();
451 V
.end() == false; ++V
)
453 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
455 Ver
->DescriptionList
= V
->DescriptionList
;
459 // We haven't found reusable descriptions, so add the first description(s)
460 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
461 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
462 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
463 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
468 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
470 pkgCache::DescIterator Desc
;
471 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
473 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
474 if (unlikely(descindex
== 0))
475 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
476 Ver
.ParentPkg().Name(), "NewDescription", 1);
478 md5idx
= Desc
->md5sum
;
479 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
481 // we add at the end, so that the start is constant as we need
482 // that to be able to efficiently share these lists
483 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
484 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
485 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
486 *LastNextDesc
= descindex
;
488 if (NewFileDesc(Desc
,List
) == false)
489 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
490 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
496 // CacheGenerator::NewGroup - Add a new group /*{{{*/
497 // ---------------------------------------------------------------------
498 /* This creates a new group structure and adds it to the hash table */
499 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
501 Grp
= Cache
.FindGrp(Name
);
502 if (Grp
.end() == false)
506 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
507 if (unlikely(Group
== 0))
510 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
511 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
512 if (unlikely(idxName
== 0))
516 // Insert it into the hash table
517 unsigned long const Hash
= Cache
.Hash(Name
);
518 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
519 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
520 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
521 Grp
->Next
= *insertAt
;
524 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
528 // CacheGenerator::NewPackage - Add a new package /*{{{*/
529 // ---------------------------------------------------------------------
530 /* This creates a new package structure and adds it to the hash table */
531 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
532 const string
&Arch
) {
533 pkgCache::GrpIterator Grp
;
534 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
535 if (unlikely(NewGroup(Grp
, Name
) == false))
538 Pkg
= Grp
.FindPkg(Arch
);
539 if (Pkg
.end() == false)
543 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
544 if (unlikely(Package
== 0))
546 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
548 // Set the name, arch and the ID
549 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
550 Pkg
->Group
= Grp
.Index();
551 // all is mapped to the native architecture
552 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
553 if (unlikely(idxArch
== 0))
556 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
558 // Insert the package into our package list
559 if (Grp
->FirstPackage
== 0) // the group is new
561 Grp
->FirstPackage
= Package
;
562 // Insert it into the hash table
563 map_id_t
const Hash
= Cache
.Hash(Name
);
564 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
565 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
566 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
567 Pkg
->NextPackage
= *insertAt
;
570 else // Group the Packages together
572 // but first get implicit provides done
573 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
575 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
576 if (M
.end() == false) {
577 pkgCache::PrvIterator Prv
;
578 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
579 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
581 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
583 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
584 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
585 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
586 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
587 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
588 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
594 pkgCache::PkgIterator P
;
595 pkgCache::VerIterator Ver
;
596 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
597 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
599 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
600 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
601 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
602 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
605 // and negative dependencies, don't forget negative dependencies
607 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
608 if (M
.end() == false) {
609 pkgCache::DepIterator Dep
;
610 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
611 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
613 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
615 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
616 Dep
->Type
!= pkgCache::Dep::Replaces
)
618 pkgCache::VerIterator Ver
= Dep
.ParentVer();
619 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
620 map_pointer_t
* unused
= NULL
;
621 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
627 // this package is the new last package
628 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
629 Pkg
->NextPackage
= LastPkg
->NextPackage
;
630 LastPkg
->NextPackage
= Package
;
632 Grp
->LastPackage
= Package
;
634 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
637 size_t const found
= Name
.find(':');
638 std::string
const NameA
= Name
.substr(0, found
);
639 std::string
const ArchA
= Name
.substr(found
+ 1);
640 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
641 if (PkgA
.end() == false)
643 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
644 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
645 for (; Prv
.end() == false; ++Prv
)
647 if (Prv
.IsMultiArchImplicit())
649 pkgCache::VerIterator V
= Prv
.OwnerVer();
650 if (ArchA
!= V
.ParentPkg().Arch())
652 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
655 pkgCache::VerIterator V
= PkgA
.VersionList();
656 Dynamic
<pkgCache::VerIterator
> DynV(V
);
657 for (; V
.end() == false; ++V
)
659 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
667 // CacheGenerator::AddImplicitDepends /*{{{*/
668 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
669 pkgCache::PkgIterator
&P
,
670 pkgCache::VerIterator
&V
)
672 // copy P.Arch() into a string here as a cache remap
673 // in NewDepends() later may alter the pointer location
674 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
675 map_pointer_t
*OldDepLast
= NULL
;
676 /* MultiArch handling introduces a lot of implicit Dependencies:
677 - MultiArch: same → Co-Installable if they have the same version
678 - All others conflict with all other group members */
679 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
680 pkgCache::PkgIterator D
= G
.PackageList();
681 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
682 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
683 for (; D
.end() != true; D
= G
.NextPkg(D
))
685 if (Arch
== D
.Arch() || D
->VersionList
== 0)
687 /* We allow only one installed arch at the time
688 per group, therefore each group member conflicts
689 with all other group members */
690 if (coInstall
== true)
692 // Replaces: ${self}:other ( << ${binary:Version})
693 NewDepends(D
, V
, VerStrIdx
,
694 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
696 // Breaks: ${self}:other (!= ${binary:Version})
697 NewDepends(D
, V
, VerStrIdx
,
698 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
701 // Conflicts: ${self}:other
703 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
709 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
710 pkgCache::PkgIterator
&D
)
712 /* MultiArch handling introduces a lot of implicit Dependencies:
713 - MultiArch: same → Co-Installable if they have the same version
714 - All others conflict with all other group members */
715 map_pointer_t
*OldDepLast
= NULL
;
716 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
717 if (coInstall
== true)
719 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
720 // Replaces: ${self}:other ( << ${binary:Version})
721 NewDepends(D
, V
, VerStrIdx
,
722 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
724 // Breaks: ${self}:other (!= ${binary:Version})
725 NewDepends(D
, V
, VerStrIdx
,
726 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
729 // Conflicts: ${self}:other
731 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
738 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
739 // ---------------------------------------------------------------------
741 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
744 if (CurrentFile
== 0)
748 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
752 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
753 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
755 // Link it to the end of the list
756 map_pointer_t
*Last
= &Ver
->FileList
;
757 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
759 VF
->NextFile
= *Last
;
762 VF
->Offset
= List
.Offset();
763 VF
->Size
= List
.Size();
764 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
765 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
766 Cache
.HeaderP
->VerFileCount
++;
771 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
772 // ---------------------------------------------------------------------
773 /* This puts a version structure in the linked list */
774 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
775 const string
&VerStr
,
776 map_pointer_t
const ParentPkg
,
777 unsigned short const Hash
,
778 map_pointer_t
const Next
)
781 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
786 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
787 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
789 Ver
->ParentPkg
= ParentPkg
;
791 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
793 // try to find the version string in the group for reuse
794 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
795 pkgCache::GrpIterator Grp
= Pkg
.Group();
796 if (Pkg
.end() == false && Grp
.end() == false)
798 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
802 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
804 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
807 Ver
->VerStr
= V
->VerStr
;
815 // haven't found the version string, so create
816 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
817 if (unlikely(idxVerStr
== 0))
819 Ver
->VerStr
= idxVerStr
;
823 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
824 // ---------------------------------------------------------------------
826 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
829 if (CurrentFile
== 0)
833 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
837 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
838 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
840 // Link it to the end of the list
841 map_pointer_t
*Last
= &Desc
->FileList
;
842 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
845 DF
->NextFile
= *Last
;
848 DF
->Offset
= List
.Offset();
849 DF
->Size
= List
.Size();
850 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
851 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
852 Cache
.HeaderP
->DescFileCount
++;
857 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
858 // ---------------------------------------------------------------------
859 /* This puts a description structure in the linked list */
860 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
862 const MD5SumValue
&md5sum
,
863 map_stringitem_t
const idxmd5str
)
866 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
867 if (Description
== 0)
871 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
872 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
873 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
874 if (unlikely(idxlanguage_code
== 0))
876 Desc
->language_code
= idxlanguage_code
;
879 Desc
->md5sum
= idxmd5str
;
882 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
883 if (unlikely(idxmd5sum
== 0))
885 Desc
->md5sum
= idxmd5sum
;
891 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
892 // ---------------------------------------------------------------------
893 /* This creates a dependency element in the tree. It is linked to the
894 version and to the package that it is pointing to. */
895 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
896 pkgCache::VerIterator
&Ver
,
897 map_pointer_t
const Version
,
900 map_pointer_t
* &OldDepLast
)
902 void const * const oldMap
= Map
.Data();
904 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
905 if (unlikely(Dependency
== 0))
908 bool isDuplicate
= false;
909 map_pointer_t DependencyData
= 0;
910 map_pointer_t PreviousData
= 0;
911 if (Pkg
->RevDepends
!= 0)
913 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
914 DependencyData
= L
->DependencyData
;
916 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
917 if (Version
> D
->Version
)
919 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
924 PreviousData
= DependencyData
;
925 DependencyData
= D
->NextData
;
926 } while (DependencyData
!= 0);
929 if (isDuplicate
== false)
931 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
932 if (unlikely(DependencyData
== 0))
936 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
937 Link
->ParentVer
= Ver
.Index();
938 Link
->DependencyData
= DependencyData
;
939 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
941 pkgCache::DepIterator
Dep(Cache
, Link
);
942 if (isDuplicate
== false)
946 Dep
->Version
= Version
;
947 Dep
->Package
= Pkg
.Index();
948 ++Cache
.HeaderP
->DependsDataCount
;
949 if (PreviousData
!= 0)
951 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
952 Dep
->NextData
= D
->NextData
;
953 D
->NextData
= DependencyData
;
955 else if (Pkg
->RevDepends
!= 0)
957 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
958 Dep
->NextData
= D
->DependencyData
;
962 if (isDuplicate
== true || PreviousData
!= 0)
964 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
965 Link
->NextRevDepends
= L
->NextRevDepends
;
966 L
->NextRevDepends
= Dependency
;
970 Link
->NextRevDepends
= Pkg
->RevDepends
;
971 Pkg
->RevDepends
= Dependency
;
975 // Do we know where to link the Dependency to?
976 if (OldDepLast
== NULL
)
978 OldDepLast
= &Ver
->DependsList
;
979 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
980 OldDepLast
= &D
->NextDepends
;
981 } else if (oldMap
!= Map
.Data())
982 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
984 Dep
->NextDepends
= *OldDepLast
;
985 *OldDepLast
= Dependency
;
986 OldDepLast
= &Dep
->NextDepends
;
990 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
991 // ---------------------------------------------------------------------
992 /* This creates a Group and the Package to link this dependency to if
993 needed and handles also the caching of the old endpoint */
994 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
995 const string
&PackageName
,
997 const string
&Version
,
1001 pkgCache::GrpIterator Grp
;
1002 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1003 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1006 map_stringitem_t idxVersion
= 0;
1007 if (Version
.empty() == false)
1009 int const CmpOp
= Op
& 0x0F;
1010 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1011 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
1012 idxVersion
= Ver
->VerStr
;
1014 if (idxVersion
== 0)
1016 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1017 if (unlikely(idxVersion
== 0))
1022 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1023 Type
== pkgCache::Dep::Conflicts
||
1024 Type
== pkgCache::Dep::Replaces
);
1026 pkgCache::PkgIterator Pkg
;
1027 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1028 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1030 // Locate the target package
1031 Pkg
= Grp
.FindPkg(Arch
);
1032 if (Pkg
.end() == true) {
1033 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1037 /* Caching the old end point speeds up generation substantially */
1038 if (OldDepVer
!= Ver
) {
1043 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1047 /* Caching the old end point speeds up generation substantially */
1048 if (OldDepVer
!= Ver
) {
1053 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1055 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1062 // ListParser::NewProvides - Create a Provides element /*{{{*/
1063 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1064 const string
&PkgName
,
1065 const string
&PkgArch
,
1066 const string
&Version
,
1067 uint8_t const Flags
)
1069 pkgCache
const &Cache
= Owner
->Cache
;
1071 // We do not add self referencing provides
1072 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1073 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1074 (Version
.empty() || Version
== Ver
.VerStr()))
1077 // Locate the target package
1078 pkgCache::PkgIterator Pkg
;
1079 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1080 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1083 map_stringitem_t idxProvideVersion
= 0;
1084 if (Version
.empty() == false) {
1085 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1086 if (unlikely(idxProvideVersion
== 0))
1089 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1091 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1092 pkgCache::PkgIterator
&Pkg
,
1093 map_pointer_t
const ProvideVersion
,
1094 uint8_t const Flags
)
1097 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1098 if (unlikely(Provides
== 0))
1100 ++Cache
.HeaderP
->ProvidesCount
;
1103 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1104 Prv
->Version
= Ver
.Index();
1105 Prv
->ProvideVersion
= ProvideVersion
;
1107 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1108 Ver
->ProvidesList
= Prv
.Index();
1110 // Link it to the package
1111 Prv
->ParentPkg
= Pkg
.Index();
1112 Prv
->NextProvides
= Pkg
->ProvidesList
;
1113 Pkg
->ProvidesList
= Prv
.Index();
1117 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1118 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, string
const &Package
,
1119 string
const &Version
, uint8_t const Flags
) {
1120 pkgCache
&Cache
= Owner
->Cache
;
1121 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1122 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1124 if (Grp
.end() == true)
1125 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1128 map_stringitem_t idxProvideVersion
= 0;
1129 if (Version
.empty() == false) {
1130 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1131 if (unlikely(idxProvideVersion
== 0))
1135 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1136 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1137 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1138 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1139 pkgCache::PkgIterator Pkg
;
1140 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1141 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1143 if (isImplicit
&& OwnerPkg
== Pkg
)
1145 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1147 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1154 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1155 pkgCache::VerIterator
const &Ver
)
1157 return Hash
== Ver
->Hash
;
1160 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1161 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1162 unsigned long Flags
)
1164 if (File
.empty() && Site
.empty())
1166 CurrentRlsFile
= NULL
;
1170 // Get some space for the structure
1171 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1172 if (unlikely(idxFile
== 0))
1174 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1177 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1178 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1179 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1181 CurrentRlsFile
->FileName
= idxFileName
;
1182 CurrentRlsFile
->Site
= idxSite
;
1183 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1184 CurrentRlsFile
->Flags
= Flags
;
1185 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1187 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1188 Cache
.HeaderP
->ReleaseFileCount
++;
1193 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1194 // ---------------------------------------------------------------------
1195 /* This is used to select which file is to be associated with all newly
1196 added versions. The caller is responsible for setting the IMS fields. */
1197 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1198 pkgIndexFile
const &Index
,
1199 std::string
const &Architecture
,
1200 std::string
const &Component
,
1201 unsigned long const Flags
)
1203 // Get some space for the structure
1204 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1205 if (unlikely(idxFile
== 0))
1207 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1210 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1211 if (unlikely(idxFileName
== 0))
1213 CurrentFile
->FileName
= idxFileName
;
1214 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1215 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1216 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1217 if (unlikely(idxIndexType
== 0))
1219 CurrentFile
->IndexType
= idxIndexType
;
1220 if (Architecture
.empty())
1221 CurrentFile
->Architecture
= 0;
1224 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1225 if (unlikely(arch
== 0))
1227 CurrentFile
->Architecture
= arch
;
1229 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1230 if (unlikely(component
== 0))
1232 CurrentFile
->Component
= component
;
1233 CurrentFile
->Flags
= Flags
;
1234 if (CurrentRlsFile
!= NULL
)
1235 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1237 CurrentFile
->Release
= 0;
1239 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1240 Cache
.HeaderP
->PackageFileCount
++;
1243 Progress
->SubProgress(Index
.Size());
1247 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1248 // ---------------------------------------------------------------------
1249 /* This is used to create handles to strings. Given the same text it
1250 always returns the same number */
1251 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1254 std::string
const key(S
, Size
);
1256 std::unordered_map
<std::string
,map_stringitem_t
> * strings
;
1258 case MIXED
: strings
= &strMixed
; break;
1259 case PKGNAME
: strings
= &strPkgNames
; break;
1260 case VERSIONNUMBER
: strings
= &strVersions
; break;
1261 case SECTION
: strings
= &strSections
; break;
1262 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1265 std::unordered_map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1266 if (item
!= strings
->end())
1267 return item
->second
;
1269 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1270 strings
->insert(std::make_pair(key
, idxString
));
1274 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1275 // ---------------------------------------------------------------------
1276 /* This just verifies that each file in the list of index files exists,
1277 has matching attributes with the cache and the cache does not have
1279 class APT_HIDDEN ScopedErrorRevert
{
1281 ScopedErrorRevert() { _error
->PushToStack(); }
1282 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1284 static bool CheckValidity(const string
&CacheFile
,
1285 pkgSourceList
&List
,
1286 FileIterator
const Start
,
1287 FileIterator
const End
,
1290 ScopedErrorRevert ser
;
1291 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1292 // No file, certainly invalid
1293 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1296 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1300 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1303 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1308 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1309 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1310 if (unlikely(Map
->validData()) == false)
1312 pkgCache
Cache(Map
.get());
1313 if (_error
->PendingError() || Map
->Size() == 0)
1316 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1320 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1321 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1322 std::vector
<pkgIndexFile
*> Files
;
1323 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1326 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1327 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1328 if (RlsFile
.end() == true)
1331 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1335 RlsVisited
[RlsFile
->ID
] = true;
1337 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1339 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1340 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1341 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1343 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1344 if (RlsVisited
[I
] == false)
1347 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1351 std::copy(Start
, End
, std::back_inserter(Files
));
1353 /* Now we check every index file, see if it is in the cache,
1354 verify the IMS data and check that it is on the disk too.. */
1355 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1356 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1357 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1360 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1361 if ((*PkgFile
)->Exists() == false)
1364 std::clog
<< "file doesn't exist" << std::endl
;
1368 // FindInCache is also expected to do an IMS check.
1369 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1370 if (File
.end() == true)
1373 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1377 Visited
[File
->ID
] = true;
1379 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1382 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1383 if (Visited
[I
] == false)
1386 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1390 if (_error
->PendingError() == true)
1394 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1395 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1401 *OutMap
= Map
.release();
1405 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1406 // ---------------------------------------------------------------------
1407 /* Size is kind of an abstract notion that is only used for the progress
1409 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1411 map_filesize_t TotalSize
= 0;
1414 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1416 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1417 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1418 if ((*j
)->HasPackages() == true)
1419 TotalSize
+= (*j
)->Size();
1423 for (; Start
< End
; ++Start
)
1425 if ((*Start
)->HasPackages() == false)
1427 TotalSize
+= (*Start
)->Size();
1432 // BuildCache - Merge the list of index files into the cache /*{{{*/
1433 static bool BuildCache(pkgCacheGenerator
&Gen
,
1434 OpProgress
* const Progress
,
1435 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1436 pkgSourceList
const * const List
,
1437 FileIterator
const Start
, FileIterator
const End
)
1439 bool mergeFailure
= false;
1441 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1442 if (I
->HasPackages() == false || mergeFailure
)
1445 if (I
->Exists() == false)
1448 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1450 _error
->Warning("Duplicate sources.list entry %s",
1451 I
->Describe().c_str());
1455 map_filesize_t
const Size
= I
->Size();
1456 if (Progress
!= NULL
)
1457 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1458 CurrentSize
+= Size
;
1460 if (I
->Merge(Gen
,Progress
) == false)
1461 mergeFailure
= true;
1466 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1468 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1470 _error
->Warning("Duplicate sources.list entry %s",
1471 (*i
)->Describe().c_str());
1475 if ((*i
)->Merge(Gen
, Progress
) == false)
1478 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1479 if (Indexes
!= NULL
)
1480 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1488 Gen
.SelectReleaseFile("", "");
1489 std::for_each(Start
, End
, indexFileMerge
);
1496 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1497 // ---------------------------------------------------------------------
1498 /* This makes sure that the status cache (the cache that has all
1499 index files from the sources list and all local ones) is ready
1500 to be mmaped. If OutMap is not zero then a MMap object representing
1501 the cache will be stored there. This is pretty much mandetory if you
1502 are using AllowMem. AllowMem lets the function be run as non-root
1503 where it builds the cache 'fast' into a memory buffer. */
1504 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1506 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1507 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1508 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1509 Flags
|= MMap::Moveable
;
1510 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1511 Flags
|= MMap::Fallback
;
1513 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1515 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1517 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1518 std::string
const &FileName
)
1520 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1521 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1524 fchmod(SCacheF
.Fd(),0644);
1526 // Write out the main data
1527 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1528 return _error
->Error(_("IO Error saving source cache"));
1531 // Write out the proper header
1532 Gen
->GetCache().HeaderP
->Dirty
= false;
1533 if (SCacheF
.Seek(0) == false ||
1534 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1535 return _error
->Error(_("IO Error saving source cache"));
1536 Gen
->GetCache().HeaderP
->Dirty
= true;
1540 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1541 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1543 Map
.reset(CreateDynamicMMap(NULL
, 0));
1544 if (unlikely(Map
->validData()) == false)
1546 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1547 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1549 _error
->PushToStack();
1550 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1551 bool const newError
= _error
->PendingError();
1552 _error
->MergeWithStack();
1553 if (alloc
== 0 && newError
)
1555 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1557 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1560 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1561 MMap
**OutMap
, bool AllowMem
)
1562 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1563 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1566 // FIXME: deprecate the ignored AllowMem parameter
1567 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1569 std::vector
<pkgIndexFile
*> Files
;
1570 if (_system
->AddStatusFiles(Files
) == false)
1573 // Decide if we can write to the files..
1574 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1575 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1577 // ensure the cache directory exists
1578 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1580 string dir
= _config
->FindDir("Dir::Cache");
1581 size_t const len
= dir
.size();
1582 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1583 dir
= dir
.substr(0, len
- 5);
1584 if (CacheFile
.empty() == false)
1585 CreateDirectory(dir
, flNotFile(CacheFile
));
1586 if (SrcCacheFile
.empty() == false)
1587 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1590 if (Progress
!= NULL
)
1591 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1593 bool pkgcache_fine
= false;
1594 bool srcpkgcache_fine
= false;
1595 bool volatile_fine
= List
.GetVolatileFiles().empty();
1597 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
) == true)
1600 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1601 pkgcache_fine
= true;
1602 srcpkgcache_fine
= true;
1604 if (pkgcache_fine
== false)
1606 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1609 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1610 srcpkgcache_fine
= true;
1614 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1616 if (Progress
!= NULL
)
1617 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1621 bool Writeable
= false;
1622 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1624 if (CacheFile
.empty() == false)
1625 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1626 else if (SrcCacheFile
.empty() == false)
1627 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1630 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1633 // At this point we know we need to construct something, so get storage ready
1634 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1635 if (unlikely(Map
->validData()) == false)
1638 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1640 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1641 map_filesize_t CurrentSize
= 0;
1642 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1643 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1644 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1647 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1648 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1650 srcpkgcache_fine
= true;
1651 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1653 else if (srcpkgcache_fine
== false)
1656 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1657 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1659 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1660 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1661 Files
.end(),Files
.end()) == false)
1664 if (Writeable
== true && SrcCacheFile
.empty() == false)
1665 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1669 if (pkgcache_fine
== false)
1672 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1673 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1674 Files
.begin(), Files
.end()) == false)
1677 if (Writeable
== true && CacheFile
.empty() == false)
1678 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1683 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1685 if (volatile_fine
== false)
1690 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1691 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1695 Files
= List
.GetVolatileFiles();
1696 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1697 Files
.begin(), Files
.end()) == false)
1701 if (OutMap
!= nullptr)
1702 *OutMap
= Map
.release();
1705 std::clog
<< "Everything is ready for shipping" << std::endl
;
1709 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1710 class APT_HIDDEN ScopedErrorMerge
{
1712 ScopedErrorMerge() { _error
->PushToStack(); }
1713 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1715 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1716 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1717 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1719 std::vector
<pkgIndexFile
*> Files
;
1720 if (_system
->AddStatusFiles(Files
) == false)
1723 ScopedErrorMerge sem
;
1724 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1725 if (unlikely(Map
->validData()) == false)
1727 map_filesize_t CurrentSize
= 0;
1728 map_filesize_t TotalSize
= 0;
1729 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1731 // Build the status cache
1732 if (Progress
!= NULL
)
1733 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1734 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1735 if (_error
->PendingError() == true)
1737 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1738 Files
.begin(), Files
.end()) == false)
1741 if (_error
->PendingError() == true)
1743 *OutMap
= Map
.release();
1748 // IsDuplicateDescription /*{{{*/
1749 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1750 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1752 // Descriptions in the same link-list have all the same md5
1753 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1755 for (; Desc
.end() == false; ++Desc
)
1756 if (Desc
.LanguageCode() == CurLang
)
1762 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1763 pkgCacheListParser::~pkgCacheListParser() {}