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();
73 return _error
->ReturnError();
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 (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::TagIterator
*>::const_iterator i
= Dynamic
<pkgCache::TagIterator
>::toReMap
.begin();
179 i
!= Dynamic
<pkgCache::TagIterator
>::toReMap
.end(); ++i
)
180 if (std::get
<1>(seen
.insert(*i
)) == true)
181 (*i
)->ReMap(oldMap
, newMap
);
182 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
183 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
184 if (std::get
<1>(seen
.insert(*i
)) == true)
185 (*i
)->ReMap(oldMap
, newMap
);
186 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
187 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
188 if (std::get
<1>(seen
.insert(*i
)) == true)
189 (*i
)->ReMap(oldMap
, newMap
);
190 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
191 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
192 if (std::get
<1>(seen
.insert(*i
)) == true)
193 (*i
)->ReMap(oldMap
, newMap
);
194 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
195 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
196 if (std::get
<1>(seen
.insert(*i
)) == true)
197 (*i
)->ReMap(oldMap
, newMap
);
198 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
199 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
200 if (std::get
<1>(seen
.insert(*i
)) == true)
201 (*i
)->ReMap(oldMap
, newMap
);
202 for (APT::StringView
* ViewP
: Dynamic
<APT::StringView
>::toReMap
) {
203 if (std::get
<1>(seen
.insert(ViewP
)) == false)
205 // Ignore views outside of the cache.
206 if (ViewP
->data() < static_cast<const char*>(oldMap
)
207 || ViewP
->data() > static_cast<const char*>(oldMap
) + oldSize
)
209 const char *data
= ViewP
->data() + (static_cast<const char*>(newMap
) - static_cast<const char*>(oldMap
));
210 *ViewP
= StringView(data
, ViewP
->size());
213 // CacheGenerator::WriteStringInMap /*{{{*/
214 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
215 const unsigned long &Len
) {
216 size_t oldSize
= Map
.Size();
217 void const * const oldMap
= Map
.Data();
218 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
220 ReMap(oldMap
, Map
.Data(), oldSize
);
224 // CacheGenerator::WriteStringInMap /*{{{*/
225 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
226 size_t oldSize
= Map
.Size();
227 void const * const oldMap
= Map
.Data();
228 map_stringitem_t
const index
= Map
.WriteString(String
);
230 ReMap(oldMap
, Map
.Data(), oldSize
);
234 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
235 size_t oldSize
= Map
.Size();
236 void const * const oldMap
= Map
.Data();
237 map_pointer_t
const index
= Map
.Allocate(size
);
239 ReMap(oldMap
, Map
.Data(), oldSize
);
243 // CacheGenerator::MergeList - Merge the package list /*{{{*/
244 // ---------------------------------------------------------------------
245 /* This provides the generation of the entries in the cache. Each loop
246 goes through a single package record from the underlying parse engine. */
247 bool pkgCacheGenerator::MergeList(ListParser
&List
,
248 pkgCache::VerIterator
*OutVer
)
252 unsigned int Counter
= 0;
253 while (List
.Step() == true)
255 string
const PackageName
= List
.Package();
256 if (PackageName
.empty() == true)
260 if (Counter
% 100 == 0 && Progress
!= 0)
261 Progress
->Progress(List
.Offset());
263 APT::StringView Arch
= List
.Architecture();
264 Dynamic
<APT::StringView
> DynArch(Arch
);
265 APT::StringView Version
= List
.Version();
266 Dynamic
<APT::StringView
> DynVersion(Version
);
267 if (Version
.empty() == true && Arch
.empty() == true)
269 // package descriptions
270 if (MergeListGroup(List
, PackageName
) == false)
275 // Get a pointer to the package structure
276 pkgCache::PkgIterator Pkg
;
277 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
278 if (NewPackage(Pkg
, PackageName
, Arch
) == false) {
279 // TRANSLATOR: The first placeholder is a package name,
280 // the other two should be copied verbatim as they include debug info
281 _error
->Error(_("Error occurred while processing %s (%s%d)"),
282 PackageName
.c_str(), "NewPackage", 1);
287 if (Version
.empty() == true)
289 if (MergeListPackage(List
, Pkg
) == false)
294 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
302 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
303 return _error
->Error(_("Wow, you exceeded the number of package "
304 "names this APT is capable of."));
305 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
306 return _error
->Error(_("Wow, you exceeded the number of versions "
307 "this APT is capable of."));
308 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
309 return _error
->Error(_("Wow, you exceeded the number of descriptions "
310 "this APT is capable of."));
311 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
312 return _error
->Error(_("Wow, you exceeded the number of dependencies "
313 "this APT is capable of."));
317 // CacheGenerator::MergeListGroup /*{{{*/
318 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
320 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
321 // a group has no data on it's own, only packages have it but these
322 // stanzas like this come from Translation- files to add descriptions,
323 // but without a version we don't need a description for it…
324 if (Grp
.end() == true)
326 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
328 pkgCache::PkgIterator Pkg
;
329 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
330 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
331 if (MergeListPackage(List
, Pkg
) == false)
337 // CacheGenerator::MergeListPackage /*{{{*/
338 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
340 // we first process the package, then the descriptions
341 // (for deb this package processing is in fact a no-op)
342 pkgCache::VerIterator
Ver(Cache
);
343 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
344 if (List
.UsePackage(Pkg
, Ver
) == false)
345 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
346 Pkg
.Name(), "UsePackage", 1);
348 // Find the right version to write the description
349 StringView CurMd5
= List
.Description_md5();
350 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
351 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
353 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
355 // a version can only have one md5 describing it
356 if (VerDesc
.end() == true || Cache
.ViewString(VerDesc
->md5sum
) != CurMd5
)
359 map_stringitem_t md5idx
= VerDesc
->md5sum
;
360 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
362 // don't add a new description if we have one for the given
364 if (IsDuplicateDescription(Cache
, VerDesc
, CurMd5
, *CurLang
) == true)
367 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
370 // we can stop here as all "same" versions will share the description
377 // CacheGenerator::MergeListVersion /*{{{*/
378 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
379 APT::StringView
const &Version
, pkgCache::VerIterator
* &OutVer
)
381 pkgCache::VerIterator Ver
= Pkg
.VersionList();
382 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
383 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
384 void const * oldMap
= Map
.Data();
386 unsigned short const Hash
= List
.VersionHash();
387 if (Ver
.end() == false)
389 /* We know the list is sorted so we use that fact in the search.
390 Insertion of new versions is done with correct sorting */
392 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
394 char const * const VerStr
= Ver
.VerStr();
395 Res
= Cache
.VS
->DoCmpVersion(Version
.data(), Version
.data() + Version
.length(),
396 VerStr
, VerStr
+ strlen(VerStr
));
397 // Version is higher as current version - insert here
400 // Versionstrings are equal - is hash also equal?
403 if (List
.SameVersion(Hash
, Ver
) == true)
405 // sort (volatile) sources above not-sources like the status file
406 if ((CurrentFile
->Flags
& pkgCache::Flag::NotSource
) == 0)
408 auto VF
= Ver
.FileList();
409 for (; VF
.end() == false; ++VF
)
410 if (VF
.File().Flagged(pkgCache::Flag::NotSource
) == false)
412 if (VF
.end() == true)
416 // proceed with the next till we have either the right
417 // or we found another version (which will be lower)
420 /* We already have a version for this item, record that we saw it */
421 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
423 if (List
.UsePackage(Pkg
,Ver
) == false)
424 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
425 Pkg
.Name(), "UsePackage", 2);
427 if (NewFileVer(Ver
,List
) == false)
428 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
429 Pkg
.Name(), "NewFileVer", 1);
431 // Read only a single record and return
443 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
444 if (unlikely(verindex
== 0))
445 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
446 Pkg
.Name(), "NewVersion", 1);
448 if (oldMap
!= Map
.Data())
449 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
452 if (unlikely(List
.NewVersion(Ver
) == false))
453 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
454 Pkg
.Name(), "NewVersion", 2);
456 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
457 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
458 Pkg
.Name(), "UsePackage", 3);
460 if (unlikely(NewFileVer(Ver
,List
) == false))
461 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
462 Pkg
.Name(), "NewFileVer", 2);
464 pkgCache::GrpIterator Grp
= Pkg
.Group();
465 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
467 /* If it is the first version of this package we need to add implicit
468 Multi-Arch dependencies to all other package versions in the group now -
469 otherwise we just add them for this new version */
470 if (Pkg
.VersionList()->NextVer
== 0)
472 pkgCache::PkgIterator P
= Grp
.PackageList();
473 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
474 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
476 if (P
->ID
== Pkg
->ID
)
478 pkgCache::VerIterator V
= P
.VersionList();
479 Dynamic
<pkgCache::VerIterator
> DynV(V
);
480 for (; V
.end() != true; ++V
)
481 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
482 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
483 Pkg
.Name(), "AddImplicitDepends", 1);
486 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
487 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
488 Pkg
.Name(), "AddImplicitDepends", 2);
490 // Read only a single record and return
497 /* Record the Description(s) based on their master md5sum */
498 StringView CurMd5
= List
.Description_md5();
500 /* Before we add a new description we first search in the group for
501 a version with a description of the same MD5 - if so we reuse this
502 description group instead of creating our own for this version */
503 for (pkgCache::PkgIterator P
= Grp
.PackageList();
504 P
.end() == false; P
= Grp
.NextPkg(P
))
506 for (pkgCache::VerIterator V
= P
.VersionList();
507 V
.end() == false; ++V
)
509 if (V
->DescriptionList
== 0 || Cache
.ViewString(V
.DescriptionList()->md5sum
) != CurMd5
)
511 Ver
->DescriptionList
= V
->DescriptionList
;
515 // We haven't found reusable descriptions, so add the first description(s)
516 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
517 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
518 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
519 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
524 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, APT::StringView CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
526 pkgCache::DescIterator Desc
;
527 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
529 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
530 if (unlikely(descindex
== 0))
531 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
532 Ver
.ParentPkg().Name(), "NewDescription", 1);
534 md5idx
= Desc
->md5sum
;
535 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
537 // we add at the end, so that the start is constant as we need
538 // that to be able to efficiently share these lists
539 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
540 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
541 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
542 *LastNextDesc
= descindex
;
544 if (NewFileDesc(Desc
,List
) == false)
545 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
546 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
552 // CacheGenerator::NewGroup - Add a new group /*{{{*/
553 // ---------------------------------------------------------------------
554 /* This creates a new group structure and adds it to the hash table */
555 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
557 Dynamic
<StringView
> DName(Name
);
558 Grp
= Cache
.FindGrp(Name
);
559 if (Grp
.end() == false)
563 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
564 if (unlikely(Group
== 0))
567 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
568 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
569 if (unlikely(idxName
== 0))
573 // Insert it into the hash table
574 unsigned long const Hash
= Cache
.Hash(Name
);
575 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
577 while (*insertAt
!= 0 && StringViewCompareFast(Name
, Cache
.ViewString((Cache
.GrpP
+ *insertAt
)->Name
)) > 0)
578 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
579 Grp
->Next
= *insertAt
;
582 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
586 // CacheGenerator::NewPackage - Add a new package /*{{{*/
587 // ---------------------------------------------------------------------
588 /* This creates a new package structure and adds it to the hash table */
589 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
591 pkgCache::GrpIterator Grp
;
592 Dynamic
<StringView
> DName(Name
);
593 Dynamic
<StringView
> DArch(Arch
);
594 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
595 if (unlikely(NewGroup(Grp
, Name
) == false))
598 Pkg
= Grp
.FindPkg(Arch
);
599 if (Pkg
.end() == false)
603 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
604 if (unlikely(Package
== 0))
606 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
608 // Set the name, arch and the ID
609 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
610 Pkg
->Group
= Grp
.Index();
611 // all is mapped to the native architecture
612 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
613 if (unlikely(idxArch
== 0))
616 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
618 // Insert the package into our package list
619 if (Grp
->FirstPackage
== 0) // the group is new
621 Grp
->FirstPackage
= Package
;
622 // Insert it into the hash table
623 map_id_t
const Hash
= Cache
.Hash(Name
);
624 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
625 while (*insertAt
!= 0 && StringViewCompareFast(Name
, Cache
.ViewString((Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
)) > 0)
626 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
627 Pkg
->NextPackage
= *insertAt
;
630 else // Group the Packages together
632 // if sibling is provided by another package, this one is too
634 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
635 if (M
.end() == false) {
636 pkgCache::PrvIterator Prv
;
637 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
638 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
640 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
642 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
643 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
644 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
645 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
646 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
648 if (APT::Configuration::checkArchitecture(Ver
.ParentPkg().Arch()) == false)
650 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
656 // let M-A:foreign package siblings provide this package
658 pkgCache::PkgIterator P
;
659 pkgCache::VerIterator Ver
;
660 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
661 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
663 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
665 if (APT::Configuration::checkArchitecture(P
.Arch()) == false)
667 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
668 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
669 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
673 // and negative dependencies, don't forget negative dependencies
675 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
676 if (M
.end() == false) {
677 pkgCache::DepIterator Dep
;
678 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
679 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
681 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
683 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
684 Dep
->Type
!= pkgCache::Dep::Replaces
)
686 pkgCache::VerIterator Ver
= Dep
.ParentVer();
687 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
688 map_pointer_t
* unused
= NULL
;
689 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
695 // this package is the new last package
696 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
697 Pkg
->NextPackage
= LastPkg
->NextPackage
;
698 LastPkg
->NextPackage
= Package
;
700 Grp
->LastPackage
= Package
;
702 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
705 size_t const found
= Name
.rfind(':');
706 StringView ArchA
= Name
.substr(found
+ 1);
709 // ArchA is used inside the loop which might remap (NameA is not used)
710 Dynamic
<StringView
> DynArchA(ArchA
);
711 StringView NameA
= Name
.substr(0, found
);
712 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
713 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
716 Dynamic
<StringView
> DynNameA(NameA
);
717 if (NewPackage(PkgA
, NameA
, ArchA
) == false)
720 if (unlikely(PkgA
.end()))
721 return _error
->Fatal("NewPackage was successful for %s:%s,"
722 "but the package doesn't exist anyhow!",
723 NameA
.to_string().c_str(), ArchA
.to_string().c_str());
726 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
727 for (; Prv
.end() == false; ++Prv
)
729 if (Prv
.IsMultiArchImplicit())
731 pkgCache::VerIterator V
= Prv
.OwnerVer();
732 if (ArchA
!= V
.ParentPkg().Arch())
734 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
737 pkgCache::VerIterator V
= PkgA
.VersionList();
738 Dynamic
<pkgCache::VerIterator
> DynV(V
);
739 for (; V
.end() == false; ++V
)
741 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
750 // CacheGenerator::AddImplicitDepends /*{{{*/
751 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
752 pkgCache::PkgIterator
&P
,
753 pkgCache::VerIterator
&V
)
755 APT::StringView Arch
= P
.Arch() == NULL
? "" : P
.Arch();
756 Dynamic
<APT::StringView
> DynArch(Arch
);
757 map_pointer_t
*OldDepLast
= NULL
;
758 /* MultiArch handling introduces a lot of implicit Dependencies:
759 - MultiArch: same → Co-Installable if they have the same version
760 - All others conflict with all other group members */
761 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
762 pkgCache::PkgIterator D
= G
.PackageList();
763 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
764 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
765 for (; D
.end() != true; D
= G
.NextPkg(D
))
767 if (Arch
== D
.Arch() || D
->VersionList
== 0)
769 /* We allow only one installed arch at the time
770 per group, therefore each group member conflicts
771 with all other group members */
772 if (coInstall
== true)
774 // Replaces: ${self}:other ( << ${binary:Version})
775 NewDepends(D
, V
, VerStrIdx
,
776 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
778 // Breaks: ${self}:other (!= ${binary:Version})
779 NewDepends(D
, V
, VerStrIdx
,
780 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
783 // Conflicts: ${self}:other
785 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
791 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
792 pkgCache::PkgIterator
&D
)
794 /* MultiArch handling introduces a lot of implicit Dependencies:
795 - MultiArch: same → Co-Installable if they have the same version
796 - All others conflict with all other group members */
797 map_pointer_t
*OldDepLast
= NULL
;
798 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
799 if (coInstall
== true)
801 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
802 // Replaces: ${self}:other ( << ${binary:Version})
803 NewDepends(D
, V
, VerStrIdx
,
804 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
806 // Breaks: ${self}:other (!= ${binary:Version})
807 NewDepends(D
, V
, VerStrIdx
,
808 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
811 // Conflicts: ${self}:other
813 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
820 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
821 // ---------------------------------------------------------------------
823 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
826 if (CurrentFile
== 0)
830 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
834 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
835 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
837 // Link it to the end of the list
838 map_pointer_t
*Last
= &Ver
->FileList
;
839 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
841 VF
->NextFile
= *Last
;
844 VF
->Offset
= List
.Offset();
845 VF
->Size
= List
.Size();
846 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
847 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
848 Cache
.HeaderP
->VerFileCount
++;
853 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
854 // ---------------------------------------------------------------------
855 /* This puts a version structure in the linked list */
856 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
857 APT::StringView
const &VerStr
,
858 map_pointer_t
const ParentPkg
,
859 unsigned short const Hash
,
860 map_pointer_t
const Next
)
863 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
868 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
869 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
871 Ver
->ParentPkg
= ParentPkg
;
873 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
875 // try to find the version string in the group for reuse
876 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
877 pkgCache::GrpIterator Grp
= Pkg
.Group();
878 if (Pkg
.end() == false && Grp
.end() == false)
880 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
884 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
886 int const cmp
= strncmp(V
.VerStr(), VerStr
.data(), VerStr
.length());
887 if (cmp
== 0 && V
.VerStr()[VerStr
.length()] == '\0')
889 Ver
->VerStr
= V
->VerStr
;
897 // haven't found the version string, so create
898 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
899 if (unlikely(idxVerStr
== 0))
901 Ver
->VerStr
= idxVerStr
;
905 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
906 // ---------------------------------------------------------------------
908 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
911 if (CurrentFile
== 0)
915 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
919 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
920 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
922 // Link it to the end of the list
923 map_pointer_t
*Last
= &Desc
->FileList
;
924 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
927 DF
->NextFile
= *Last
;
930 DF
->Offset
= List
.Offset();
931 DF
->Size
= List
.Size();
932 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
933 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
934 Cache
.HeaderP
->DescFileCount
++;
939 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
940 // ---------------------------------------------------------------------
941 /* This puts a description structure in the linked list */
942 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
944 APT::StringView md5sum
,
945 map_stringitem_t
const idxmd5str
)
948 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
949 if (Description
== 0)
953 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
954 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
955 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
956 if (unlikely(idxlanguage_code
== 0))
958 Desc
->language_code
= idxlanguage_code
;
961 Desc
->md5sum
= idxmd5str
;
964 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
);
965 if (unlikely(idxmd5sum
== 0))
967 Desc
->md5sum
= idxmd5sum
;
973 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
974 // ---------------------------------------------------------------------
975 /* This creates a dependency element in the tree. It is linked to the
976 version and to the package that it is pointing to. */
977 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
978 pkgCache::VerIterator
&Ver
,
979 map_pointer_t
const Version
,
982 map_pointer_t
* &OldDepLast
)
984 void const * const oldMap
= Map
.Data();
986 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
987 if (unlikely(Dependency
== 0))
990 bool isDuplicate
= false;
991 map_pointer_t DependencyData
= 0;
992 map_pointer_t PreviousData
= 0;
993 if (Pkg
->RevDepends
!= 0)
995 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
996 DependencyData
= L
->DependencyData
;
998 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
999 if (Version
> D
->Version
)
1001 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
1006 PreviousData
= DependencyData
;
1007 DependencyData
= D
->NextData
;
1008 } while (DependencyData
!= 0);
1011 if (isDuplicate
== false)
1013 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
1014 if (unlikely(DependencyData
== 0))
1018 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
1019 Link
->ParentVer
= Ver
.Index();
1020 Link
->DependencyData
= DependencyData
;
1021 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
1023 pkgCache::DepIterator
Dep(Cache
, Link
);
1024 if (isDuplicate
== false)
1027 Dep
->CompareOp
= Op
;
1028 Dep
->Version
= Version
;
1029 Dep
->Package
= Pkg
.Index();
1030 ++Cache
.HeaderP
->DependsDataCount
;
1031 if (PreviousData
!= 0)
1033 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
1034 Dep
->NextData
= D
->NextData
;
1035 D
->NextData
= DependencyData
;
1037 else if (Pkg
->RevDepends
!= 0)
1039 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
1040 Dep
->NextData
= D
->DependencyData
;
1044 if (isDuplicate
== true || PreviousData
!= 0)
1046 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
1047 Link
->NextRevDepends
= L
->NextRevDepends
;
1048 L
->NextRevDepends
= Dependency
;
1052 Link
->NextRevDepends
= Pkg
->RevDepends
;
1053 Pkg
->RevDepends
= Dependency
;
1057 // Do we know where to link the Dependency to?
1058 if (OldDepLast
== NULL
)
1060 OldDepLast
= &Ver
->DependsList
;
1061 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
1062 OldDepLast
= &D
->NextDepends
;
1063 } else if (oldMap
!= Map
.Data())
1064 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
1066 Dep
->NextDepends
= *OldDepLast
;
1067 *OldDepLast
= Dependency
;
1068 OldDepLast
= &Dep
->NextDepends
;
1072 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1073 // ---------------------------------------------------------------------
1074 /* This creates a Group and the Package to link this dependency to if
1075 needed and handles also the caching of the old endpoint */
1076 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1077 StringView PackageName
,
1083 pkgCache::GrpIterator Grp
;
1084 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1085 Dynamic
<StringView
> DynPackageName(PackageName
);
1086 Dynamic
<StringView
> DynArch(Arch
);
1087 Dynamic
<StringView
> DynVersion(Version
);
1088 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1091 map_stringitem_t idxVersion
= 0;
1092 if (Version
.empty() == false)
1094 int const CmpOp
= Op
& 0x0F;
1095 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1096 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1097 idxVersion
= Ver
->VerStr
;
1099 if (idxVersion
== 0)
1101 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1102 if (unlikely(idxVersion
== 0))
1107 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1108 Type
== pkgCache::Dep::Conflicts
||
1109 Type
== pkgCache::Dep::Replaces
);
1111 pkgCache::PkgIterator Pkg
;
1112 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1113 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1115 // Locate the target package
1116 Pkg
= Grp
.FindPkg(Arch
);
1117 if (Pkg
.end() == true) {
1118 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1122 /* Caching the old end point speeds up generation substantially */
1123 if (OldDepVer
!= Ver
) {
1128 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1132 /* Caching the old end point speeds up generation substantially */
1133 if (OldDepVer
!= Ver
) {
1138 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1140 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1147 // ListParser::NewProvides - Create a Provides element /*{{{*/
1148 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1152 uint8_t const Flags
)
1154 pkgCache
const &Cache
= Owner
->Cache
;
1155 Dynamic
<StringView
> DynPkgName(PkgName
);
1156 Dynamic
<StringView
> DynArch(PkgArch
);
1157 Dynamic
<StringView
> DynVersion(Version
);
1159 // We do not add self referencing provides
1160 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1161 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1162 (Version
.empty() || Version
== Ver
.VerStr()))
1165 // Locate the target package
1166 pkgCache::PkgIterator Pkg
;
1167 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1168 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1171 map_stringitem_t idxProvideVersion
= 0;
1172 if (Version
.empty() == false) {
1173 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1174 if (unlikely(idxProvideVersion
== 0))
1177 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1179 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1180 pkgCache::PkgIterator
&Pkg
,
1181 map_pointer_t
const ProvideVersion
,
1182 uint8_t const Flags
)
1185 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1186 if (unlikely(Provides
== 0))
1188 ++Cache
.HeaderP
->ProvidesCount
;
1191 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1192 Prv
->Version
= Ver
.Index();
1193 Prv
->ProvideVersion
= ProvideVersion
;
1195 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1196 Ver
->ProvidesList
= Prv
.Index();
1198 // Link it to the package
1199 Prv
->ParentPkg
= Pkg
.Index();
1200 Prv
->NextProvides
= Pkg
->ProvidesList
;
1201 Pkg
->ProvidesList
= Prv
.Index();
1205 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1206 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1207 StringView Version
, uint8_t const Flags
) {
1208 pkgCache
&Cache
= Owner
->Cache
;
1209 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1210 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1211 Dynamic
<StringView
> DynPackage(Package
);
1212 Dynamic
<StringView
> DynVersion(Version
);
1214 if (Grp
.end() == true)
1215 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1218 map_stringitem_t idxProvideVersion
= 0;
1219 if (Version
.empty() == false) {
1220 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1221 if (unlikely(idxProvideVersion
== 0))
1225 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1226 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1227 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1228 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1229 pkgCache::PkgIterator Pkg
;
1230 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1231 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1233 if (isImplicit
&& OwnerPkg
== Pkg
)
1235 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1237 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1244 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1245 pkgCache::VerIterator
const &Ver
)
1247 return Hash
== Ver
->Hash
;
1250 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1251 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1252 unsigned long Flags
)
1254 if (File
.empty() && Site
.empty())
1256 CurrentRlsFile
= NULL
;
1260 // Get some space for the structure
1261 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1262 if (unlikely(idxFile
== 0))
1264 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1267 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1268 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1269 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1271 CurrentRlsFile
->FileName
= idxFileName
;
1272 CurrentRlsFile
->Site
= idxSite
;
1273 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1274 CurrentRlsFile
->Flags
= Flags
;
1275 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1277 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1278 Cache
.HeaderP
->ReleaseFileCount
++;
1283 // ListParser::NewTag - Create a Tag element /*{{{*/
1284 // ---------------------------------------------------------------------
1286 bool pkgCacheListParser::NewTag(pkgCache::VerIterator
&Ver
,
1287 const char *NameStart
,
1288 unsigned int NameSize
)
1290 return Owner
->NewTag(Ver
, NameStart
, NameSize
);
1292 bool pkgCacheGenerator::NewTag(pkgCache::VerIterator
&Ver
,
1293 const char *NameStart
,
1294 unsigned int NameSize
)
1297 map_pointer_t
const idxTag
= AllocateInMap(sizeof(pkgCache::Tag
));
1298 if (unlikely(idxTag
== 0))
1302 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ idxTag
);
1303 map_pointer_t
const idxName
= StoreString(TAG
,NameStart
,NameSize
);
1308 Tg
->NextTag
= Ver
->TagList
;
1309 Ver
->TagList
= Tg
.Index();
1310 Cache
.HeaderP
->TagCount
++;
1315 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1316 // ---------------------------------------------------------------------
1317 /* This is used to select which file is to be associated with all newly
1318 added versions. The caller is responsible for setting the IMS fields. */
1319 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1320 pkgIndexFile
const &Index
,
1321 std::string
const &Architecture
,
1322 std::string
const &Component
,
1323 unsigned long const Flags
)
1325 // Get some space for the structure
1326 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1327 if (unlikely(idxFile
== 0))
1329 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1332 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1333 if (unlikely(idxFileName
== 0))
1335 CurrentFile
->FileName
= idxFileName
;
1336 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1337 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1338 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1339 if (unlikely(idxIndexType
== 0))
1341 CurrentFile
->IndexType
= idxIndexType
;
1342 if (Architecture
.empty())
1343 CurrentFile
->Architecture
= 0;
1346 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1347 if (unlikely(arch
== 0))
1349 CurrentFile
->Architecture
= arch
;
1351 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1352 if (unlikely(component
== 0))
1354 CurrentFile
->Component
= component
;
1355 CurrentFile
->Flags
= Flags
;
1356 if (CurrentRlsFile
!= NULL
)
1357 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1359 CurrentFile
->Release
= 0;
1361 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1362 Cache
.HeaderP
->PackageFileCount
++;
1365 Progress
->SubProgress(Index
.Size());
1369 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1370 // ---------------------------------------------------------------------
1371 /* This is used to create handles to strings. Given the same text it
1372 always returns the same number */
1373 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1376 auto strings
= &strMixed
;
1378 case MIXED
: strings
= &strMixed
; break;
1379 case PKGNAME
: strings
= &strPkgNames
; break;
1380 case VERSIONNUMBER
: strings
= &strVersions
; break;
1381 case SECTION
: strings
= &strSections
; break;
1382 case TAG
: strings
= &strTags
; break;
1383 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1386 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1387 if (item
!= strings
->end())
1390 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1391 strings
->insert({nullptr, Size
, this, idxString
});
1395 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1396 // ---------------------------------------------------------------------
1397 /* This just verifies that each file in the list of index files exists,
1398 has matching attributes with the cache and the cache does not have
1400 class APT_HIDDEN ScopedErrorRevert
{
1402 ScopedErrorRevert() { _error
->PushToStack(); }
1403 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1405 static bool CheckValidity(const string
&CacheFile
,
1406 pkgSourceList
&List
,
1407 FileIterator
const Start
,
1408 FileIterator
const End
,
1410 pkgCache
**OutCache
= 0)
1412 ScopedErrorRevert ser
;
1413 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1414 // No file, certainly invalid
1415 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1418 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1422 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1425 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1430 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1431 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1432 if (unlikely(Map
->validData()) == false)
1434 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1435 pkgCache
&Cache
= *CacheP
.get();
1436 if (_error
->PendingError() || Map
->Size() == 0)
1439 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1440 return _error
->ReturnError();
1443 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1444 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1445 std::vector
<pkgIndexFile
*> Files
;
1446 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1449 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1450 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1451 if (RlsFile
.end() == true)
1454 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1458 RlsVisited
[RlsFile
->ID
] = true;
1460 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1462 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1463 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1464 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1466 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1467 if (RlsVisited
[I
] == false)
1470 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1474 std::copy(Start
, End
, std::back_inserter(Files
));
1476 /* Now we check every index file, see if it is in the cache,
1477 verify the IMS data and check that it is on the disk too.. */
1478 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1479 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1480 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1483 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1484 if ((*PkgFile
)->Exists() == false)
1487 std::clog
<< "file doesn't exist" << std::endl
;
1491 // FindInCache is also expected to do an IMS check.
1492 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1493 if (File
.end() == true)
1496 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1500 Visited
[File
->ID
] = true;
1502 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1505 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1506 if (Visited
[I
] == false)
1509 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1513 if (_error
->PendingError() == true)
1517 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1518 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1520 return _error
->ReturnError();
1524 *OutMap
= Map
.release();
1526 *OutCache
= CacheP
.release();
1530 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1531 // ---------------------------------------------------------------------
1532 /* Size is kind of an abstract notion that is only used for the progress
1534 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1536 map_filesize_t TotalSize
= 0;
1539 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1541 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1542 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1543 if ((*j
)->HasPackages() == true)
1544 TotalSize
+= (*j
)->Size();
1548 for (; Start
< End
; ++Start
)
1550 if ((*Start
)->HasPackages() == false)
1552 TotalSize
+= (*Start
)->Size();
1557 // BuildCache - Merge the list of index files into the cache /*{{{*/
1558 static void BuildCache(pkgCacheGenerator
&Gen
,
1559 OpProgress
* const Progress
,
1560 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1561 pkgSourceList
const * const List
,
1562 FileIterator
const Start
, FileIterator
const End
)
1564 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1565 if (I
->HasPackages() == false)
1568 if (I
->Exists() == false)
1571 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1573 _error
->Warning("Duplicate sources.list entry %s",
1574 I
->Describe().c_str());
1578 map_filesize_t
const Size
= I
->Size();
1579 if (Progress
!= NULL
)
1580 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1581 CurrentSize
+= Size
;
1583 if (I
->Merge(Gen
,Progress
) == false) {
1584 _error
->ReturnError();
1591 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1593 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1595 _error
->Warning("Duplicate sources.list entry %s",
1596 (*i
)->Describe().c_str());
1600 if ((*i
)->Merge(Gen
, Progress
) == false) {
1601 _error
->ReturnError();
1605 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1606 if (Indexes
!= NULL
)
1607 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1613 Gen
.SelectReleaseFile("", "");
1614 std::for_each(Start
, End
, indexFileMerge
);
1618 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1619 // ---------------------------------------------------------------------
1620 /* This makes sure that the status cache (the cache that has all
1621 index files from the sources list and all local ones) is ready
1622 to be mmaped. If OutMap is not zero then a MMap object representing
1623 the cache will be stored there. This is pretty much mandetory if you
1624 are using AllowMem. AllowMem lets the function be run as non-root
1625 where it builds the cache 'fast' into a memory buffer. */
1626 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1628 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1629 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1630 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1631 Flags
|= MMap::Moveable
;
1632 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1633 Flags
|= MMap::Fallback
;
1635 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1637 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1639 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1640 std::string
const &FileName
)
1642 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1643 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1646 fchmod(SCacheF
.Fd(),0644);
1648 // Write out the main data
1649 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1650 return _error
->Error(_("IO Error saving source cache"));
1652 // Write out the proper header
1653 Gen
->GetCache().HeaderP
->Dirty
= false;
1654 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1655 if (SCacheF
.Seek(0) == false ||
1656 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1657 return _error
->Error(_("IO Error saving source cache"));
1658 Gen
->GetCache().HeaderP
->Dirty
= true;
1661 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1662 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1664 Map
.reset(CreateDynamicMMap(NULL
, 0));
1665 if (unlikely(Map
->validData()) == false)
1667 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1668 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1670 _error
->PushToStack();
1671 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1672 bool const newError
= _error
->PendingError();
1673 _error
->MergeWithStack();
1674 if (alloc
== 0 && newError
)
1675 return _error
->ReturnError();
1676 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1678 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1679 return Gen
->Start();
1681 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1682 MMap
**OutMap
, bool AllowMem
)
1683 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1684 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1687 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1689 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1690 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1692 // FIXME: deprecate the ignored AllowMem parameter
1693 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1695 std::vector
<pkgIndexFile
*> Files
;
1696 if (_system
->AddStatusFiles(Files
) == false)
1699 // Decide if we can write to the files..
1700 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1701 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1703 // ensure the cache directory exists
1704 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1706 string dir
= _config
->FindDir("Dir::Cache");
1707 size_t const len
= dir
.size();
1708 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1709 dir
= dir
.substr(0, len
- 5);
1710 if (CacheFile
.empty() == false)
1711 CreateDirectory(dir
, flNotFile(CacheFile
));
1712 if (SrcCacheFile
.empty() == false)
1713 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1716 if (Progress
!= NULL
)
1717 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1719 bool pkgcache_fine
= false;
1720 bool srcpkgcache_fine
= false;
1721 bool volatile_fine
= List
.GetVolatileFiles().empty();
1723 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1724 volatile_fine
? OutCache
: NULL
) == true)
1727 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1728 pkgcache_fine
= true;
1729 srcpkgcache_fine
= true;
1731 if (pkgcache_fine
== false)
1733 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1736 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1737 srcpkgcache_fine
= true;
1741 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1743 if (Progress
!= NULL
)
1744 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1748 bool Writeable
= false;
1749 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1751 if (CacheFile
.empty() == false)
1752 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1753 else if (SrcCacheFile
.empty() == false)
1754 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1757 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1760 // At this point we know we need to construct something, so get storage ready
1761 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1762 if (unlikely(Map
->validData()) == false)
1765 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1767 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1768 map_filesize_t CurrentSize
= 0;
1769 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1770 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1771 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1774 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1775 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1777 srcpkgcache_fine
= true;
1778 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1780 else if (srcpkgcache_fine
== false)
1783 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1784 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1785 if (Gen
->Start() == false)
1788 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1789 BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1790 Files
.end(),Files
.end());
1792 if (Writeable
== true && SrcCacheFile
.empty() == false)
1793 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1797 if (pkgcache_fine
== false)
1800 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1801 BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1802 Files
.begin(), Files
.end());
1804 if (Writeable
== true && CacheFile
.empty() == false)
1805 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1810 std::clog
<< "Caches done. " << (volatile_fine
? "No volatile files, so we are done here." : "Now bring in the volatile files") << std::endl
;
1812 if (volatile_fine
== false)
1817 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1818 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1822 Files
= List
.GetVolatileFiles();
1823 BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1824 Files
.begin(), Files
.end());
1827 if (OutMap
!= nullptr)
1828 *OutMap
= Map
.release();
1831 std::clog
<< "Everything is ready for shipping" << std::endl
;
1835 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1836 class APT_HIDDEN ScopedErrorMerge
{
1838 ScopedErrorMerge() { _error
->PushToStack(); }
1839 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1841 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1842 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1843 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1845 std::vector
<pkgIndexFile
*> Files
;
1846 if (_system
->AddStatusFiles(Files
) == false)
1849 ScopedErrorMerge sem
;
1850 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1851 if (unlikely(Map
->validData()) == false)
1853 map_filesize_t CurrentSize
= 0;
1854 map_filesize_t TotalSize
= 0;
1855 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1857 // Build the status cache
1858 if (Progress
!= NULL
)
1859 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1860 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1861 if (Gen
.Start() == false)
1863 if (_error
->PendingError() == true)
1864 return _error
->ReturnError();
1865 BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1866 Files
.begin(), Files
.end());
1867 // We've passed the point of no return
1868 _error
->ReturnError();
1870 *OutMap
= Map
.release();
1875 // IsDuplicateDescription /*{{{*/
1876 static bool IsDuplicateDescription(pkgCache
&Cache
, pkgCache::DescIterator Desc
,
1877 APT::StringView CurMd5
, std::string
const &CurLang
)
1879 // Descriptions in the same link-list have all the same md5
1880 if (Desc
.end() == true || Cache
.ViewString(Desc
->md5sum
) != CurMd5
)
1882 for (; Desc
.end() == false; ++Desc
)
1883 if (Desc
.LanguageCode() == CurLang
)
1889 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1890 pkgCacheListParser::~pkgCacheListParser() {}