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
&Cache
, pkgCache::DescIterator Desc
,
49 APT::StringView 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
)
62 bool pkgCacheGenerator::Start()
66 // Setup the map interface..
67 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
68 _error
->PushToStack();
69 Map
.RawAllocate(sizeof(pkgCache::Header
));
70 bool const newError
= _error
->PendingError();
71 _error
->MergeWithStack();
77 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
80 *Cache
.HeaderP
= pkgCache::Header();
82 // make room for the hashtables for packages and groups
83 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
86 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
87 if (unlikely(idxVerSysName
== 0))
89 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
90 if (unlikely(idxArchitecture
== 0))
92 map_stringitem_t idxArchitectures
;
94 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
97 std::vector
<std::string
>::const_iterator a
= archs
.begin();
98 std::string list
= *a
;
99 for (++a
; a
!= archs
.end(); ++a
)
100 list
.append(",").append(*a
);
101 idxArchitectures
= WriteStringInMap(list
);
102 if (unlikely(idxArchitectures
== 0))
106 idxArchitectures
= idxArchitecture
;
108 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
109 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
110 Cache
.HeaderP
->Architecture
= idxArchitecture
;
111 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
113 // Calculate the hash for the empty map, so ReMap does not fail
114 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
119 // Map directly from the existing file
121 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
122 if (Cache
.VS
!= _system
->VS
)
123 return _error
->Error(_("Cache has an incompatible versioning system"));
126 Cache
.HeaderP
->Dirty
= true;
127 Map
.Sync(0,sizeof(pkgCache::Header
));
131 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
132 // ---------------------------------------------------------------------
133 /* We sync the data then unset the dirty flag in two steps so as to
134 advoid a problem during a crash */
135 pkgCacheGenerator::~pkgCacheGenerator()
137 if (_error
->PendingError() == true || Map
.validData() == false)
139 if (Map
.Sync() == false)
142 Cache
.HeaderP
->Dirty
= false;
143 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
145 if (_config
->FindB("Debug::pkgCacheGen", false))
146 std::clog
<< "Produced cache with hash " << Cache
.HeaderP
->CacheFileSize
<< std::endl
;
147 Map
.Sync(0,sizeof(pkgCache::Header
));
150 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
, size_t oldSize
) {/*{{{*/
151 // Prevent multiple remaps of the same iterator. If seen.insert(iterator)
152 // returns (something, true) the iterator was not yet seen and we can
154 std::unordered_set
<void *> seen
;
155 if (oldMap
== newMap
)
158 if (_config
->FindB("Debug::pkgCacheGen", false))
159 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
163 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
164 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
166 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
167 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
168 if (std::get
<1>(seen
.insert(*i
)) == true)
169 (*i
)->ReMap(oldMap
, newMap
);
170 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
171 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
172 if (std::get
<1>(seen
.insert(*i
)) == true)
173 (*i
)->ReMap(oldMap
, newMap
);
174 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
175 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
176 if (std::get
<1>(seen
.insert(*i
)) == true)
177 (*i
)->ReMap(oldMap
, newMap
);
178 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
179 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
180 if (std::get
<1>(seen
.insert(*i
)) == true)
181 (*i
)->ReMap(oldMap
, newMap
);
182 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
183 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
184 if (std::get
<1>(seen
.insert(*i
)) == true)
185 (*i
)->ReMap(oldMap
, newMap
);
186 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
187 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
188 if (std::get
<1>(seen
.insert(*i
)) == true)
189 (*i
)->ReMap(oldMap
, newMap
);
190 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
191 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
192 if (std::get
<1>(seen
.insert(*i
)) == true)
193 (*i
)->ReMap(oldMap
, newMap
);
194 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
195 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
196 if (std::get
<1>(seen
.insert(*i
)) == true)
197 (*i
)->ReMap(oldMap
, newMap
);
198 for (APT::StringView
* ViewP
: Dynamic
<APT::StringView
>::toReMap
) {
199 if (std::get
<1>(seen
.insert(ViewP
)) == false)
201 // Ignore views outside of the cache.
202 if (ViewP
->data() < static_cast<const char*>(oldMap
)
203 || ViewP
->data() > static_cast<const char*>(oldMap
) + oldSize
)
205 const char *data
= ViewP
->data() + (static_cast<const char*>(newMap
) - static_cast<const char*>(oldMap
));
206 *ViewP
= StringView(data
, ViewP
->size());
209 // CacheGenerator::WriteStringInMap /*{{{*/
210 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
211 const unsigned long &Len
) {
212 size_t oldSize
= Map
.Size();
213 void const * const oldMap
= Map
.Data();
214 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
216 ReMap(oldMap
, Map
.Data(), oldSize
);
220 // CacheGenerator::WriteStringInMap /*{{{*/
221 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
222 size_t oldSize
= Map
.Size();
223 void const * const oldMap
= Map
.Data();
224 map_stringitem_t
const index
= Map
.WriteString(String
);
226 ReMap(oldMap
, Map
.Data(), oldSize
);
230 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
231 size_t oldSize
= Map
.Size();
232 void const * const oldMap
= Map
.Data();
233 map_pointer_t
const index
= Map
.Allocate(size
);
235 ReMap(oldMap
, Map
.Data(), oldSize
);
239 // CacheGenerator::MergeList - Merge the package list /*{{{*/
240 // ---------------------------------------------------------------------
241 /* This provides the generation of the entries in the cache. Each loop
242 goes through a single package record from the underlying parse engine. */
243 bool pkgCacheGenerator::MergeList(ListParser
&List
,
244 pkgCache::VerIterator
*OutVer
)
248 unsigned int Counter
= 0;
249 while (List
.Step() == true)
251 string
const PackageName
= List
.Package();
252 if (PackageName
.empty() == true) {
253 _error
->Warning("Encountered a section with no Package: header");
258 if (Counter
% 100 == 0 && Progress
!= 0)
259 Progress
->Progress(List
.Offset());
261 APT::StringView Arch
= List
.Architecture();
262 Dynamic
<APT::StringView
> DynArch(Arch
);
263 APT::StringView Version
= List
.Version();
264 Dynamic
<APT::StringView
> DynVersion(Version
);
265 if (Version
.empty() == true && Arch
.empty() == true)
267 // package descriptions
268 if (MergeListGroup(List
, PackageName
) == false)
273 // Get a pointer to the package structure
274 pkgCache::PkgIterator Pkg
;
275 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
276 if (NewPackage(Pkg
, PackageName
, Arch
) == false) {
277 // TRANSLATOR: The first placeholder is a package name,
278 // the other two should be copied verbatim as they include debug info
279 _error
->Warning(_("Error occurred while processing %s (%s%d)"),
280 PackageName
.c_str(), "NewPackage", 1);
285 if (Version
.empty() == true)
287 if (MergeListPackage(List
, Pkg
) == false)
292 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
300 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
301 return _error
->Error(_("Wow, you exceeded the number of package "
302 "names this APT is capable of."));
303 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
304 return _error
->Error(_("Wow, you exceeded the number of versions "
305 "this APT is capable of."));
306 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
307 return _error
->Error(_("Wow, you exceeded the number of descriptions "
308 "this APT is capable of."));
309 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
310 return _error
->Error(_("Wow, you exceeded the number of dependencies "
311 "this APT is capable of."));
315 // CacheGenerator::MergeListGroup /*{{{*/
316 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
318 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
319 // a group has no data on it's own, only packages have it but these
320 // stanzas like this come from Translation- files to add descriptions,
321 // but without a version we don't need a description for it…
322 if (Grp
.end() == true)
324 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
326 pkgCache::PkgIterator Pkg
;
327 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
328 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
329 if (MergeListPackage(List
, Pkg
) == false)
335 // CacheGenerator::MergeListPackage /*{{{*/
336 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
338 // we first process the package, then the descriptions
339 // (for deb this package processing is in fact a no-op)
340 pkgCache::VerIterator
Ver(Cache
);
341 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
342 if (List
.UsePackage(Pkg
, Ver
) == false)
343 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
344 Pkg
.Name(), "UsePackage", 1);
346 // Find the right version to write the description
347 StringView CurMd5
= List
.Description_md5();
348 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
349 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
351 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
353 // a version can only have one md5 describing it
354 if (VerDesc
.end() == true || Cache
.ViewString(VerDesc
->md5sum
) != CurMd5
)
357 map_stringitem_t md5idx
= VerDesc
->md5sum
;
358 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
360 // don't add a new description if we have one for the given
362 if (IsDuplicateDescription(Cache
, VerDesc
, CurMd5
, *CurLang
) == true)
365 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
368 // we can stop here as all "same" versions will share the description
375 // CacheGenerator::MergeListVersion /*{{{*/
376 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
377 APT::StringView
const &Version
, pkgCache::VerIterator
* &OutVer
)
379 pkgCache::VerIterator Ver
= Pkg
.VersionList();
380 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
381 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
382 void const * oldMap
= Map
.Data();
384 unsigned short const Hash
= List
.VersionHash();
385 if (Ver
.end() == false)
387 /* We know the list is sorted so we use that fact in the search.
388 Insertion of new versions is done with correct sorting */
390 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
392 char const * const VerStr
= Ver
.VerStr();
393 Res
= Cache
.VS
->DoCmpVersion(Version
.data(), Version
.data() + Version
.length(),
394 VerStr
, VerStr
+ strlen(VerStr
));
395 // Version is higher as current version - insert here
398 // Versionstrings are equal - is hash also equal?
401 if (List
.SameVersion(Hash
, Ver
) == true)
403 // sort (volatile) sources above not-sources like the status file
404 if ((CurrentFile
->Flags
& pkgCache::Flag::NotSource
) == 0)
406 auto VF
= Ver
.FileList();
407 for (; VF
.end() == false; ++VF
)
408 if (VF
.File().Flagged(pkgCache::Flag::NotSource
) == false)
410 if (VF
.end() == true)
414 // proceed with the next till we have either the right
415 // or we found another version (which will be lower)
418 /* We already have a version for this item, record that we saw it */
419 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
421 if (List
.UsePackage(Pkg
,Ver
) == false)
422 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
423 Pkg
.Name(), "UsePackage", 2);
425 if (NewFileVer(Ver
,List
) == false)
426 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
427 Pkg
.Name(), "NewFileVer", 1);
429 // Read only a single record and return
441 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
442 if (unlikely(verindex
== 0))
443 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
444 Pkg
.Name(), "NewVersion", 1);
446 if (oldMap
!= Map
.Data())
447 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
450 if (unlikely(List
.NewVersion(Ver
) == false))
451 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
452 Pkg
.Name(), "NewVersion", 2);
454 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
455 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
456 Pkg
.Name(), "UsePackage", 3);
458 if (unlikely(NewFileVer(Ver
,List
) == false))
459 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
460 Pkg
.Name(), "NewFileVer", 2);
462 pkgCache::GrpIterator Grp
= Pkg
.Group();
463 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
465 /* If it is the first version of this package we need to add implicit
466 Multi-Arch dependencies to all other package versions in the group now -
467 otherwise we just add them for this new version */
468 if (Pkg
.VersionList()->NextVer
== 0)
470 pkgCache::PkgIterator P
= Grp
.PackageList();
471 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
472 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
474 if (P
->ID
== Pkg
->ID
)
476 pkgCache::VerIterator V
= P
.VersionList();
477 Dynamic
<pkgCache::VerIterator
> DynV(V
);
478 for (; V
.end() != true; ++V
)
479 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
480 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
481 Pkg
.Name(), "AddImplicitDepends", 1);
484 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
485 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
486 Pkg
.Name(), "AddImplicitDepends", 2);
488 // Read only a single record and return
495 /* Record the Description(s) based on their master md5sum */
496 StringView CurMd5
= List
.Description_md5();
498 /* Before we add a new description we first search in the group for
499 a version with a description of the same MD5 - if so we reuse this
500 description group instead of creating our own for this version */
501 for (pkgCache::PkgIterator P
= Grp
.PackageList();
502 P
.end() == false; P
= Grp
.NextPkg(P
))
504 for (pkgCache::VerIterator V
= P
.VersionList();
505 V
.end() == false; ++V
)
507 if (V
->DescriptionList
== 0 || Cache
.ViewString(V
.DescriptionList()->md5sum
) != CurMd5
)
509 Ver
->DescriptionList
= V
->DescriptionList
;
513 // We haven't found reusable descriptions, so add the first description(s)
514 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
515 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
516 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
517 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
522 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, APT::StringView CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
524 pkgCache::DescIterator Desc
;
525 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
527 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
528 if (unlikely(descindex
== 0))
529 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
530 Ver
.ParentPkg().Name(), "NewDescription", 1);
532 md5idx
= Desc
->md5sum
;
533 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
535 // we add at the end, so that the start is constant as we need
536 // that to be able to efficiently share these lists
537 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
538 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
539 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
540 *LastNextDesc
= descindex
;
542 if (NewFileDesc(Desc
,List
) == false)
543 return _error
->Warning(_("Error occurred while processing %s (%s%d)"),
544 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
550 // CacheGenerator::NewGroup - Add a new group /*{{{*/
551 // ---------------------------------------------------------------------
552 /* This creates a new group structure and adds it to the hash table */
553 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
555 Dynamic
<StringView
> DName(Name
);
556 Grp
= Cache
.FindGrp(Name
);
557 if (Grp
.end() == false)
561 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
562 if (unlikely(Group
== 0))
565 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
566 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
567 if (unlikely(idxName
== 0))
571 // Insert it into the hash table
572 unsigned long const Hash
= Cache
.Hash(Name
);
573 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
575 while (*insertAt
!= 0 && StringViewCompareFast(Name
, Cache
.ViewString((Cache
.GrpP
+ *insertAt
)->Name
)) > 0)
576 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
577 Grp
->Next
= *insertAt
;
580 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
584 // CacheGenerator::NewPackage - Add a new package /*{{{*/
585 // ---------------------------------------------------------------------
586 /* This creates a new package structure and adds it to the hash table */
587 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
589 pkgCache::GrpIterator Grp
;
590 Dynamic
<StringView
> DName(Name
);
591 Dynamic
<StringView
> DArch(Arch
);
592 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
593 if (unlikely(NewGroup(Grp
, Name
) == false))
596 Pkg
= Grp
.FindPkg(Arch
);
597 if (Pkg
.end() == false)
601 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
602 if (unlikely(Package
== 0))
604 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
606 // Set the name, arch and the ID
607 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
608 Pkg
->Group
= Grp
.Index();
609 // all is mapped to the native architecture
610 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
611 if (unlikely(idxArch
== 0))
614 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
616 // Insert the package into our package list
617 if (Grp
->FirstPackage
== 0) // the group is new
619 Grp
->FirstPackage
= Package
;
620 // Insert it into the hash table
621 map_id_t
const Hash
= Cache
.Hash(Name
);
622 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
623 while (*insertAt
!= 0 && StringViewCompareFast(Name
, Cache
.ViewString((Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
)) > 0)
624 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
625 Pkg
->NextPackage
= *insertAt
;
628 else // Group the Packages together
630 // if sibling is provided by another package, this one is too
632 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
633 if (M
.end() == false) {
634 pkgCache::PrvIterator Prv
;
635 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
636 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
638 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
640 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
641 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
642 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
643 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
644 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
646 if (APT::Configuration::checkArchitecture(Ver
.ParentPkg().Arch()) == false)
648 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
654 // let M-A:foreign package siblings provide this package
656 pkgCache::PkgIterator P
;
657 pkgCache::VerIterator Ver
;
658 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
659 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
661 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
663 if (APT::Configuration::checkArchitecture(P
.Arch()) == false)
665 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
666 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
667 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
671 // and negative dependencies, don't forget negative dependencies
673 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
674 if (M
.end() == false) {
675 pkgCache::DepIterator Dep
;
676 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
677 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
679 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
681 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
682 Dep
->Type
!= pkgCache::Dep::Replaces
)
684 pkgCache::VerIterator Ver
= Dep
.ParentVer();
685 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
686 map_pointer_t
* unused
= NULL
;
687 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
693 // this package is the new last package
694 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
695 Pkg
->NextPackage
= LastPkg
->NextPackage
;
696 LastPkg
->NextPackage
= Package
;
698 Grp
->LastPackage
= Package
;
700 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
703 size_t const found
= Name
.rfind(':');
704 StringView ArchA
= Name
.substr(found
+ 1);
707 // ArchA is used inside the loop which might remap (NameA is not used)
708 Dynamic
<StringView
> DynArchA(ArchA
);
709 StringView NameA
= Name
.substr(0, found
);
710 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
711 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
714 Dynamic
<StringView
> DynNameA(NameA
);
715 if (NewPackage(PkgA
, NameA
, ArchA
) == false)
718 if (unlikely(PkgA
.end()))
719 return _error
->Fatal("NewPackage was successful for %s:%s,"
720 "but the package doesn't exist anyhow!",
721 NameA
.to_string().c_str(), ArchA
.to_string().c_str());
724 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
725 for (; Prv
.end() == false; ++Prv
)
727 if (Prv
.IsMultiArchImplicit())
729 pkgCache::VerIterator V
= Prv
.OwnerVer();
730 if (ArchA
!= V
.ParentPkg().Arch())
732 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
735 pkgCache::VerIterator V
= PkgA
.VersionList();
736 Dynamic
<pkgCache::VerIterator
> DynV(V
);
737 for (; V
.end() == false; ++V
)
739 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
748 // CacheGenerator::AddImplicitDepends /*{{{*/
749 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
750 pkgCache::PkgIterator
&P
,
751 pkgCache::VerIterator
&V
)
753 APT::StringView Arch
= P
.Arch() == NULL
? "" : P
.Arch();
754 Dynamic
<APT::StringView
> DynArch(Arch
);
755 map_pointer_t
*OldDepLast
= NULL
;
756 /* MultiArch handling introduces a lot of implicit Dependencies:
757 - MultiArch: same → Co-Installable if they have the same version
758 - All others conflict with all other group members */
759 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
760 pkgCache::PkgIterator D
= G
.PackageList();
761 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
762 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
763 for (; D
.end() != true; D
= G
.NextPkg(D
))
765 if (Arch
== D
.Arch() || D
->VersionList
== 0)
767 /* We allow only one installed arch at the time
768 per group, therefore each group member conflicts
769 with all other group members */
770 if (coInstall
== true)
772 // Replaces: ${self}:other ( << ${binary:Version})
773 NewDepends(D
, V
, VerStrIdx
,
774 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
776 // Breaks: ${self}:other (!= ${binary:Version})
777 NewDepends(D
, V
, VerStrIdx
,
778 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
781 // Conflicts: ${self}:other
783 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
789 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
790 pkgCache::PkgIterator
&D
)
792 /* MultiArch handling introduces a lot of implicit Dependencies:
793 - MultiArch: same → Co-Installable if they have the same version
794 - All others conflict with all other group members */
795 map_pointer_t
*OldDepLast
= NULL
;
796 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
797 if (coInstall
== true)
799 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
800 // Replaces: ${self}:other ( << ${binary:Version})
801 NewDepends(D
, V
, VerStrIdx
,
802 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
804 // Breaks: ${self}:other (!= ${binary:Version})
805 NewDepends(D
, V
, VerStrIdx
,
806 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
809 // Conflicts: ${self}:other
811 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
818 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
819 // ---------------------------------------------------------------------
821 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
824 if (CurrentFile
== 0)
828 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
832 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
833 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
835 // Link it to the end of the list
836 map_pointer_t
*Last
= &Ver
->FileList
;
837 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
839 VF
->NextFile
= *Last
;
842 VF
->Offset
= List
.Offset();
843 VF
->Size
= List
.Size();
844 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
845 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
846 Cache
.HeaderP
->VerFileCount
++;
851 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
852 // ---------------------------------------------------------------------
853 /* This puts a version structure in the linked list */
854 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
855 APT::StringView
const &VerStr
,
856 map_pointer_t
const ParentPkg
,
857 unsigned short const Hash
,
858 map_pointer_t
const Next
)
861 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
866 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
867 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
869 Ver
->ParentPkg
= ParentPkg
;
871 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
873 // try to find the version string in the group for reuse
874 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
875 pkgCache::GrpIterator Grp
= Pkg
.Group();
876 if (Pkg
.end() == false && Grp
.end() == false)
878 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
882 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
884 int const cmp
= strncmp(V
.VerStr(), VerStr
.data(), VerStr
.length());
885 if (cmp
== 0 && V
.VerStr()[VerStr
.length()] == '\0')
887 Ver
->VerStr
= V
->VerStr
;
895 // haven't found the version string, so create
896 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
897 if (unlikely(idxVerStr
== 0))
899 Ver
->VerStr
= idxVerStr
;
903 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
904 // ---------------------------------------------------------------------
906 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
909 if (CurrentFile
== 0)
913 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
917 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
918 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
920 // Link it to the end of the list
921 map_pointer_t
*Last
= &Desc
->FileList
;
922 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
925 DF
->NextFile
= *Last
;
928 DF
->Offset
= List
.Offset();
929 DF
->Size
= List
.Size();
930 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
931 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
932 Cache
.HeaderP
->DescFileCount
++;
937 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
938 // ---------------------------------------------------------------------
939 /* This puts a description structure in the linked list */
940 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
942 APT::StringView md5sum
,
943 map_stringitem_t
const idxmd5str
)
946 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
947 if (Description
== 0)
951 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
952 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
953 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
954 if (unlikely(idxlanguage_code
== 0))
956 Desc
->language_code
= idxlanguage_code
;
959 Desc
->md5sum
= idxmd5str
;
962 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
);
963 if (unlikely(idxmd5sum
== 0))
965 Desc
->md5sum
= idxmd5sum
;
971 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
972 // ---------------------------------------------------------------------
973 /* This creates a dependency element in the tree. It is linked to the
974 version and to the package that it is pointing to. */
975 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
976 pkgCache::VerIterator
&Ver
,
977 map_pointer_t
const Version
,
980 map_pointer_t
* &OldDepLast
)
982 void const * const oldMap
= Map
.Data();
984 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
985 if (unlikely(Dependency
== 0))
988 bool isDuplicate
= false;
989 map_pointer_t DependencyData
= 0;
990 map_pointer_t PreviousData
= 0;
991 if (Pkg
->RevDepends
!= 0)
993 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
994 DependencyData
= L
->DependencyData
;
996 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
997 if (Version
> D
->Version
)
999 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
1004 PreviousData
= DependencyData
;
1005 DependencyData
= D
->NextData
;
1006 } while (DependencyData
!= 0);
1009 if (isDuplicate
== false)
1011 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
1012 if (unlikely(DependencyData
== 0))
1016 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
1017 Link
->ParentVer
= Ver
.Index();
1018 Link
->DependencyData
= DependencyData
;
1019 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
1021 pkgCache::DepIterator
Dep(Cache
, Link
);
1022 if (isDuplicate
== false)
1025 Dep
->CompareOp
= Op
;
1026 Dep
->Version
= Version
;
1027 Dep
->Package
= Pkg
.Index();
1028 ++Cache
.HeaderP
->DependsDataCount
;
1029 if (PreviousData
!= 0)
1031 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
1032 Dep
->NextData
= D
->NextData
;
1033 D
->NextData
= DependencyData
;
1035 else if (Pkg
->RevDepends
!= 0)
1037 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
1038 Dep
->NextData
= D
->DependencyData
;
1042 if (isDuplicate
== true || PreviousData
!= 0)
1044 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
1045 Link
->NextRevDepends
= L
->NextRevDepends
;
1046 L
->NextRevDepends
= Dependency
;
1050 Link
->NextRevDepends
= Pkg
->RevDepends
;
1051 Pkg
->RevDepends
= Dependency
;
1055 // Do we know where to link the Dependency to?
1056 if (OldDepLast
== NULL
)
1058 OldDepLast
= &Ver
->DependsList
;
1059 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
1060 OldDepLast
= &D
->NextDepends
;
1061 } else if (oldMap
!= Map
.Data())
1062 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
1064 Dep
->NextDepends
= *OldDepLast
;
1065 *OldDepLast
= Dependency
;
1066 OldDepLast
= &Dep
->NextDepends
;
1070 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1071 // ---------------------------------------------------------------------
1072 /* This creates a Group and the Package to link this dependency to if
1073 needed and handles also the caching of the old endpoint */
1074 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1075 StringView PackageName
,
1081 pkgCache::GrpIterator Grp
;
1082 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1083 Dynamic
<StringView
> DynPackageName(PackageName
);
1084 Dynamic
<StringView
> DynArch(Arch
);
1085 Dynamic
<StringView
> DynVersion(Version
);
1086 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1089 map_stringitem_t idxVersion
= 0;
1090 if (Version
.empty() == false)
1092 int const CmpOp
= Op
& 0x0F;
1093 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1094 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1095 idxVersion
= Ver
->VerStr
;
1097 if (idxVersion
== 0)
1099 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1100 if (unlikely(idxVersion
== 0))
1105 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1106 Type
== pkgCache::Dep::Conflicts
||
1107 Type
== pkgCache::Dep::Replaces
);
1109 pkgCache::PkgIterator Pkg
;
1110 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1111 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1113 // Locate the target package
1114 Pkg
= Grp
.FindPkg(Arch
);
1115 if (Pkg
.end() == true) {
1116 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1120 /* Caching the old end point speeds up generation substantially */
1121 if (OldDepVer
!= Ver
) {
1126 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1130 /* Caching the old end point speeds up generation substantially */
1131 if (OldDepVer
!= Ver
) {
1136 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1138 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1145 // ListParser::NewProvides - Create a Provides element /*{{{*/
1146 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1150 uint8_t const Flags
)
1152 pkgCache
const &Cache
= Owner
->Cache
;
1153 Dynamic
<StringView
> DynPkgName(PkgName
);
1154 Dynamic
<StringView
> DynArch(PkgArch
);
1155 Dynamic
<StringView
> DynVersion(Version
);
1157 // We do not add self referencing provides
1158 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1159 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1160 (Version
.empty() || Version
== Ver
.VerStr()))
1163 // Locate the target package
1164 pkgCache::PkgIterator Pkg
;
1165 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1166 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1169 map_stringitem_t idxProvideVersion
= 0;
1170 if (Version
.empty() == false) {
1171 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1172 if (unlikely(idxProvideVersion
== 0))
1175 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1177 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1178 pkgCache::PkgIterator
&Pkg
,
1179 map_pointer_t
const ProvideVersion
,
1180 uint8_t const Flags
)
1183 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1184 if (unlikely(Provides
== 0))
1186 ++Cache
.HeaderP
->ProvidesCount
;
1189 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1190 Prv
->Version
= Ver
.Index();
1191 Prv
->ProvideVersion
= ProvideVersion
;
1193 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1194 Ver
->ProvidesList
= Prv
.Index();
1196 // Link it to the package
1197 Prv
->ParentPkg
= Pkg
.Index();
1198 Prv
->NextProvides
= Pkg
->ProvidesList
;
1199 Pkg
->ProvidesList
= Prv
.Index();
1203 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1204 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1205 StringView Version
, uint8_t const Flags
) {
1206 pkgCache
&Cache
= Owner
->Cache
;
1207 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1208 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1209 Dynamic
<StringView
> DynPackage(Package
);
1210 Dynamic
<StringView
> DynVersion(Version
);
1212 if (Grp
.end() == true)
1213 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1216 map_stringitem_t idxProvideVersion
= 0;
1217 if (Version
.empty() == false) {
1218 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1219 if (unlikely(idxProvideVersion
== 0))
1223 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1224 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1225 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1226 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1227 pkgCache::PkgIterator Pkg
;
1228 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1229 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1231 if (isImplicit
&& OwnerPkg
== Pkg
)
1233 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1235 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1242 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1243 pkgCache::VerIterator
const &Ver
)
1245 return Hash
== Ver
->Hash
;
1248 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1249 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1250 unsigned long Flags
)
1252 if (File
.empty() && Site
.empty())
1254 CurrentRlsFile
= NULL
;
1258 // Get some space for the structure
1259 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1260 if (unlikely(idxFile
== 0))
1262 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1265 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1266 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1267 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1269 CurrentRlsFile
->FileName
= idxFileName
;
1270 CurrentRlsFile
->Site
= idxSite
;
1271 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1272 CurrentRlsFile
->Flags
= Flags
;
1273 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1275 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1276 Cache
.HeaderP
->ReleaseFileCount
++;
1281 // ListParser::NewTag - Create a Tag element /*{{{*/
1282 // ---------------------------------------------------------------------
1284 bool pkgCacheListParser::NewTag(pkgCache::VerIterator
&Ver
,
1285 const char *NameStart
,
1286 unsigned int NameSize
)
1288 return Owner
->NewTag(Ver
, NameStart
, NameSize
);
1290 bool pkgCacheGenerator::NewTag(pkgCache::VerIterator
&Ver
,
1291 const char *NameStart
,
1292 unsigned int NameSize
)
1295 unsigned long Tagg
= AllocateInMap(sizeof(pkgCache::Tag
));
1298 Cache
.HeaderP
->TagCount
++;
1301 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ Tagg
);
1302 Tg
->Name
= WriteStringInMap(NameStart
,NameSize
);
1305 Tg
->NextTag
= Ver
->TagList
;
1306 Ver
->TagList
= Tg
.Index();
1311 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1312 // ---------------------------------------------------------------------
1313 /* This is used to select which file is to be associated with all newly
1314 added versions. The caller is responsible for setting the IMS fields. */
1315 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1316 pkgIndexFile
const &Index
,
1317 std::string
const &Architecture
,
1318 std::string
const &Component
,
1319 unsigned long const Flags
)
1321 // Get some space for the structure
1322 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1323 if (unlikely(idxFile
== 0))
1325 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1328 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1329 if (unlikely(idxFileName
== 0))
1331 CurrentFile
->FileName
= idxFileName
;
1332 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1333 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1334 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1335 if (unlikely(idxIndexType
== 0))
1337 CurrentFile
->IndexType
= idxIndexType
;
1338 if (Architecture
.empty())
1339 CurrentFile
->Architecture
= 0;
1342 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1343 if (unlikely(arch
== 0))
1345 CurrentFile
->Architecture
= arch
;
1347 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1348 if (unlikely(component
== 0))
1350 CurrentFile
->Component
= component
;
1351 CurrentFile
->Flags
= Flags
;
1352 if (CurrentRlsFile
!= NULL
)
1353 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1355 CurrentFile
->Release
= 0;
1357 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1358 Cache
.HeaderP
->PackageFileCount
++;
1361 Progress
->SubProgress(Index
.Size());
1365 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1366 // ---------------------------------------------------------------------
1367 /* This is used to create handles to strings. Given the same text it
1368 always returns the same number */
1369 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1372 auto strings
= &strMixed
;
1374 case MIXED
: strings
= &strMixed
; break;
1375 case PKGNAME
: strings
= &strPkgNames
; break;
1376 case VERSIONNUMBER
: strings
= &strVersions
; break;
1377 case SECTION
: strings
= &strSections
; break;
1378 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1381 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1382 if (item
!= strings
->end())
1385 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1386 strings
->insert({nullptr, Size
, this, idxString
});
1390 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1391 // ---------------------------------------------------------------------
1392 /* This just verifies that each file in the list of index files exists,
1393 has matching attributes with the cache and the cache does not have
1395 class APT_HIDDEN ScopedErrorRevert
{
1397 ScopedErrorRevert() { _error
->PushToStack(); }
1398 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1400 static bool CheckValidity(const string
&CacheFile
,
1401 pkgSourceList
&List
,
1402 FileIterator
const Start
,
1403 FileIterator
const End
,
1405 pkgCache
**OutCache
= 0)
1407 ScopedErrorRevert ser
;
1408 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1409 // No file, certainly invalid
1410 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1413 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1417 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1420 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1425 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1426 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1427 if (unlikely(Map
->validData()) == false)
1429 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1430 pkgCache
&Cache
= *CacheP
.get();
1431 if (_error
->PendingError() || Map
->Size() == 0)
1434 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1438 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1439 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1440 std::vector
<pkgIndexFile
*> Files
;
1441 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1444 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1445 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1446 if (RlsFile
.end() == true)
1449 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1453 RlsVisited
[RlsFile
->ID
] = true;
1455 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1457 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1458 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1459 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1461 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1462 if (RlsVisited
[I
] == false)
1465 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1469 std::copy(Start
, End
, std::back_inserter(Files
));
1471 /* Now we check every index file, see if it is in the cache,
1472 verify the IMS data and check that it is on the disk too.. */
1473 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1474 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1475 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1478 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1479 if ((*PkgFile
)->Exists() == false)
1482 std::clog
<< "file doesn't exist" << std::endl
;
1486 // FindInCache is also expected to do an IMS check.
1487 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1488 if (File
.end() == true)
1491 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1495 Visited
[File
->ID
] = true;
1497 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1500 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1501 if (Visited
[I
] == false)
1504 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1508 if (_error
->PendingError() == true)
1512 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1513 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1519 *OutMap
= Map
.release();
1521 *OutCache
= CacheP
.release();
1525 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1526 // ---------------------------------------------------------------------
1527 /* Size is kind of an abstract notion that is only used for the progress
1529 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1531 map_filesize_t TotalSize
= 0;
1534 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1536 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1537 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1538 if ((*j
)->HasPackages() == true)
1539 TotalSize
+= (*j
)->Size();
1543 for (; Start
< End
; ++Start
)
1545 if ((*Start
)->HasPackages() == false)
1547 TotalSize
+= (*Start
)->Size();
1552 // BuildCache - Merge the list of index files into the cache /*{{{*/
1553 static void BuildCache(pkgCacheGenerator
&Gen
,
1554 OpProgress
* const Progress
,
1555 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1556 pkgSourceList
const * const List
,
1557 FileIterator
const Start
, FileIterator
const End
)
1559 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1560 if (I
->HasPackages() == false)
1563 if (I
->Exists() == false)
1566 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1568 _error
->Warning("Duplicate sources.list entry %s",
1569 I
->Describe().c_str());
1573 map_filesize_t
const Size
= I
->Size();
1574 if (Progress
!= NULL
)
1575 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1576 CurrentSize
+= Size
;
1578 if (I
->Merge(Gen
,Progress
) == false)
1584 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1586 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1588 _error
->Warning("Duplicate sources.list entry %s",
1589 (*i
)->Describe().c_str());
1593 if ((*i
)->Merge(Gen
, Progress
) == false)
1596 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1597 if (Indexes
!= NULL
)
1598 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1604 Gen
.SelectReleaseFile("", "");
1605 std::for_each(Start
, End
, indexFileMerge
);
1609 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1610 // ---------------------------------------------------------------------
1611 /* This makes sure that the status cache (the cache that has all
1612 index files from the sources list and all local ones) is ready
1613 to be mmaped. If OutMap is not zero then a MMap object representing
1614 the cache will be stored there. This is pretty much mandetory if you
1615 are using AllowMem. AllowMem lets the function be run as non-root
1616 where it builds the cache 'fast' into a memory buffer. */
1617 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1619 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1620 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1621 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1622 Flags
|= MMap::Moveable
;
1623 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1624 Flags
|= MMap::Fallback
;
1626 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1628 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1630 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1631 std::string
const &FileName
)
1633 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1634 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1637 fchmod(SCacheF
.Fd(),0644);
1639 // Write out the main data
1640 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1641 return _error
->Error(_("IO Error saving source cache"));
1643 // Write out the proper header
1644 Gen
->GetCache().HeaderP
->Dirty
= false;
1645 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1646 if (SCacheF
.Seek(0) == false ||
1647 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1648 return _error
->Error(_("IO Error saving source cache"));
1649 Gen
->GetCache().HeaderP
->Dirty
= true;
1652 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1653 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1655 Map
.reset(CreateDynamicMMap(NULL
, 0));
1656 if (unlikely(Map
->validData()) == false)
1658 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1659 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1661 _error
->PushToStack();
1662 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1663 bool const newError
= _error
->PendingError();
1664 _error
->MergeWithStack();
1665 if (alloc
== 0 && newError
)
1667 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1669 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1670 return Gen
->Start();
1672 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1673 MMap
**OutMap
, bool AllowMem
)
1674 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1675 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1678 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1680 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1681 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1683 // FIXME: deprecate the ignored AllowMem parameter
1684 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1686 std::vector
<pkgIndexFile
*> Files
;
1687 if (_system
->AddStatusFiles(Files
) == false)
1690 // Decide if we can write to the files..
1691 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1692 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1694 // ensure the cache directory exists
1695 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1697 string dir
= _config
->FindDir("Dir::Cache");
1698 size_t const len
= dir
.size();
1699 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1700 dir
= dir
.substr(0, len
- 5);
1701 if (CacheFile
.empty() == false)
1702 CreateDirectory(dir
, flNotFile(CacheFile
));
1703 if (SrcCacheFile
.empty() == false)
1704 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1707 if (Progress
!= NULL
)
1708 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1710 bool pkgcache_fine
= false;
1711 bool srcpkgcache_fine
= false;
1712 bool volatile_fine
= List
.GetVolatileFiles().empty();
1714 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1715 volatile_fine
? OutCache
: NULL
) == true)
1718 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1719 pkgcache_fine
= true;
1720 srcpkgcache_fine
= true;
1722 if (pkgcache_fine
== false)
1724 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1727 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1728 srcpkgcache_fine
= true;
1732 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1734 if (Progress
!= NULL
)
1735 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1739 bool Writeable
= false;
1740 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1742 if (CacheFile
.empty() == false)
1743 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1744 else if (SrcCacheFile
.empty() == false)
1745 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1748 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1751 // At this point we know we need to construct something, so get storage ready
1752 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1753 if (unlikely(Map
->validData()) == false)
1756 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1758 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1759 map_filesize_t CurrentSize
= 0;
1760 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1761 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1762 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1765 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1766 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1768 srcpkgcache_fine
= true;
1769 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1771 else if (srcpkgcache_fine
== false)
1774 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1775 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1776 if (Gen
->Start() == false)
1779 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1780 BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1781 Files
.end(),Files
.end());
1783 if (Writeable
== true && SrcCacheFile
.empty() == false)
1784 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1788 if (pkgcache_fine
== false)
1791 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1792 BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1793 Files
.begin(), Files
.end());
1795 if (Writeable
== true && CacheFile
.empty() == false)
1796 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1801 std::clog
<< "Caches done. " << (volatile_fine
? "No volatile files, so we are done here." : "Now bring in the volatile files") << std::endl
;
1803 if (volatile_fine
== false)
1808 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1809 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1813 Files
= List
.GetVolatileFiles();
1814 BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1815 Files
.begin(), Files
.end());
1818 if (OutMap
!= nullptr)
1819 *OutMap
= Map
.release();
1822 std::clog
<< "Everything is ready for shipping" << std::endl
;
1826 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1827 class APT_HIDDEN ScopedErrorMerge
{
1829 ScopedErrorMerge() { _error
->PushToStack(); }
1830 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1832 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1833 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1834 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1836 std::vector
<pkgIndexFile
*> Files
;
1837 if (_system
->AddStatusFiles(Files
) == false)
1840 ScopedErrorMerge sem
;
1841 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1842 if (unlikely(Map
->validData()) == false)
1844 map_filesize_t CurrentSize
= 0;
1845 map_filesize_t TotalSize
= 0;
1846 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1848 // Build the status cache
1849 if (Progress
!= NULL
)
1850 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1851 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1852 if (Gen
.Start() == false || _error
->PendingError() == true)
1854 BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1855 Files
.begin(), Files
.end());
1857 if (_error
->PendingError() == true)
1859 *OutMap
= Map
.release();
1864 // IsDuplicateDescription /*{{{*/
1865 static bool IsDuplicateDescription(pkgCache
&Cache
, pkgCache::DescIterator Desc
,
1866 APT::StringView CurMd5
, std::string
const &CurLang
)
1868 // Descriptions in the same link-list have all the same md5
1869 if (Desc
.end() == true || Cache
.ViewString(Desc
->md5sum
) != CurMd5
)
1871 for (; Desc
.end() == false; ++Desc
)
1872 if (Desc
.LanguageCode() == CurLang
)
1878 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1879 pkgCacheListParser::~pkgCacheListParser() {}