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)
256 if (Counter
% 100 == 0 && Progress
!= 0)
257 Progress
->Progress(List
.Offset());
259 APT::StringView Arch
= List
.Architecture();
260 Dynamic
<APT::StringView
> DynArch(Arch
);
261 APT::StringView Version
= List
.Version();
262 Dynamic
<APT::StringView
> DynVersion(Version
);
263 if (Version
.empty() == true && Arch
.empty() == true)
265 // package descriptions
266 if (MergeListGroup(List
, PackageName
) == false)
271 // Get a pointer to the package structure
272 pkgCache::PkgIterator Pkg
;
273 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
274 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
275 // TRANSLATOR: The first placeholder is a package name,
276 // the other two should be copied verbatim as they include debug info
277 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
278 PackageName
.c_str(), "NewPackage", 1);
281 if (Version
.empty() == true)
283 if (MergeListPackage(List
, Pkg
) == false)
288 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
296 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
297 return _error
->Error(_("Wow, you exceeded the number of package "
298 "names this APT is capable of."));
299 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
300 return _error
->Error(_("Wow, you exceeded the number of versions "
301 "this APT is capable of."));
302 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
303 return _error
->Error(_("Wow, you exceeded the number of descriptions "
304 "this APT is capable of."));
305 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
306 return _error
->Error(_("Wow, you exceeded the number of dependencies "
307 "this APT is capable of."));
311 // CacheGenerator::MergeListGroup /*{{{*/
312 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
314 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
315 // a group has no data on it's own, only packages have it but these
316 // stanzas like this come from Translation- files to add descriptions,
317 // but without a version we don't need a description for it…
318 if (Grp
.end() == true)
320 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
322 pkgCache::PkgIterator Pkg
;
323 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
324 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
325 if (MergeListPackage(List
, Pkg
) == false)
331 // CacheGenerator::MergeListPackage /*{{{*/
332 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
334 // we first process the package, then the descriptions
335 // (for deb this package processing is in fact a no-op)
336 pkgCache::VerIterator
Ver(Cache
);
337 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
338 if (List
.UsePackage(Pkg
, Ver
) == false)
339 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
340 Pkg
.Name(), "UsePackage", 1);
342 // Find the right version to write the description
343 StringView CurMd5
= List
.Description_md5();
344 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
345 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
347 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
349 // a version can only have one md5 describing it
350 if (VerDesc
.end() == true || Cache
.ViewString(VerDesc
->md5sum
) != CurMd5
)
353 map_stringitem_t md5idx
= VerDesc
->md5sum
;
354 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
356 // don't add a new description if we have one for the given
358 if (IsDuplicateDescription(Cache
, VerDesc
, CurMd5
, *CurLang
) == true)
361 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
364 // we can stop here as all "same" versions will share the description
371 // CacheGenerator::MergeListVersion /*{{{*/
372 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
373 APT::StringView
const &Version
, pkgCache::VerIterator
* &OutVer
)
375 pkgCache::VerIterator Ver
= Pkg
.VersionList();
376 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
377 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
378 void const * oldMap
= Map
.Data();
380 unsigned short const Hash
= List
.VersionHash();
381 if (Ver
.end() == false)
383 /* We know the list is sorted so we use that fact in the search.
384 Insertion of new versions is done with correct sorting */
386 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
388 char const * const VerStr
= Ver
.VerStr();
389 Res
= Cache
.VS
->DoCmpVersion(Version
.data(), Version
.data() + Version
.length(),
390 VerStr
, VerStr
+ strlen(VerStr
));
391 // Version is higher as current version - insert here
394 // Versionstrings are equal - is hash also equal?
397 if (List
.SameVersion(Hash
, Ver
) == true)
399 // sort (volatile) sources above not-sources like the status file
400 if ((CurrentFile
->Flags
& pkgCache::Flag::NotSource
) == 0)
402 auto VF
= Ver
.FileList();
403 for (; VF
.end() == false; ++VF
)
404 if (VF
.File().Flagged(pkgCache::Flag::NotSource
) == false)
406 if (VF
.end() == true)
410 // proceed with the next till we have either the right
411 // or we found another version (which will be lower)
414 /* We already have a version for this item, record that we saw it */
415 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
417 if (List
.UsePackage(Pkg
,Ver
) == false)
418 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
419 Pkg
.Name(), "UsePackage", 2);
421 if (NewFileVer(Ver
,List
) == false)
422 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
423 Pkg
.Name(), "NewFileVer", 1);
425 // Read only a single record and return
437 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
438 if (unlikely(verindex
== 0))
439 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
440 Pkg
.Name(), "NewVersion", 1);
442 if (oldMap
!= Map
.Data())
443 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
446 if (unlikely(List
.NewVersion(Ver
) == false))
447 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
448 Pkg
.Name(), "NewVersion", 2);
450 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
451 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
452 Pkg
.Name(), "UsePackage", 3);
454 if (unlikely(NewFileVer(Ver
,List
) == false))
455 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
456 Pkg
.Name(), "NewFileVer", 2);
458 pkgCache::GrpIterator Grp
= Pkg
.Group();
459 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
461 /* If it is the first version of this package we need to add implicit
462 Multi-Arch dependencies to all other package versions in the group now -
463 otherwise we just add them for this new version */
464 if (Pkg
.VersionList()->NextVer
== 0)
466 pkgCache::PkgIterator P
= Grp
.PackageList();
467 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
468 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
470 if (P
->ID
== Pkg
->ID
)
472 pkgCache::VerIterator V
= P
.VersionList();
473 Dynamic
<pkgCache::VerIterator
> DynV(V
);
474 for (; V
.end() != true; ++V
)
475 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
476 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
477 Pkg
.Name(), "AddImplicitDepends", 1);
480 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
481 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
482 Pkg
.Name(), "AddImplicitDepends", 2);
484 // Read only a single record and return
491 /* Record the Description(s) based on their master md5sum */
492 StringView CurMd5
= List
.Description_md5();
494 /* Before we add a new description we first search in the group for
495 a version with a description of the same MD5 - if so we reuse this
496 description group instead of creating our own for this version */
497 for (pkgCache::PkgIterator P
= Grp
.PackageList();
498 P
.end() == false; P
= Grp
.NextPkg(P
))
500 for (pkgCache::VerIterator V
= P
.VersionList();
501 V
.end() == false; ++V
)
503 if (V
->DescriptionList
== 0 || Cache
.ViewString(V
.DescriptionList()->md5sum
) != CurMd5
)
505 Ver
->DescriptionList
= V
->DescriptionList
;
509 // We haven't found reusable descriptions, so add the first description(s)
510 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
511 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
512 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
513 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
518 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, APT::StringView CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
520 pkgCache::DescIterator Desc
;
521 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
523 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
524 if (unlikely(descindex
== 0))
525 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
526 Ver
.ParentPkg().Name(), "NewDescription", 1);
528 md5idx
= Desc
->md5sum
;
529 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
531 // we add at the end, so that the start is constant as we need
532 // that to be able to efficiently share these lists
533 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
534 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
535 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
536 *LastNextDesc
= descindex
;
538 if (NewFileDesc(Desc
,List
) == false)
539 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
540 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
546 // CacheGenerator::NewGroup - Add a new group /*{{{*/
547 // ---------------------------------------------------------------------
548 /* This creates a new group structure and adds it to the hash table */
549 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
551 Dynamic
<StringView
> DName(Name
);
552 Grp
= Cache
.FindGrp(Name
);
553 if (Grp
.end() == false)
557 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
558 if (unlikely(Group
== 0))
561 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
562 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
563 if (unlikely(idxName
== 0))
567 // Insert it into the hash table
568 unsigned long const Hash
= Cache
.Hash(Name
);
569 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
571 while (*insertAt
!= 0 && StringViewCompareFast(Name
, Cache
.ViewString((Cache
.GrpP
+ *insertAt
)->Name
)) > 0)
572 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
573 Grp
->Next
= *insertAt
;
576 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
580 // CacheGenerator::NewPackage - Add a new package /*{{{*/
581 // ---------------------------------------------------------------------
582 /* This creates a new package structure and adds it to the hash table */
583 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
585 pkgCache::GrpIterator Grp
;
586 Dynamic
<StringView
> DName(Name
);
587 Dynamic
<StringView
> DArch(Arch
);
588 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
589 if (unlikely(NewGroup(Grp
, Name
) == false))
592 Pkg
= Grp
.FindPkg(Arch
);
593 if (Pkg
.end() == false)
597 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
598 if (unlikely(Package
== 0))
600 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
602 // Set the name, arch and the ID
603 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
604 Pkg
->Group
= Grp
.Index();
605 // all is mapped to the native architecture
606 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
607 if (unlikely(idxArch
== 0))
610 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
612 // Insert the package into our package list
613 if (Grp
->FirstPackage
== 0) // the group is new
615 Grp
->FirstPackage
= Package
;
616 // Insert it into the hash table
617 map_id_t
const Hash
= Cache
.Hash(Name
);
618 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
619 while (*insertAt
!= 0 && StringViewCompareFast(Name
, Cache
.ViewString((Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
)) > 0)
620 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
621 Pkg
->NextPackage
= *insertAt
;
624 else // Group the Packages together
626 // if sibling is provided by another package, this one is too
628 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
629 if (M
.end() == false) {
630 pkgCache::PrvIterator Prv
;
631 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
632 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
634 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
636 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
637 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
638 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
639 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
640 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
642 if (APT::Configuration::checkArchitecture(Ver
.ParentPkg().Arch()) == false)
644 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
650 // let M-A:foreign package siblings provide this package
652 pkgCache::PkgIterator P
;
653 pkgCache::VerIterator Ver
;
654 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
655 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
657 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
659 if (APT::Configuration::checkArchitecture(P
.Arch()) == false)
661 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
662 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
663 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
667 // and negative dependencies, don't forget negative dependencies
669 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
670 if (M
.end() == false) {
671 pkgCache::DepIterator Dep
;
672 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
673 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
675 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
677 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
678 Dep
->Type
!= pkgCache::Dep::Replaces
)
680 pkgCache::VerIterator Ver
= Dep
.ParentVer();
681 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
682 map_pointer_t
* unused
= NULL
;
683 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
689 // this package is the new last package
690 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
691 Pkg
->NextPackage
= LastPkg
->NextPackage
;
692 LastPkg
->NextPackage
= Package
;
694 Grp
->LastPackage
= Package
;
696 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
699 size_t const found
= Name
.rfind(':');
700 StringView ArchA
= Name
.substr(found
+ 1);
703 // ArchA is used inside the loop which might remap (NameA is not used)
704 Dynamic
<StringView
> DynArchA(ArchA
);
705 StringView NameA
= Name
.substr(0, found
);
706 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
707 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
710 Dynamic
<StringView
> DynNameA(NameA
);
711 if (NewPackage(PkgA
, NameA
, ArchA
) == false)
714 if (unlikely(PkgA
.end()))
715 return _error
->Fatal("NewPackage was successful for %s:%s,"
716 "but the package doesn't exist anyhow!",
717 NameA
.to_string().c_str(), ArchA
.to_string().c_str());
720 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
721 for (; Prv
.end() == false; ++Prv
)
723 if (Prv
.IsMultiArchImplicit())
725 pkgCache::VerIterator V
= Prv
.OwnerVer();
726 if (ArchA
!= V
.ParentPkg().Arch())
728 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
731 pkgCache::VerIterator V
= PkgA
.VersionList();
732 Dynamic
<pkgCache::VerIterator
> DynV(V
);
733 for (; V
.end() == false; ++V
)
735 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
744 // CacheGenerator::AddImplicitDepends /*{{{*/
745 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
746 pkgCache::PkgIterator
&P
,
747 pkgCache::VerIterator
&V
)
749 APT::StringView Arch
= P
.Arch() == NULL
? "" : P
.Arch();
750 Dynamic
<APT::StringView
> DynArch(Arch
);
751 map_pointer_t
*OldDepLast
= NULL
;
752 /* MultiArch handling introduces a lot of implicit Dependencies:
753 - MultiArch: same → Co-Installable if they have the same version
754 - All others conflict with all other group members */
755 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
756 pkgCache::PkgIterator D
= G
.PackageList();
757 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
758 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
759 for (; D
.end() != true; D
= G
.NextPkg(D
))
761 if (Arch
== D
.Arch() || D
->VersionList
== 0)
763 /* We allow only one installed arch at the time
764 per group, therefore each group member conflicts
765 with all other group members */
766 if (coInstall
== true)
768 // Replaces: ${self}:other ( << ${binary:Version})
769 NewDepends(D
, V
, VerStrIdx
,
770 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
772 // Breaks: ${self}:other (!= ${binary:Version})
773 NewDepends(D
, V
, VerStrIdx
,
774 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
777 // Conflicts: ${self}:other
779 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
785 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
786 pkgCache::PkgIterator
&D
)
788 /* MultiArch handling introduces a lot of implicit Dependencies:
789 - MultiArch: same → Co-Installable if they have the same version
790 - All others conflict with all other group members */
791 map_pointer_t
*OldDepLast
= NULL
;
792 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
793 if (coInstall
== true)
795 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
796 // Replaces: ${self}:other ( << ${binary:Version})
797 NewDepends(D
, V
, VerStrIdx
,
798 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
800 // Breaks: ${self}:other (!= ${binary:Version})
801 NewDepends(D
, V
, VerStrIdx
,
802 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
805 // Conflicts: ${self}:other
807 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
814 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
815 // ---------------------------------------------------------------------
817 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
820 if (CurrentFile
== 0)
824 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
828 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
829 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
831 // Link it to the end of the list
832 map_pointer_t
*Last
= &Ver
->FileList
;
833 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
835 VF
->NextFile
= *Last
;
838 VF
->Offset
= List
.Offset();
839 VF
->Size
= List
.Size();
840 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
841 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
842 Cache
.HeaderP
->VerFileCount
++;
847 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
848 // ---------------------------------------------------------------------
849 /* This puts a version structure in the linked list */
850 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
851 APT::StringView
const &VerStr
,
852 map_pointer_t
const ParentPkg
,
853 unsigned short const Hash
,
854 map_pointer_t
const Next
)
857 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
862 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
863 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
865 Ver
->ParentPkg
= ParentPkg
;
867 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
869 // try to find the version string in the group for reuse
870 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
871 pkgCache::GrpIterator Grp
= Pkg
.Group();
872 if (Pkg
.end() == false && Grp
.end() == false)
874 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
878 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
880 int const cmp
= strncmp(V
.VerStr(), VerStr
.data(), VerStr
.length());
881 if (cmp
== 0 && V
.VerStr()[VerStr
.length()] == '\0')
883 Ver
->VerStr
= V
->VerStr
;
891 // haven't found the version string, so create
892 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
893 if (unlikely(idxVerStr
== 0))
895 Ver
->VerStr
= idxVerStr
;
899 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
900 // ---------------------------------------------------------------------
902 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
905 if (CurrentFile
== 0)
909 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
913 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
914 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
916 // Link it to the end of the list
917 map_pointer_t
*Last
= &Desc
->FileList
;
918 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
921 DF
->NextFile
= *Last
;
924 DF
->Offset
= List
.Offset();
925 DF
->Size
= List
.Size();
926 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
927 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
928 Cache
.HeaderP
->DescFileCount
++;
933 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
934 // ---------------------------------------------------------------------
935 /* This puts a description structure in the linked list */
936 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
938 APT::StringView md5sum
,
939 map_stringitem_t
const idxmd5str
)
942 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
943 if (Description
== 0)
947 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
948 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
949 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
950 if (unlikely(idxlanguage_code
== 0))
952 Desc
->language_code
= idxlanguage_code
;
955 Desc
->md5sum
= idxmd5str
;
958 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
);
959 if (unlikely(idxmd5sum
== 0))
961 Desc
->md5sum
= idxmd5sum
;
967 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
968 // ---------------------------------------------------------------------
969 /* This creates a dependency element in the tree. It is linked to the
970 version and to the package that it is pointing to. */
971 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
972 pkgCache::VerIterator
&Ver
,
973 map_pointer_t
const Version
,
976 map_pointer_t
* &OldDepLast
)
978 void const * const oldMap
= Map
.Data();
980 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
981 if (unlikely(Dependency
== 0))
984 bool isDuplicate
= false;
985 map_pointer_t DependencyData
= 0;
986 map_pointer_t PreviousData
= 0;
987 if (Pkg
->RevDepends
!= 0)
989 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
990 DependencyData
= L
->DependencyData
;
992 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
993 if (Version
> D
->Version
)
995 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
1000 PreviousData
= DependencyData
;
1001 DependencyData
= D
->NextData
;
1002 } while (DependencyData
!= 0);
1005 if (isDuplicate
== false)
1007 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
1008 if (unlikely(DependencyData
== 0))
1012 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
1013 Link
->ParentVer
= Ver
.Index();
1014 Link
->DependencyData
= DependencyData
;
1015 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
1017 pkgCache::DepIterator
Dep(Cache
, Link
);
1018 if (isDuplicate
== false)
1021 Dep
->CompareOp
= Op
;
1022 Dep
->Version
= Version
;
1023 Dep
->Package
= Pkg
.Index();
1024 ++Cache
.HeaderP
->DependsDataCount
;
1025 if (PreviousData
!= 0)
1027 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
1028 Dep
->NextData
= D
->NextData
;
1029 D
->NextData
= DependencyData
;
1031 else if (Pkg
->RevDepends
!= 0)
1033 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
1034 Dep
->NextData
= D
->DependencyData
;
1038 if (isDuplicate
== true || PreviousData
!= 0)
1040 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
1041 Link
->NextRevDepends
= L
->NextRevDepends
;
1042 L
->NextRevDepends
= Dependency
;
1046 Link
->NextRevDepends
= Pkg
->RevDepends
;
1047 Pkg
->RevDepends
= Dependency
;
1051 // Do we know where to link the Dependency to?
1052 if (OldDepLast
== NULL
)
1054 OldDepLast
= &Ver
->DependsList
;
1055 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
1056 OldDepLast
= &D
->NextDepends
;
1057 } else if (oldMap
!= Map
.Data())
1058 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
1060 Dep
->NextDepends
= *OldDepLast
;
1061 *OldDepLast
= Dependency
;
1062 OldDepLast
= &Dep
->NextDepends
;
1066 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1067 // ---------------------------------------------------------------------
1068 /* This creates a Group and the Package to link this dependency to if
1069 needed and handles also the caching of the old endpoint */
1070 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1071 StringView PackageName
,
1077 pkgCache::GrpIterator Grp
;
1078 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1079 Dynamic
<StringView
> DynPackageName(PackageName
);
1080 Dynamic
<StringView
> DynArch(Arch
);
1081 Dynamic
<StringView
> DynVersion(Version
);
1082 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1085 map_stringitem_t idxVersion
= 0;
1086 if (Version
.empty() == false)
1088 int const CmpOp
= Op
& 0x0F;
1089 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1090 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1091 idxVersion
= Ver
->VerStr
;
1093 if (idxVersion
== 0)
1095 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1096 if (unlikely(idxVersion
== 0))
1101 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1102 Type
== pkgCache::Dep::Conflicts
||
1103 Type
== pkgCache::Dep::Replaces
);
1105 pkgCache::PkgIterator Pkg
;
1106 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1107 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1109 // Locate the target package
1110 Pkg
= Grp
.FindPkg(Arch
);
1111 if (Pkg
.end() == true) {
1112 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1116 /* Caching the old end point speeds up generation substantially */
1117 if (OldDepVer
!= Ver
) {
1122 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1126 /* Caching the old end point speeds up generation substantially */
1127 if (OldDepVer
!= Ver
) {
1132 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1134 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1141 // ListParser::NewProvides - Create a Provides element /*{{{*/
1142 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1146 uint8_t const Flags
)
1148 pkgCache
const &Cache
= Owner
->Cache
;
1149 Dynamic
<StringView
> DynPkgName(PkgName
);
1150 Dynamic
<StringView
> DynArch(PkgArch
);
1151 Dynamic
<StringView
> DynVersion(Version
);
1153 // We do not add self referencing provides
1154 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1155 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1156 (Version
.empty() || Version
== Ver
.VerStr()))
1159 // Locate the target package
1160 pkgCache::PkgIterator Pkg
;
1161 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1162 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1165 map_stringitem_t idxProvideVersion
= 0;
1166 if (Version
.empty() == false) {
1167 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1168 if (unlikely(idxProvideVersion
== 0))
1171 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1173 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1174 pkgCache::PkgIterator
&Pkg
,
1175 map_pointer_t
const ProvideVersion
,
1176 uint8_t const Flags
)
1179 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1180 if (unlikely(Provides
== 0))
1182 ++Cache
.HeaderP
->ProvidesCount
;
1185 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1186 Prv
->Version
= Ver
.Index();
1187 Prv
->ProvideVersion
= ProvideVersion
;
1189 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1190 Ver
->ProvidesList
= Prv
.Index();
1192 // Link it to the package
1193 Prv
->ParentPkg
= Pkg
.Index();
1194 Prv
->NextProvides
= Pkg
->ProvidesList
;
1195 Pkg
->ProvidesList
= Prv
.Index();
1199 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1200 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1201 StringView Version
, uint8_t const Flags
) {
1202 pkgCache
&Cache
= Owner
->Cache
;
1203 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1204 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1205 Dynamic
<StringView
> DynPackage(Package
);
1206 Dynamic
<StringView
> DynVersion(Version
);
1208 if (Grp
.end() == true)
1209 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1212 map_stringitem_t idxProvideVersion
= 0;
1213 if (Version
.empty() == false) {
1214 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1215 if (unlikely(idxProvideVersion
== 0))
1219 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1220 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1221 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1222 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1223 pkgCache::PkgIterator Pkg
;
1224 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1225 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1227 if (isImplicit
&& OwnerPkg
== Pkg
)
1229 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1231 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1238 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1239 pkgCache::VerIterator
const &Ver
)
1241 return Hash
== Ver
->Hash
;
1244 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1245 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1246 unsigned long Flags
)
1248 if (File
.empty() && Site
.empty())
1250 CurrentRlsFile
= NULL
;
1254 // Get some space for the structure
1255 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1256 if (unlikely(idxFile
== 0))
1258 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1261 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1262 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1263 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1265 CurrentRlsFile
->FileName
= idxFileName
;
1266 CurrentRlsFile
->Site
= idxSite
;
1267 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1268 CurrentRlsFile
->Flags
= Flags
;
1269 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1271 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1272 Cache
.HeaderP
->ReleaseFileCount
++;
1277 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1278 // ---------------------------------------------------------------------
1279 /* This is used to select which file is to be associated with all newly
1280 added versions. The caller is responsible for setting the IMS fields. */
1281 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1282 pkgIndexFile
const &Index
,
1283 std::string
const &Architecture
,
1284 std::string
const &Component
,
1285 unsigned long const Flags
)
1287 // Get some space for the structure
1288 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1289 if (unlikely(idxFile
== 0))
1291 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1294 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1295 if (unlikely(idxFileName
== 0))
1297 CurrentFile
->FileName
= idxFileName
;
1298 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1299 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1300 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1301 if (unlikely(idxIndexType
== 0))
1303 CurrentFile
->IndexType
= idxIndexType
;
1304 if (Architecture
.empty())
1305 CurrentFile
->Architecture
= 0;
1308 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1309 if (unlikely(arch
== 0))
1311 CurrentFile
->Architecture
= arch
;
1313 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1314 if (unlikely(component
== 0))
1316 CurrentFile
->Component
= component
;
1317 CurrentFile
->Flags
= Flags
;
1318 if (CurrentRlsFile
!= NULL
)
1319 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1321 CurrentFile
->Release
= 0;
1323 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1324 Cache
.HeaderP
->PackageFileCount
++;
1327 Progress
->SubProgress(Index
.Size());
1331 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1332 // ---------------------------------------------------------------------
1333 /* This is used to create handles to strings. Given the same text it
1334 always returns the same number */
1335 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1338 auto strings
= &strMixed
;
1340 case MIXED
: strings
= &strMixed
; break;
1341 case PKGNAME
: strings
= &strPkgNames
; break;
1342 case VERSIONNUMBER
: strings
= &strVersions
; break;
1343 case SECTION
: strings
= &strSections
; break;
1344 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1347 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1348 if (item
!= strings
->end())
1351 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1352 strings
->insert({nullptr, Size
, this, idxString
});
1356 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1357 // ---------------------------------------------------------------------
1358 /* This just verifies that each file in the list of index files exists,
1359 has matching attributes with the cache and the cache does not have
1361 class APT_HIDDEN ScopedErrorRevert
{
1363 ScopedErrorRevert() { _error
->PushToStack(); }
1364 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1366 static bool CheckValidity(const string
&CacheFile
,
1367 pkgSourceList
&List
,
1368 FileIterator
const Start
,
1369 FileIterator
const End
,
1371 pkgCache
**OutCache
= 0)
1373 ScopedErrorRevert ser
;
1374 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1375 // No file, certainly invalid
1376 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1379 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1383 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1386 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1391 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1392 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1393 if (unlikely(Map
->validData()) == false)
1395 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1396 pkgCache
&Cache
= *CacheP
.get();
1397 if (_error
->PendingError() || Map
->Size() == 0)
1400 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1404 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1405 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1406 std::vector
<pkgIndexFile
*> Files
;
1407 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1410 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1411 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1412 if (RlsFile
.end() == true)
1415 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1419 RlsVisited
[RlsFile
->ID
] = true;
1421 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1423 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1424 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1425 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1427 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1428 if (RlsVisited
[I
] == false)
1431 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1435 std::copy(Start
, End
, std::back_inserter(Files
));
1437 /* Now we check every index file, see if it is in the cache,
1438 verify the IMS data and check that it is on the disk too.. */
1439 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1440 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1441 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1444 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1445 if ((*PkgFile
)->Exists() == false)
1448 std::clog
<< "file doesn't exist" << std::endl
;
1452 // FindInCache is also expected to do an IMS check.
1453 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1454 if (File
.end() == true)
1457 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1461 Visited
[File
->ID
] = true;
1463 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1466 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1467 if (Visited
[I
] == false)
1470 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1474 if (_error
->PendingError() == true)
1478 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1479 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1485 *OutMap
= Map
.release();
1487 *OutCache
= CacheP
.release();
1491 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1492 // ---------------------------------------------------------------------
1493 /* Size is kind of an abstract notion that is only used for the progress
1495 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1497 map_filesize_t TotalSize
= 0;
1500 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1502 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1503 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1504 if ((*j
)->HasPackages() == true)
1505 TotalSize
+= (*j
)->Size();
1509 for (; Start
< End
; ++Start
)
1511 if ((*Start
)->HasPackages() == false)
1513 TotalSize
+= (*Start
)->Size();
1518 // BuildCache - Merge the list of index files into the cache /*{{{*/
1519 static bool BuildCache(pkgCacheGenerator
&Gen
,
1520 OpProgress
* const Progress
,
1521 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1522 pkgSourceList
const * const List
,
1523 FileIterator
const Start
, FileIterator
const End
)
1525 bool mergeFailure
= false;
1527 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1528 if (I
->HasPackages() == false || mergeFailure
)
1531 if (I
->Exists() == false)
1534 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1536 _error
->Warning("Duplicate sources.list entry %s",
1537 I
->Describe().c_str());
1541 map_filesize_t
const Size
= I
->Size();
1542 if (Progress
!= NULL
)
1543 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1544 CurrentSize
+= Size
;
1546 if (I
->Merge(Gen
,Progress
) == false)
1547 mergeFailure
= true;
1552 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1554 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1556 _error
->Warning("Duplicate sources.list entry %s",
1557 (*i
)->Describe().c_str());
1561 if ((*i
)->Merge(Gen
, Progress
) == false)
1564 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1565 if (Indexes
!= NULL
)
1566 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1574 Gen
.SelectReleaseFile("", "");
1575 std::for_each(Start
, End
, indexFileMerge
);
1582 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1583 // ---------------------------------------------------------------------
1584 /* This makes sure that the status cache (the cache that has all
1585 index files from the sources list and all local ones) is ready
1586 to be mmaped. If OutMap is not zero then a MMap object representing
1587 the cache will be stored there. This is pretty much mandetory if you
1588 are using AllowMem. AllowMem lets the function be run as non-root
1589 where it builds the cache 'fast' into a memory buffer. */
1590 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1592 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1593 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1594 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1595 Flags
|= MMap::Moveable
;
1596 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1597 Flags
|= MMap::Fallback
;
1599 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1601 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1603 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1604 std::string
const &FileName
)
1606 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1607 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1610 fchmod(SCacheF
.Fd(),0644);
1612 // Write out the main data
1613 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1614 return _error
->Error(_("IO Error saving source cache"));
1616 // Write out the proper header
1617 Gen
->GetCache().HeaderP
->Dirty
= false;
1618 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1619 if (SCacheF
.Seek(0) == false ||
1620 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1621 return _error
->Error(_("IO Error saving source cache"));
1622 Gen
->GetCache().HeaderP
->Dirty
= true;
1625 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1626 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1628 Map
.reset(CreateDynamicMMap(NULL
, 0));
1629 if (unlikely(Map
->validData()) == false)
1631 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1632 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1634 _error
->PushToStack();
1635 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1636 bool const newError
= _error
->PendingError();
1637 _error
->MergeWithStack();
1638 if (alloc
== 0 && newError
)
1640 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1642 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1643 return Gen
->Start();
1645 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1646 MMap
**OutMap
, bool AllowMem
)
1647 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1648 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1651 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1653 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1654 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1656 // FIXME: deprecate the ignored AllowMem parameter
1657 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1659 std::vector
<pkgIndexFile
*> Files
;
1660 if (_system
->AddStatusFiles(Files
) == false)
1663 // Decide if we can write to the files..
1664 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1665 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1667 // ensure the cache directory exists
1668 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1670 string dir
= _config
->FindDir("Dir::Cache");
1671 size_t const len
= dir
.size();
1672 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1673 dir
= dir
.substr(0, len
- 5);
1674 if (CacheFile
.empty() == false)
1675 CreateDirectory(dir
, flNotFile(CacheFile
));
1676 if (SrcCacheFile
.empty() == false)
1677 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1680 if (Progress
!= NULL
)
1681 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1683 bool pkgcache_fine
= false;
1684 bool srcpkgcache_fine
= false;
1685 bool volatile_fine
= List
.GetVolatileFiles().empty();
1687 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1688 volatile_fine
? OutCache
: NULL
) == true)
1691 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1692 pkgcache_fine
= true;
1693 srcpkgcache_fine
= true;
1695 if (pkgcache_fine
== false)
1697 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1700 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1701 srcpkgcache_fine
= true;
1705 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1707 if (Progress
!= NULL
)
1708 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1712 bool Writeable
= false;
1713 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1715 if (CacheFile
.empty() == false)
1716 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1717 else if (SrcCacheFile
.empty() == false)
1718 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1721 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1724 // At this point we know we need to construct something, so get storage ready
1725 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1726 if (unlikely(Map
->validData()) == false)
1729 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1731 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1732 map_filesize_t CurrentSize
= 0;
1733 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1734 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1735 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1738 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1739 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1741 srcpkgcache_fine
= true;
1742 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1744 else if (srcpkgcache_fine
== false)
1747 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1748 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1749 if (Gen
->Start() == false)
1752 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1753 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1754 Files
.end(),Files
.end()) == false)
1757 if (Writeable
== true && SrcCacheFile
.empty() == false)
1758 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1762 if (pkgcache_fine
== false)
1765 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1766 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1767 Files
.begin(), Files
.end()) == false)
1770 if (Writeable
== true && CacheFile
.empty() == false)
1771 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1776 std::clog
<< "Caches done. " << (volatile_fine
? "No volatile files, so we are done here." : "Now bring in the volatile files") << std::endl
;
1778 if (volatile_fine
== false)
1783 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1784 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1788 Files
= List
.GetVolatileFiles();
1789 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1790 Files
.begin(), Files
.end()) == false)
1794 if (OutMap
!= nullptr)
1795 *OutMap
= Map
.release();
1798 std::clog
<< "Everything is ready for shipping" << std::endl
;
1802 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1803 class APT_HIDDEN ScopedErrorMerge
{
1805 ScopedErrorMerge() { _error
->PushToStack(); }
1806 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1808 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1809 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1810 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1812 std::vector
<pkgIndexFile
*> Files
;
1813 if (_system
->AddStatusFiles(Files
) == false)
1816 ScopedErrorMerge sem
;
1817 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1818 if (unlikely(Map
->validData()) == false)
1820 map_filesize_t CurrentSize
= 0;
1821 map_filesize_t TotalSize
= 0;
1822 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1824 // Build the status cache
1825 if (Progress
!= NULL
)
1826 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1827 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1828 if (Gen
.Start() == false || _error
->PendingError() == true)
1830 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1831 Files
.begin(), Files
.end()) == false)
1834 if (_error
->PendingError() == true)
1836 *OutMap
= Map
.release();
1841 // IsDuplicateDescription /*{{{*/
1842 static bool IsDuplicateDescription(pkgCache
&Cache
, pkgCache::DescIterator Desc
,
1843 APT::StringView CurMd5
, std::string
const &CurLang
)
1845 // Descriptions in the same link-list have all the same md5
1846 if (Desc
.end() == true || Cache
.ViewString(Desc
->md5sum
) != CurMd5
)
1848 for (; Desc
.end() == false; ++Desc
)
1849 if (Desc
.LanguageCode() == CurLang
)
1855 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1856 pkgCacheListParser::~pkgCacheListParser() {}