1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
12 // Include Files /*{{{*/
15 #include <apt-pkg/pkgcachegen.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/version.h>
18 #include <apt-pkg/progress.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/pkgsystem.h>
22 #include <apt-pkg/macros.h>
23 #include <apt-pkg/metaindex.h>
24 #include <apt-pkg/fileutl.h>
25 #include <apt-pkg/hashsum_template.h>
26 #include <apt-pkg/indexfile.h>
27 #include <apt-pkg/md5.h>
28 #include <apt-pkg/mmap.h>
29 #include <apt-pkg/pkgcache.h>
30 #include <apt-pkg/cacheiterators.h>
44 template<class T
> using Dynamic
= pkgCacheGenerator::Dynamic
<T
>;
45 typedef std::vector
<pkgIndexFile
*>::iterator FileIterator
;
46 template <typename Iter
> std::vector
<Iter
*> pkgCacheGenerator::Dynamic
<Iter
>::toReMap
;
48 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
49 MD5SumValue
const &CurMd5
, std::string
const &CurLang
);
52 using APT::StringView
;
54 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
55 // ---------------------------------------------------------------------
56 /* We set the dirty flag and make sure that is written to the disk */
57 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
58 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
59 CurrentRlsFile(NULL
), CurrentFile(NULL
), d(NULL
)
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 if (oldMap
== newMap
)
154 if (_config
->FindB("Debug::pkgCacheGen", false))
155 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
159 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
160 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
162 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
163 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
164 (*i
)->ReMap(oldMap
, newMap
);
165 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
166 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
167 (*i
)->ReMap(oldMap
, newMap
);
168 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
169 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
170 (*i
)->ReMap(oldMap
, newMap
);
171 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
172 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
173 (*i
)->ReMap(oldMap
, newMap
);
174 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
175 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
176 (*i
)->ReMap(oldMap
, newMap
);
177 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
178 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
179 (*i
)->ReMap(oldMap
, newMap
);
180 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
181 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
182 (*i
)->ReMap(oldMap
, newMap
);
183 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
184 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
185 (*i
)->ReMap(oldMap
, newMap
);
186 for (APT::StringView
* ViewP
: Dynamic
<APT::StringView
>::toReMap
) {
187 // Ignore views outside of the cache.
188 if (ViewP
->data() < static_cast<const char*>(oldMap
)
189 || ViewP
->data() > static_cast<const char*>(oldMap
) + oldSize
)
191 const char *data
= ViewP
->data() + (static_cast<const char*>(newMap
) - static_cast<const char*>(oldMap
));
192 *ViewP
= StringView(data
, ViewP
->size());
195 // CacheGenerator::WriteStringInMap /*{{{*/
196 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
197 const unsigned long &Len
) {
198 size_t oldSize
= Map
.Size();
199 void const * const oldMap
= Map
.Data();
200 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
202 ReMap(oldMap
, Map
.Data(), oldSize
);
206 // CacheGenerator::WriteStringInMap /*{{{*/
207 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
208 size_t oldSize
= Map
.Size();
209 void const * const oldMap
= Map
.Data();
210 map_stringitem_t
const index
= Map
.WriteString(String
);
212 ReMap(oldMap
, Map
.Data(), oldSize
);
216 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
217 size_t oldSize
= Map
.Size();
218 void const * const oldMap
= Map
.Data();
219 map_pointer_t
const index
= Map
.Allocate(size
);
221 ReMap(oldMap
, Map
.Data(), oldSize
);
225 // CacheGenerator::MergeList - Merge the package list /*{{{*/
226 // ---------------------------------------------------------------------
227 /* This provides the generation of the entries in the cache. Each loop
228 goes through a single package record from the underlying parse engine. */
229 bool pkgCacheGenerator::MergeList(ListParser
&List
,
230 pkgCache::VerIterator
*OutVer
)
234 unsigned int Counter
= 0;
235 while (List
.Step() == true)
237 string
const PackageName
= List
.Package();
238 if (PackageName
.empty() == true)
242 if (Counter
% 100 == 0 && Progress
!= 0)
243 Progress
->Progress(List
.Offset());
245 APT::StringView Arch
= List
.Architecture();
246 Dynamic
<APT::StringView
> DynArch(Arch
);
247 APT::StringView Version
= List
.Version();
248 Dynamic
<APT::StringView
> DynVersion(Version
);
249 if (Version
.empty() == true && Arch
.empty() == true)
251 // package descriptions
252 if (MergeListGroup(List
, PackageName
) == false)
257 // Get a pointer to the package structure
258 pkgCache::PkgIterator Pkg
;
259 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
260 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
261 // TRANSLATOR: The first placeholder is a package name,
262 // the other two should be copied verbatim as they include debug info
263 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
264 PackageName
.c_str(), "NewPackage", 1);
267 if (Version
.empty() == true)
269 if (MergeListPackage(List
, Pkg
) == false)
274 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
282 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
283 return _error
->Error(_("Wow, you exceeded the number of package "
284 "names this APT is capable of."));
285 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
286 return _error
->Error(_("Wow, you exceeded the number of versions "
287 "this APT is capable of."));
288 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
289 return _error
->Error(_("Wow, you exceeded the number of descriptions "
290 "this APT is capable of."));
291 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
292 return _error
->Error(_("Wow, you exceeded the number of dependencies "
293 "this APT is capable of."));
297 // CacheGenerator::MergeListGroup /*{{{*/
298 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
300 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
301 // a group has no data on it's own, only packages have it but these
302 // stanzas like this come from Translation- files to add descriptions,
303 // but without a version we don't need a description for it…
304 if (Grp
.end() == true)
306 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
308 pkgCache::PkgIterator Pkg
;
309 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
310 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
311 if (MergeListPackage(List
, Pkg
) == false)
317 // CacheGenerator::MergeListPackage /*{{{*/
318 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
320 // we first process the package, then the descriptions
321 // (for deb this package processing is in fact a no-op)
322 pkgCache::VerIterator
Ver(Cache
);
323 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
324 if (List
.UsePackage(Pkg
, Ver
) == false)
325 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
326 Pkg
.Name(), "UsePackage", 1);
328 // Find the right version to write the description
329 MD5SumValue CurMd5
= List
.Description_md5();
330 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
331 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
333 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
335 // a version can only have one md5 describing it
336 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
339 map_stringitem_t md5idx
= VerDesc
->md5sum
;
340 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
342 // don't add a new description if we have one for the given
344 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
347 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
350 // we can stop here as all "same" versions will share the description
357 // CacheGenerator::MergeListVersion /*{{{*/
358 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
359 APT::StringView
const &Version
, pkgCache::VerIterator
* &OutVer
)
361 pkgCache::VerIterator Ver
= Pkg
.VersionList();
362 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
363 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
364 void const * oldMap
= Map
.Data();
366 unsigned short const Hash
= List
.VersionHash();
367 if (Ver
.end() == false)
369 /* We know the list is sorted so we use that fact in the search.
370 Insertion of new versions is done with correct sorting */
372 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
374 char const * const VerStr
= Ver
.VerStr();
375 Res
= Cache
.VS
->DoCmpVersion(Version
.data(), Version
.data() + Version
.length(),
376 VerStr
, VerStr
+ strlen(VerStr
));
377 // Version is higher as current version - insert here
380 // Versionstrings are equal - is hash also equal?
381 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
383 // proceed with the next till we have either the right
384 // or we found another version (which will be lower)
387 /* We already have a version for this item, record that we saw it */
388 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
390 if (List
.UsePackage(Pkg
,Ver
) == false)
391 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
392 Pkg
.Name(), "UsePackage", 2);
394 if (NewFileVer(Ver
,List
) == false)
395 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
396 Pkg
.Name(), "NewFileVer", 1);
398 // Read only a single record and return
410 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
411 if (unlikely(verindex
== 0))
412 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
413 Pkg
.Name(), "NewVersion", 1);
415 if (oldMap
!= Map
.Data())
416 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
419 if (unlikely(List
.NewVersion(Ver
) == false))
420 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
421 Pkg
.Name(), "NewVersion", 2);
423 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
424 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
425 Pkg
.Name(), "UsePackage", 3);
427 if (unlikely(NewFileVer(Ver
,List
) == false))
428 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
429 Pkg
.Name(), "NewFileVer", 2);
431 pkgCache::GrpIterator Grp
= Pkg
.Group();
432 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
434 /* If it is the first version of this package we need to add implicit
435 Multi-Arch dependencies to all other package versions in the group now -
436 otherwise we just add them for this new version */
437 if (Pkg
.VersionList()->NextVer
== 0)
439 pkgCache::PkgIterator P
= Grp
.PackageList();
440 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
441 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
443 if (P
->ID
== Pkg
->ID
)
445 pkgCache::VerIterator V
= P
.VersionList();
446 Dynamic
<pkgCache::VerIterator
> DynV(V
);
447 for (; V
.end() != true; ++V
)
448 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
449 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
450 Pkg
.Name(), "AddImplicitDepends", 1);
453 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
454 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
455 Pkg
.Name(), "AddImplicitDepends", 2);
457 // Read only a single record and return
464 /* Record the Description(s) based on their master md5sum */
465 MD5SumValue CurMd5
= List
.Description_md5();
467 /* Before we add a new description we first search in the group for
468 a version with a description of the same MD5 - if so we reuse this
469 description group instead of creating our own for this version */
470 for (pkgCache::PkgIterator P
= Grp
.PackageList();
471 P
.end() == false; P
= Grp
.NextPkg(P
))
473 for (pkgCache::VerIterator V
= P
.VersionList();
474 V
.end() == false; ++V
)
476 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
478 Ver
->DescriptionList
= V
->DescriptionList
;
482 // We haven't found reusable descriptions, so add the first description(s)
483 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
484 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
485 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
486 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
491 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
493 pkgCache::DescIterator Desc
;
494 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
496 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
497 if (unlikely(descindex
== 0))
498 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
499 Ver
.ParentPkg().Name(), "NewDescription", 1);
501 md5idx
= Desc
->md5sum
;
502 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
504 // we add at the end, so that the start is constant as we need
505 // that to be able to efficiently share these lists
506 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
507 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
508 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
509 *LastNextDesc
= descindex
;
511 if (NewFileDesc(Desc
,List
) == false)
512 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
513 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
519 // CacheGenerator::NewGroup - Add a new group /*{{{*/
520 // ---------------------------------------------------------------------
521 /* This creates a new group structure and adds it to the hash table */
522 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
524 Dynamic
<StringView
> DName(Name
);
525 Grp
= Cache
.FindGrp(Name
);
526 if (Grp
.end() == false)
530 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
531 if (unlikely(Group
== 0))
534 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
535 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
536 if (unlikely(idxName
== 0))
540 // Insert it into the hash table
541 unsigned long const Hash
= Cache
.Hash(Name
);
542 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
544 while (*insertAt
!= 0 && Name
.compare(Cache
.ViewString((Cache
.GrpP
+ *insertAt
)->Name
)) > 0)
545 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
546 Grp
->Next
= *insertAt
;
549 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
553 // CacheGenerator::NewPackage - Add a new package /*{{{*/
554 // ---------------------------------------------------------------------
555 /* This creates a new package structure and adds it to the hash table */
556 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
558 pkgCache::GrpIterator Grp
;
559 Dynamic
<StringView
> DName(Name
);
560 Dynamic
<StringView
> DArch(Arch
);
561 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
562 if (unlikely(NewGroup(Grp
, Name
) == false))
565 Pkg
= Grp
.FindPkg(Arch
);
566 if (Pkg
.end() == false)
570 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
571 if (unlikely(Package
== 0))
573 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
575 // Set the name, arch and the ID
576 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
577 Pkg
->Group
= Grp
.Index();
578 // all is mapped to the native architecture
579 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
580 if (unlikely(idxArch
== 0))
583 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
585 // Insert the package into our package list
586 if (Grp
->FirstPackage
== 0) // the group is new
588 Grp
->FirstPackage
= Package
;
589 // Insert it into the hash table
590 map_id_t
const Hash
= Cache
.Hash(Name
);
591 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
592 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
593 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
594 Pkg
->NextPackage
= *insertAt
;
597 else // Group the Packages together
599 // if sibling is provided by another package, this one is too
601 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
602 if (M
.end() == false) {
603 pkgCache::PrvIterator Prv
;
604 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
605 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
607 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
609 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
610 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
611 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
612 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
613 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
615 if (APT::Configuration::checkArchitecture(Ver
.ParentPkg().Arch()) == false)
617 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
623 // let M-A:foreign package siblings provide this package
625 pkgCache::PkgIterator P
;
626 pkgCache::VerIterator Ver
;
627 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
628 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
630 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
632 if (APT::Configuration::checkArchitecture(P
.Arch()) == false)
634 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
635 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
636 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
640 // and negative dependencies, don't forget negative dependencies
642 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
643 if (M
.end() == false) {
644 pkgCache::DepIterator Dep
;
645 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
646 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
648 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
650 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
651 Dep
->Type
!= pkgCache::Dep::Replaces
)
653 pkgCache::VerIterator Ver
= Dep
.ParentVer();
654 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
655 map_pointer_t
* unused
= NULL
;
656 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
662 // this package is the new last package
663 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
664 Pkg
->NextPackage
= LastPkg
->NextPackage
;
665 LastPkg
->NextPackage
= Package
;
667 Grp
->LastPackage
= Package
;
669 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
672 size_t const found
= Name
.rfind(':');
673 StringView ArchA
= Name
.substr(found
+ 1);
676 // ArchA is used inside the loop which might remap (NameA is not used)
677 Dynamic
<StringView
> DynArchA(ArchA
);
678 StringView NameA
= Name
.substr(0, found
);
679 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
680 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
683 Dynamic
<StringView
> DynNameA(NameA
);
684 if (NewPackage(PkgA
, NameA
, ArchA
) == false)
687 if (unlikely(PkgA
.end()))
688 return _error
->Fatal("NewPackage was successful for %s:%s,"
689 "but the package doesn't exist anyhow!",
690 NameA
.to_string().c_str(), ArchA
.to_string().c_str());
693 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
694 for (; Prv
.end() == false; ++Prv
)
696 if (Prv
.IsMultiArchImplicit())
698 pkgCache::VerIterator V
= Prv
.OwnerVer();
699 if (ArchA
!= V
.ParentPkg().Arch())
701 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
704 pkgCache::VerIterator V
= PkgA
.VersionList();
705 Dynamic
<pkgCache::VerIterator
> DynV(V
);
706 for (; V
.end() == false; ++V
)
708 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
717 // CacheGenerator::AddImplicitDepends /*{{{*/
718 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
719 pkgCache::PkgIterator
&P
,
720 pkgCache::VerIterator
&V
)
722 APT::StringView Arch
= P
.Arch() == NULL
? "" : P
.Arch();
723 Dynamic
<APT::StringView
> DynArch(Arch
);
724 map_pointer_t
*OldDepLast
= NULL
;
725 /* MultiArch handling introduces a lot of implicit Dependencies:
726 - MultiArch: same → Co-Installable if they have the same version
727 - All others conflict with all other group members */
728 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
729 pkgCache::PkgIterator D
= G
.PackageList();
730 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
731 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
732 for (; D
.end() != true; D
= G
.NextPkg(D
))
734 if (Arch
== D
.Arch() || D
->VersionList
== 0)
736 /* We allow only one installed arch at the time
737 per group, therefore each group member conflicts
738 with all other group members */
739 if (coInstall
== true)
741 // Replaces: ${self}:other ( << ${binary:Version})
742 NewDepends(D
, V
, VerStrIdx
,
743 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
745 // Breaks: ${self}:other (!= ${binary:Version})
746 NewDepends(D
, V
, VerStrIdx
,
747 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
750 // Conflicts: ${self}:other
752 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
758 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
759 pkgCache::PkgIterator
&D
)
761 /* MultiArch handling introduces a lot of implicit Dependencies:
762 - MultiArch: same → Co-Installable if they have the same version
763 - All others conflict with all other group members */
764 map_pointer_t
*OldDepLast
= NULL
;
765 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
766 if (coInstall
== true)
768 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
769 // Replaces: ${self}:other ( << ${binary:Version})
770 NewDepends(D
, V
, VerStrIdx
,
771 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
773 // Breaks: ${self}:other (!= ${binary:Version})
774 NewDepends(D
, V
, VerStrIdx
,
775 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
778 // Conflicts: ${self}:other
780 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
787 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
788 // ---------------------------------------------------------------------
790 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
793 if (CurrentFile
== 0)
797 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
801 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
802 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
804 // Link it to the end of the list
805 map_pointer_t
*Last
= &Ver
->FileList
;
806 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
808 VF
->NextFile
= *Last
;
811 VF
->Offset
= List
.Offset();
812 VF
->Size
= List
.Size();
813 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
814 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
815 Cache
.HeaderP
->VerFileCount
++;
820 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
821 // ---------------------------------------------------------------------
822 /* This puts a version structure in the linked list */
823 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
824 APT::StringView
const &VerStr
,
825 map_pointer_t
const ParentPkg
,
826 unsigned short const Hash
,
827 map_pointer_t
const Next
)
830 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
835 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
836 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
838 Ver
->ParentPkg
= ParentPkg
;
840 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
842 // try to find the version string in the group for reuse
843 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
844 pkgCache::GrpIterator Grp
= Pkg
.Group();
845 if (Pkg
.end() == false && Grp
.end() == false)
847 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
851 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
853 int const cmp
= strncmp(V
.VerStr(), VerStr
.data(), VerStr
.length());
854 if (cmp
== 0 && V
.VerStr()[VerStr
.length()] == '\0')
856 Ver
->VerStr
= V
->VerStr
;
864 // haven't found the version string, so create
865 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
866 if (unlikely(idxVerStr
== 0))
868 Ver
->VerStr
= idxVerStr
;
872 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
873 // ---------------------------------------------------------------------
875 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
878 if (CurrentFile
== 0)
882 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
886 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
887 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
889 // Link it to the end of the list
890 map_pointer_t
*Last
= &Desc
->FileList
;
891 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
894 DF
->NextFile
= *Last
;
897 DF
->Offset
= List
.Offset();
898 DF
->Size
= List
.Size();
899 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
900 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
901 Cache
.HeaderP
->DescFileCount
++;
906 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
907 // ---------------------------------------------------------------------
908 /* This puts a description structure in the linked list */
909 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
911 const MD5SumValue
&md5sum
,
912 map_stringitem_t
const idxmd5str
)
915 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
916 if (Description
== 0)
920 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
921 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
922 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
923 if (unlikely(idxlanguage_code
== 0))
925 Desc
->language_code
= idxlanguage_code
;
928 Desc
->md5sum
= idxmd5str
;
931 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
932 if (unlikely(idxmd5sum
== 0))
934 Desc
->md5sum
= idxmd5sum
;
940 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
941 // ---------------------------------------------------------------------
942 /* This creates a dependency element in the tree. It is linked to the
943 version and to the package that it is pointing to. */
944 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
945 pkgCache::VerIterator
&Ver
,
946 map_pointer_t
const Version
,
949 map_pointer_t
* &OldDepLast
)
951 void const * const oldMap
= Map
.Data();
953 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
954 if (unlikely(Dependency
== 0))
957 bool isDuplicate
= false;
958 map_pointer_t DependencyData
= 0;
959 map_pointer_t PreviousData
= 0;
960 if (Pkg
->RevDepends
!= 0)
962 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
963 DependencyData
= L
->DependencyData
;
965 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
966 if (Version
> D
->Version
)
968 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
973 PreviousData
= DependencyData
;
974 DependencyData
= D
->NextData
;
975 } while (DependencyData
!= 0);
978 if (isDuplicate
== false)
980 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
981 if (unlikely(DependencyData
== 0))
985 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
986 Link
->ParentVer
= Ver
.Index();
987 Link
->DependencyData
= DependencyData
;
988 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
990 pkgCache::DepIterator
Dep(Cache
, Link
);
991 if (isDuplicate
== false)
995 Dep
->Version
= Version
;
996 Dep
->Package
= Pkg
.Index();
997 ++Cache
.HeaderP
->DependsDataCount
;
998 if (PreviousData
!= 0)
1000 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
1001 Dep
->NextData
= D
->NextData
;
1002 D
->NextData
= DependencyData
;
1004 else if (Pkg
->RevDepends
!= 0)
1006 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
1007 Dep
->NextData
= D
->DependencyData
;
1011 if (isDuplicate
== true || PreviousData
!= 0)
1013 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
1014 Link
->NextRevDepends
= L
->NextRevDepends
;
1015 L
->NextRevDepends
= Dependency
;
1019 Link
->NextRevDepends
= Pkg
->RevDepends
;
1020 Pkg
->RevDepends
= Dependency
;
1024 // Do we know where to link the Dependency to?
1025 if (OldDepLast
== NULL
)
1027 OldDepLast
= &Ver
->DependsList
;
1028 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
1029 OldDepLast
= &D
->NextDepends
;
1030 } else if (oldMap
!= Map
.Data())
1031 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
1033 Dep
->NextDepends
= *OldDepLast
;
1034 *OldDepLast
= Dependency
;
1035 OldDepLast
= &Dep
->NextDepends
;
1039 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1040 // ---------------------------------------------------------------------
1041 /* This creates a Group and the Package to link this dependency to if
1042 needed and handles also the caching of the old endpoint */
1043 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1044 StringView PackageName
,
1050 pkgCache::GrpIterator Grp
;
1051 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1052 Dynamic
<StringView
> DynPackageName(PackageName
);
1053 Dynamic
<StringView
> DynArch(Arch
);
1054 Dynamic
<StringView
> DynVersion(Version
);
1055 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1058 map_stringitem_t idxVersion
= 0;
1059 if (Version
.empty() == false)
1061 int const CmpOp
= Op
& 0x0F;
1062 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1063 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1064 idxVersion
= Ver
->VerStr
;
1066 if (idxVersion
== 0)
1068 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1069 if (unlikely(idxVersion
== 0))
1074 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1075 Type
== pkgCache::Dep::Conflicts
||
1076 Type
== pkgCache::Dep::Replaces
);
1078 pkgCache::PkgIterator Pkg
;
1079 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1080 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1082 // Locate the target package
1083 Pkg
= Grp
.FindPkg(Arch
);
1084 if (Pkg
.end() == true) {
1085 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1089 /* Caching the old end point speeds up generation substantially */
1090 if (OldDepVer
!= Ver
) {
1095 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1099 /* Caching the old end point speeds up generation substantially */
1100 if (OldDepVer
!= Ver
) {
1105 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1107 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1114 // ListParser::NewProvides - Create a Provides element /*{{{*/
1115 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1119 uint8_t const Flags
)
1121 pkgCache
const &Cache
= Owner
->Cache
;
1122 Dynamic
<StringView
> DynPkgName(PkgName
);
1123 Dynamic
<StringView
> DynArch(PkgArch
);
1124 Dynamic
<StringView
> DynVersion(Version
);
1126 // We do not add self referencing provides
1127 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1128 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1129 (Version
.empty() || Version
== Ver
.VerStr()))
1132 // Locate the target package
1133 pkgCache::PkgIterator Pkg
;
1134 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1135 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1138 map_stringitem_t idxProvideVersion
= 0;
1139 if (Version
.empty() == false) {
1140 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1141 if (unlikely(idxProvideVersion
== 0))
1144 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1146 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1147 pkgCache::PkgIterator
&Pkg
,
1148 map_pointer_t
const ProvideVersion
,
1149 uint8_t const Flags
)
1152 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1153 if (unlikely(Provides
== 0))
1155 ++Cache
.HeaderP
->ProvidesCount
;
1158 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1159 Prv
->Version
= Ver
.Index();
1160 Prv
->ProvideVersion
= ProvideVersion
;
1162 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1163 Ver
->ProvidesList
= Prv
.Index();
1165 // Link it to the package
1166 Prv
->ParentPkg
= Pkg
.Index();
1167 Prv
->NextProvides
= Pkg
->ProvidesList
;
1168 Pkg
->ProvidesList
= Prv
.Index();
1172 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1173 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1174 StringView Version
, uint8_t const Flags
) {
1175 pkgCache
&Cache
= Owner
->Cache
;
1176 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1177 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1178 Dynamic
<StringView
> DynPackage(Package
);
1179 Dynamic
<StringView
> DynVersion(Version
);
1181 if (Grp
.end() == true)
1182 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1185 map_stringitem_t idxProvideVersion
= 0;
1186 if (Version
.empty() == false) {
1187 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1188 if (unlikely(idxProvideVersion
== 0))
1192 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1193 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1194 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1195 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1196 pkgCache::PkgIterator Pkg
;
1197 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1198 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1200 if (isImplicit
&& OwnerPkg
== Pkg
)
1202 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1204 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1211 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1212 pkgCache::VerIterator
const &Ver
)
1214 return Hash
== Ver
->Hash
;
1217 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1218 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1219 unsigned long Flags
)
1221 if (File
.empty() && Site
.empty())
1223 CurrentRlsFile
= NULL
;
1227 // Get some space for the structure
1228 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1229 if (unlikely(idxFile
== 0))
1231 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1234 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1235 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1236 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1238 CurrentRlsFile
->FileName
= idxFileName
;
1239 CurrentRlsFile
->Site
= idxSite
;
1240 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1241 CurrentRlsFile
->Flags
= Flags
;
1242 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1244 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1245 Cache
.HeaderP
->ReleaseFileCount
++;
1250 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1251 // ---------------------------------------------------------------------
1252 /* This is used to select which file is to be associated with all newly
1253 added versions. The caller is responsible for setting the IMS fields. */
1254 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1255 pkgIndexFile
const &Index
,
1256 std::string
const &Architecture
,
1257 std::string
const &Component
,
1258 unsigned long const Flags
)
1260 // Get some space for the structure
1261 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1262 if (unlikely(idxFile
== 0))
1264 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1267 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1268 if (unlikely(idxFileName
== 0))
1270 CurrentFile
->FileName
= idxFileName
;
1271 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1272 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1273 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1274 if (unlikely(idxIndexType
== 0))
1276 CurrentFile
->IndexType
= idxIndexType
;
1277 if (Architecture
.empty())
1278 CurrentFile
->Architecture
= 0;
1281 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1282 if (unlikely(arch
== 0))
1284 CurrentFile
->Architecture
= arch
;
1286 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1287 if (unlikely(component
== 0))
1289 CurrentFile
->Component
= component
;
1290 CurrentFile
->Flags
= Flags
;
1291 if (CurrentRlsFile
!= NULL
)
1292 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1294 CurrentFile
->Release
= 0;
1296 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1297 Cache
.HeaderP
->PackageFileCount
++;
1300 Progress
->SubProgress(Index
.Size());
1304 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1305 // ---------------------------------------------------------------------
1306 /* This is used to create handles to strings. Given the same text it
1307 always returns the same number */
1308 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1311 auto strings
= &strMixed
;
1313 case MIXED
: strings
= &strMixed
; break;
1314 case PKGNAME
: strings
= &strPkgNames
; break;
1315 case VERSIONNUMBER
: strings
= &strVersions
; break;
1316 case SECTION
: strings
= &strSections
; break;
1317 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1320 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1321 if (item
!= strings
->end())
1324 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1325 strings
->insert({nullptr, Size
, this, idxString
});
1329 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1330 // ---------------------------------------------------------------------
1331 /* This just verifies that each file in the list of index files exists,
1332 has matching attributes with the cache and the cache does not have
1334 class APT_HIDDEN ScopedErrorRevert
{
1336 ScopedErrorRevert() { _error
->PushToStack(); }
1337 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1339 static bool CheckValidity(const string
&CacheFile
,
1340 pkgSourceList
&List
,
1341 FileIterator
const Start
,
1342 FileIterator
const End
,
1344 pkgCache
**OutCache
= 0)
1346 ScopedErrorRevert ser
;
1347 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1348 // No file, certainly invalid
1349 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1352 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1356 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1359 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1364 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1365 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1366 if (unlikely(Map
->validData()) == false)
1368 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1369 pkgCache
&Cache
= *CacheP
.get();
1370 if (_error
->PendingError() || Map
->Size() == 0)
1373 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1377 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1378 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1379 std::vector
<pkgIndexFile
*> Files
;
1380 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1383 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1384 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1385 if (RlsFile
.end() == true)
1388 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1392 RlsVisited
[RlsFile
->ID
] = true;
1394 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1396 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1397 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1398 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1400 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1401 if (RlsVisited
[I
] == false)
1404 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1408 std::copy(Start
, End
, std::back_inserter(Files
));
1410 /* Now we check every index file, see if it is in the cache,
1411 verify the IMS data and check that it is on the disk too.. */
1412 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1413 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1414 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1417 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1418 if ((*PkgFile
)->Exists() == false)
1421 std::clog
<< "file doesn't exist" << std::endl
;
1425 // FindInCache is also expected to do an IMS check.
1426 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1427 if (File
.end() == true)
1430 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1434 Visited
[File
->ID
] = true;
1436 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1439 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1440 if (Visited
[I
] == false)
1443 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1447 if (_error
->PendingError() == true)
1451 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1452 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1458 *OutMap
= Map
.release();
1460 *OutCache
= CacheP
.release();
1464 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1465 // ---------------------------------------------------------------------
1466 /* Size is kind of an abstract notion that is only used for the progress
1468 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1470 map_filesize_t TotalSize
= 0;
1473 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1475 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1476 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1477 if ((*j
)->HasPackages() == true)
1478 TotalSize
+= (*j
)->Size();
1482 for (; Start
< End
; ++Start
)
1484 if ((*Start
)->HasPackages() == false)
1486 TotalSize
+= (*Start
)->Size();
1491 // BuildCache - Merge the list of index files into the cache /*{{{*/
1492 static bool BuildCache(pkgCacheGenerator
&Gen
,
1493 OpProgress
* const Progress
,
1494 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1495 pkgSourceList
const * const List
,
1496 FileIterator
const Start
, FileIterator
const End
)
1498 bool mergeFailure
= false;
1500 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1501 if (I
->HasPackages() == false || mergeFailure
)
1504 if (I
->Exists() == false)
1507 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1509 _error
->Warning("Duplicate sources.list entry %s",
1510 I
->Describe().c_str());
1514 map_filesize_t
const Size
= I
->Size();
1515 if (Progress
!= NULL
)
1516 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1517 CurrentSize
+= Size
;
1519 if (I
->Merge(Gen
,Progress
) == false)
1520 mergeFailure
= true;
1525 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1527 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1529 _error
->Warning("Duplicate sources.list entry %s",
1530 (*i
)->Describe().c_str());
1534 if ((*i
)->Merge(Gen
, Progress
) == false)
1537 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1538 if (Indexes
!= NULL
)
1539 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1547 Gen
.SelectReleaseFile("", "");
1548 std::for_each(Start
, End
, indexFileMerge
);
1555 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1556 // ---------------------------------------------------------------------
1557 /* This makes sure that the status cache (the cache that has all
1558 index files from the sources list and all local ones) is ready
1559 to be mmaped. If OutMap is not zero then a MMap object representing
1560 the cache will be stored there. This is pretty much mandetory if you
1561 are using AllowMem. AllowMem lets the function be run as non-root
1562 where it builds the cache 'fast' into a memory buffer. */
1563 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1565 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1566 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1567 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1568 Flags
|= MMap::Moveable
;
1569 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1570 Flags
|= MMap::Fallback
;
1572 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1574 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1576 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1577 std::string
const &FileName
)
1579 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1580 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1583 fchmod(SCacheF
.Fd(),0644);
1585 // Write out the main data
1586 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1587 return _error
->Error(_("IO Error saving source cache"));
1589 // Write out the proper header
1590 Gen
->GetCache().HeaderP
->Dirty
= false;
1591 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1592 if (SCacheF
.Seek(0) == false ||
1593 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1594 return _error
->Error(_("IO Error saving source cache"));
1595 Gen
->GetCache().HeaderP
->Dirty
= true;
1598 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1599 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1601 Map
.reset(CreateDynamicMMap(NULL
, 0));
1602 if (unlikely(Map
->validData()) == false)
1604 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1605 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1607 _error
->PushToStack();
1608 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1609 bool const newError
= _error
->PendingError();
1610 _error
->MergeWithStack();
1611 if (alloc
== 0 && newError
)
1613 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1615 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1616 return Gen
->Start();
1618 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1619 MMap
**OutMap
, bool AllowMem
)
1620 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1621 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1624 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1626 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1627 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1629 // FIXME: deprecate the ignored AllowMem parameter
1630 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1632 std::vector
<pkgIndexFile
*> Files
;
1633 if (_system
->AddStatusFiles(Files
) == false)
1636 // Decide if we can write to the files..
1637 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1638 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1640 // ensure the cache directory exists
1641 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1643 string dir
= _config
->FindDir("Dir::Cache");
1644 size_t const len
= dir
.size();
1645 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1646 dir
= dir
.substr(0, len
- 5);
1647 if (CacheFile
.empty() == false)
1648 CreateDirectory(dir
, flNotFile(CacheFile
));
1649 if (SrcCacheFile
.empty() == false)
1650 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1653 if (Progress
!= NULL
)
1654 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1656 bool pkgcache_fine
= false;
1657 bool srcpkgcache_fine
= false;
1658 bool volatile_fine
= List
.GetVolatileFiles().empty();
1660 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1661 volatile_fine
? OutCache
: NULL
) == true)
1664 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1665 pkgcache_fine
= true;
1666 srcpkgcache_fine
= true;
1668 if (pkgcache_fine
== false)
1670 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1673 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1674 srcpkgcache_fine
= true;
1678 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1680 if (Progress
!= NULL
)
1681 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1685 bool Writeable
= false;
1686 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1688 if (CacheFile
.empty() == false)
1689 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1690 else if (SrcCacheFile
.empty() == false)
1691 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1694 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1697 // At this point we know we need to construct something, so get storage ready
1698 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1699 if (unlikely(Map
->validData()) == false)
1702 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1704 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1705 map_filesize_t CurrentSize
= 0;
1706 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1707 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1708 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1711 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1712 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1714 srcpkgcache_fine
= true;
1715 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1717 else if (srcpkgcache_fine
== false)
1720 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1721 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1722 if (Gen
->Start() == false)
1725 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1726 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1727 Files
.end(),Files
.end()) == false)
1730 if (Writeable
== true && SrcCacheFile
.empty() == false)
1731 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1735 if (pkgcache_fine
== false)
1738 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1739 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1740 Files
.begin(), Files
.end()) == false)
1743 if (Writeable
== true && CacheFile
.empty() == false)
1744 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1749 std::clog
<< "Caches done. " << (volatile_fine
? "No volatile files, so we are done here." : "Now bring in the volatile files") << std::endl
;
1751 if (volatile_fine
== false)
1756 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1757 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1761 Files
= List
.GetVolatileFiles();
1762 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1763 Files
.begin(), Files
.end()) == false)
1767 if (OutMap
!= nullptr)
1768 *OutMap
= Map
.release();
1771 std::clog
<< "Everything is ready for shipping" << std::endl
;
1775 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1776 class APT_HIDDEN ScopedErrorMerge
{
1778 ScopedErrorMerge() { _error
->PushToStack(); }
1779 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1781 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1782 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1783 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1785 std::vector
<pkgIndexFile
*> Files
;
1786 if (_system
->AddStatusFiles(Files
) == false)
1789 ScopedErrorMerge sem
;
1790 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1791 if (unlikely(Map
->validData()) == false)
1793 map_filesize_t CurrentSize
= 0;
1794 map_filesize_t TotalSize
= 0;
1795 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1797 // Build the status cache
1798 if (Progress
!= NULL
)
1799 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1800 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1801 if (Gen
.Start() == false || _error
->PendingError() == true)
1803 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1804 Files
.begin(), Files
.end()) == false)
1807 if (_error
->PendingError() == true)
1809 *OutMap
= Map
.release();
1814 // IsDuplicateDescription /*{{{*/
1815 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1816 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1818 // Descriptions in the same link-list have all the same md5
1819 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1821 for (; Desc
.end() == false; ++Desc
)
1822 if (Desc
.LanguageCode() == CurLang
)
1828 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1829 pkgCacheListParser::~pkgCacheListParser() {}