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
)
63 // Setup the map interface..
64 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
65 _error
->PushToStack();
66 Map
.RawAllocate(sizeof(pkgCache::Header
));
67 bool const newError
= _error
->PendingError();
68 _error
->MergeWithStack();
72 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
75 *Cache
.HeaderP
= pkgCache::Header();
77 // make room for the hashtables for packages and groups
78 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
81 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
82 if (unlikely(idxVerSysName
== 0))
84 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
85 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
86 if (unlikely(idxArchitecture
== 0))
88 Cache
.HeaderP
->Architecture
= idxArchitecture
;
90 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
93 std::vector
<std::string
>::const_iterator a
= archs
.begin();
94 std::string list
= *a
;
95 for (++a
; a
!= archs
.end(); ++a
)
96 list
.append(",").append(*a
);
97 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
98 if (unlikely(idxArchitectures
== 0))
100 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
103 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
105 // Calculate the hash for the empty map, so ReMap does not fail
106 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
111 // Map directly from the existing file
113 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
114 if (Cache
.VS
!= _system
->VS
)
116 _error
->Error(_("Cache has an incompatible versioning system"));
121 Cache
.HeaderP
->Dirty
= true;
122 Map
.Sync(0,sizeof(pkgCache::Header
));
125 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
126 // ---------------------------------------------------------------------
127 /* We sync the data then unset the dirty flag in two steps so as to
128 advoid a problem during a crash */
129 pkgCacheGenerator::~pkgCacheGenerator()
131 if (_error
->PendingError() == true || Map
.validData() == false)
133 if (Map
.Sync() == false)
136 Cache
.HeaderP
->Dirty
= false;
137 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
139 if (_config
->FindB("Debug::pkgCacheGen", false))
140 std::clog
<< "Produced cache with hash " << Cache
.HeaderP
->CacheFileSize
<< std::endl
;
141 Map
.Sync(0,sizeof(pkgCache::Header
));
144 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
, size_t oldSize
) {/*{{{*/
145 if (oldMap
== newMap
)
148 if (_config
->FindB("Debug::pkgCacheGen", false))
149 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
153 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
154 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
156 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
157 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
158 (*i
)->ReMap(oldMap
, newMap
);
159 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
160 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
161 (*i
)->ReMap(oldMap
, newMap
);
162 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
163 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
164 (*i
)->ReMap(oldMap
, newMap
);
165 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
166 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
167 (*i
)->ReMap(oldMap
, newMap
);
168 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
169 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
170 (*i
)->ReMap(oldMap
, newMap
);
171 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
172 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
173 (*i
)->ReMap(oldMap
, newMap
);
174 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
175 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
176 (*i
)->ReMap(oldMap
, newMap
);
177 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
178 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
179 (*i
)->ReMap(oldMap
, newMap
);
180 for (APT::StringView
* ViewP
: Dynamic
<APT::StringView
>::toReMap
) {
181 // Ignore views outside of the cache.
182 if (ViewP
->data() < static_cast<const char*>(oldMap
)
183 || ViewP
->data() > static_cast<const char*>(oldMap
) + oldSize
)
185 const char *data
= ViewP
->data() + (static_cast<const char*>(newMap
) - static_cast<const char*>(oldMap
));
186 *ViewP
= StringView(data
, ViewP
->size());
189 // CacheGenerator::WriteStringInMap /*{{{*/
190 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
191 const unsigned long &Len
) {
192 size_t oldSize
= Map
.Size();
193 void const * const oldMap
= Map
.Data();
194 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
196 ReMap(oldMap
, Map
.Data(), oldSize
);
200 // CacheGenerator::WriteStringInMap /*{{{*/
201 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
202 size_t oldSize
= Map
.Size();
203 void const * const oldMap
= Map
.Data();
204 map_stringitem_t
const index
= Map
.WriteString(String
);
206 ReMap(oldMap
, Map
.Data(), oldSize
);
210 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
211 size_t oldSize
= Map
.Size();
212 void const * const oldMap
= Map
.Data();
213 map_pointer_t
const index
= Map
.Allocate(size
);
215 ReMap(oldMap
, Map
.Data(), oldSize
);
219 // CacheGenerator::MergeList - Merge the package list /*{{{*/
220 // ---------------------------------------------------------------------
221 /* This provides the generation of the entries in the cache. Each loop
222 goes through a single package record from the underlying parse engine. */
223 bool pkgCacheGenerator::MergeList(ListParser
&List
,
224 pkgCache::VerIterator
*OutVer
)
228 unsigned int Counter
= 0;
229 while (List
.Step() == true)
231 string
const PackageName
= List
.Package();
232 if (PackageName
.empty() == true)
236 if (Counter
% 100 == 0 && Progress
!= 0)
237 Progress
->Progress(List
.Offset());
239 APT::StringView Arch
= List
.Architecture();
240 Dynamic
<APT::StringView
> DynArch(Arch
);
241 APT::StringView Version
= List
.Version();
242 Dynamic
<APT::StringView
> DynVersion(Version
);
243 if (Version
.empty() == true && Arch
.empty() == true)
245 // package descriptions
246 if (MergeListGroup(List
, PackageName
) == false)
251 // Get a pointer to the package structure
252 pkgCache::PkgIterator Pkg
;
253 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
254 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
255 // TRANSLATOR: The first placeholder is a package name,
256 // the other two should be copied verbatim as they include debug info
257 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
258 PackageName
.c_str(), "NewPackage", 1);
261 if (Version
.empty() == true)
263 if (MergeListPackage(List
, Pkg
) == false)
268 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
276 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
277 return _error
->Error(_("Wow, you exceeded the number of package "
278 "names this APT is capable of."));
279 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
280 return _error
->Error(_("Wow, you exceeded the number of versions "
281 "this APT is capable of."));
282 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
283 return _error
->Error(_("Wow, you exceeded the number of descriptions "
284 "this APT is capable of."));
285 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
286 return _error
->Error(_("Wow, you exceeded the number of dependencies "
287 "this APT is capable of."));
291 // CacheGenerator::MergeListGroup /*{{{*/
292 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
294 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
295 // a group has no data on it's own, only packages have it but these
296 // stanzas like this come from Translation- files to add descriptions,
297 // but without a version we don't need a description for it…
298 if (Grp
.end() == true)
300 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
302 pkgCache::PkgIterator Pkg
;
303 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
304 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
305 if (MergeListPackage(List
, Pkg
) == false)
311 // CacheGenerator::MergeListPackage /*{{{*/
312 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
314 // we first process the package, then the descriptions
315 // (for deb this package processing is in fact a no-op)
316 pkgCache::VerIterator
Ver(Cache
);
317 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
318 if (List
.UsePackage(Pkg
, Ver
) == false)
319 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
320 Pkg
.Name(), "UsePackage", 1);
322 // Find the right version to write the description
323 MD5SumValue CurMd5
= List
.Description_md5();
324 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
325 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
327 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
329 // a version can only have one md5 describing it
330 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
333 map_stringitem_t md5idx
= VerDesc
->md5sum
;
334 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
336 // don't add a new description if we have one for the given
338 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
341 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
344 // we can stop here as all "same" versions will share the description
351 // CacheGenerator::MergeListVersion /*{{{*/
352 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
353 APT::StringView
const &Version
, pkgCache::VerIterator
* &OutVer
)
355 pkgCache::VerIterator Ver
= Pkg
.VersionList();
356 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
357 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
358 void const * oldMap
= Map
.Data();
360 unsigned short const Hash
= List
.VersionHash();
361 if (Ver
.end() == false)
363 /* We know the list is sorted so we use that fact in the search.
364 Insertion of new versions is done with correct sorting */
366 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
368 char const * const VerStr
= Ver
.VerStr();
369 Res
= Cache
.VS
->DoCmpVersion(Version
.data(), Version
.data() + Version
.length(),
370 VerStr
, VerStr
+ strlen(VerStr
));
371 // Version is higher as current version - insert here
374 // Versionstrings are equal - is hash also equal?
375 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
377 // proceed with the next till we have either the right
378 // or we found another version (which will be lower)
381 /* We already have a version for this item, record that we saw it */
382 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
384 if (List
.UsePackage(Pkg
,Ver
) == false)
385 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
386 Pkg
.Name(), "UsePackage", 2);
388 if (NewFileVer(Ver
,List
) == false)
389 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
390 Pkg
.Name(), "NewFileVer", 1);
392 // Read only a single record and return
404 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
405 if (unlikely(verindex
== 0))
406 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
407 Pkg
.Name(), "NewVersion", 1);
409 if (oldMap
!= Map
.Data())
410 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
413 if (unlikely(List
.NewVersion(Ver
) == false))
414 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
415 Pkg
.Name(), "NewVersion", 2);
417 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
418 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
419 Pkg
.Name(), "UsePackage", 3);
421 if (unlikely(NewFileVer(Ver
,List
) == false))
422 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
423 Pkg
.Name(), "NewFileVer", 2);
425 pkgCache::GrpIterator Grp
= Pkg
.Group();
426 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
428 /* If it is the first version of this package we need to add implicit
429 Multi-Arch dependencies to all other package versions in the group now -
430 otherwise we just add them for this new version */
431 if (Pkg
.VersionList()->NextVer
== 0)
433 pkgCache::PkgIterator P
= Grp
.PackageList();
434 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
435 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
437 if (P
->ID
== Pkg
->ID
)
439 pkgCache::VerIterator V
= P
.VersionList();
440 Dynamic
<pkgCache::VerIterator
> DynV(V
);
441 for (; V
.end() != true; ++V
)
442 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
443 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
444 Pkg
.Name(), "AddImplicitDepends", 1);
447 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
448 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
449 Pkg
.Name(), "AddImplicitDepends", 2);
451 // Read only a single record and return
458 /* Record the Description(s) based on their master md5sum */
459 MD5SumValue CurMd5
= List
.Description_md5();
461 /* Before we add a new description we first search in the group for
462 a version with a description of the same MD5 - if so we reuse this
463 description group instead of creating our own for this version */
464 for (pkgCache::PkgIterator P
= Grp
.PackageList();
465 P
.end() == false; P
= Grp
.NextPkg(P
))
467 for (pkgCache::VerIterator V
= P
.VersionList();
468 V
.end() == false; ++V
)
470 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
472 Ver
->DescriptionList
= V
->DescriptionList
;
476 // We haven't found reusable descriptions, so add the first description(s)
477 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
478 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
479 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
480 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
485 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
487 pkgCache::DescIterator Desc
;
488 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
490 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
491 if (unlikely(descindex
== 0))
492 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
493 Ver
.ParentPkg().Name(), "NewDescription", 1);
495 md5idx
= Desc
->md5sum
;
496 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
498 // we add at the end, so that the start is constant as we need
499 // that to be able to efficiently share these lists
500 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
501 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
502 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
503 *LastNextDesc
= descindex
;
505 if (NewFileDesc(Desc
,List
) == false)
506 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
507 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
513 // CacheGenerator::NewGroup - Add a new group /*{{{*/
514 // ---------------------------------------------------------------------
515 /* This creates a new group structure and adds it to the hash table */
516 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, StringView Name
)
518 Dynamic
<StringView
> DName(Name
);
519 Grp
= Cache
.FindGrp(Name
);
520 if (Grp
.end() == false)
524 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
525 if (unlikely(Group
== 0))
528 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
529 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
530 if (unlikely(idxName
== 0))
534 // Insert it into the hash table
535 unsigned long const Hash
= Cache
.Hash(Name
);
536 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
538 while (*insertAt
!= 0 && Name
.compare(Cache
.ViewString((Cache
.GrpP
+ *insertAt
)->Name
)) > 0)
539 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
540 Grp
->Next
= *insertAt
;
543 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
547 // CacheGenerator::NewPackage - Add a new package /*{{{*/
548 // ---------------------------------------------------------------------
549 /* This creates a new package structure and adds it to the hash table */
550 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
, StringView Name
,
552 pkgCache::GrpIterator Grp
;
553 Dynamic
<StringView
> DName(Name
);
554 Dynamic
<StringView
> DArch(Arch
);
555 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
556 if (unlikely(NewGroup(Grp
, Name
) == false))
559 Pkg
= Grp
.FindPkg(Arch
);
560 if (Pkg
.end() == false)
564 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
565 if (unlikely(Package
== 0))
567 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
569 // Set the name, arch and the ID
570 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
571 Pkg
->Group
= Grp
.Index();
572 // all is mapped to the native architecture
573 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
574 if (unlikely(idxArch
== 0))
577 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
579 // Insert the package into our package list
580 if (Grp
->FirstPackage
== 0) // the group is new
582 Grp
->FirstPackage
= Package
;
583 // Insert it into the hash table
584 map_id_t
const Hash
= Cache
.Hash(Name
);
585 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
586 while (*insertAt
!= 0 && Name
.compare(Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
587 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
588 Pkg
->NextPackage
= *insertAt
;
591 else // Group the Packages together
593 // if sibling is provided by another package, this one is too
595 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
596 if (M
.end() == false) {
597 pkgCache::PrvIterator Prv
;
598 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
599 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
601 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
603 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
604 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
605 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
606 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
607 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
609 if (APT::Configuration::checkArchitecture(Ver
.ParentPkg().Arch()) == false)
611 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
617 // let M-A:foreign package siblings provide this package
619 pkgCache::PkgIterator P
;
620 pkgCache::VerIterator Ver
;
621 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
622 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
624 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
626 if (APT::Configuration::checkArchitecture(P
.Arch()) == false)
628 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
629 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
630 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
634 // and negative dependencies, don't forget negative dependencies
636 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
637 if (M
.end() == false) {
638 pkgCache::DepIterator Dep
;
639 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
640 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
642 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
644 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
645 Dep
->Type
!= pkgCache::Dep::Replaces
)
647 pkgCache::VerIterator Ver
= Dep
.ParentVer();
648 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
649 map_pointer_t
* unused
= NULL
;
650 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
656 // this package is the new last package
657 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
658 Pkg
->NextPackage
= LastPkg
->NextPackage
;
659 LastPkg
->NextPackage
= Package
;
661 Grp
->LastPackage
= Package
;
663 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
666 size_t const found
= Name
.rfind(':');
667 StringView ArchA
= Name
.substr(found
+ 1);
670 // ArchA is used inside the loop which might remap (NameA is not used)
671 Dynamic
<StringView
> DynArchA(ArchA
);
672 StringView NameA
= Name
.substr(0, found
);
673 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
674 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
677 Dynamic
<StringView
> DynNameA(NameA
);
678 if (NewPackage(PkgA
, NameA
, ArchA
) == false)
681 if (unlikely(PkgA
.end()))
682 return _error
->Fatal("NewPackage was successful for %s:%s,"
683 "but the package doesn't exist anyhow!",
684 NameA
.to_string().c_str(), ArchA
.to_string().c_str());
687 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
688 for (; Prv
.end() == false; ++Prv
)
690 if (Prv
.IsMultiArchImplicit())
692 pkgCache::VerIterator V
= Prv
.OwnerVer();
693 if (ArchA
!= V
.ParentPkg().Arch())
695 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
698 pkgCache::VerIterator V
= PkgA
.VersionList();
699 Dynamic
<pkgCache::VerIterator
> DynV(V
);
700 for (; V
.end() == false; ++V
)
702 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
711 // CacheGenerator::AddImplicitDepends /*{{{*/
712 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
713 pkgCache::PkgIterator
&P
,
714 pkgCache::VerIterator
&V
)
716 APT::StringView Arch
= P
.Arch() == NULL
? "" : P
.Arch();
717 Dynamic
<APT::StringView
> DynArch(Arch
);
718 map_pointer_t
*OldDepLast
= NULL
;
719 /* MultiArch handling introduces a lot of implicit Dependencies:
720 - MultiArch: same → Co-Installable if they have the same version
721 - All others conflict with all other group members */
722 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
723 pkgCache::PkgIterator D
= G
.PackageList();
724 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
725 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
726 for (; D
.end() != true; D
= G
.NextPkg(D
))
728 if (Arch
== D
.Arch() || D
->VersionList
== 0)
730 /* We allow only one installed arch at the time
731 per group, therefore each group member conflicts
732 with all other group members */
733 if (coInstall
== true)
735 // Replaces: ${self}:other ( << ${binary:Version})
736 NewDepends(D
, V
, VerStrIdx
,
737 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
739 // Breaks: ${self}:other (!= ${binary:Version})
740 NewDepends(D
, V
, VerStrIdx
,
741 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
744 // Conflicts: ${self}:other
746 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
752 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
753 pkgCache::PkgIterator
&D
)
755 /* MultiArch handling introduces a lot of implicit Dependencies:
756 - MultiArch: same → Co-Installable if they have the same version
757 - All others conflict with all other group members */
758 map_pointer_t
*OldDepLast
= NULL
;
759 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
760 if (coInstall
== true)
762 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
763 // Replaces: ${self}:other ( << ${binary:Version})
764 NewDepends(D
, V
, VerStrIdx
,
765 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
767 // Breaks: ${self}:other (!= ${binary:Version})
768 NewDepends(D
, V
, VerStrIdx
,
769 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
772 // Conflicts: ${self}:other
774 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
781 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
782 // ---------------------------------------------------------------------
784 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
787 if (CurrentFile
== 0)
791 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
795 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
796 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
798 // Link it to the end of the list
799 map_pointer_t
*Last
= &Ver
->FileList
;
800 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
802 VF
->NextFile
= *Last
;
805 VF
->Offset
= List
.Offset();
806 VF
->Size
= List
.Size();
807 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
808 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
809 Cache
.HeaderP
->VerFileCount
++;
814 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
815 // ---------------------------------------------------------------------
816 /* This puts a version structure in the linked list */
817 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
818 APT::StringView
const &VerStr
,
819 map_pointer_t
const ParentPkg
,
820 unsigned short const Hash
,
821 map_pointer_t
const Next
)
824 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
829 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
830 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
832 Ver
->ParentPkg
= ParentPkg
;
834 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
836 // try to find the version string in the group for reuse
837 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
838 pkgCache::GrpIterator Grp
= Pkg
.Group();
839 if (Pkg
.end() == false && Grp
.end() == false)
841 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
845 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
847 int const cmp
= strncmp(V
.VerStr(), VerStr
.data(), VerStr
.length());
848 if (cmp
== 0 && V
.VerStr()[VerStr
.length()] == '\0')
850 Ver
->VerStr
= V
->VerStr
;
858 // haven't found the version string, so create
859 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
860 if (unlikely(idxVerStr
== 0))
862 Ver
->VerStr
= idxVerStr
;
866 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
867 // ---------------------------------------------------------------------
869 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
872 if (CurrentFile
== 0)
876 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
880 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
881 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
883 // Link it to the end of the list
884 map_pointer_t
*Last
= &Desc
->FileList
;
885 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
888 DF
->NextFile
= *Last
;
891 DF
->Offset
= List
.Offset();
892 DF
->Size
= List
.Size();
893 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
894 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
895 Cache
.HeaderP
->DescFileCount
++;
900 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
901 // ---------------------------------------------------------------------
902 /* This puts a description structure in the linked list */
903 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
905 const MD5SumValue
&md5sum
,
906 map_stringitem_t
const idxmd5str
)
909 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
910 if (Description
== 0)
914 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
915 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
916 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
917 if (unlikely(idxlanguage_code
== 0))
919 Desc
->language_code
= idxlanguage_code
;
922 Desc
->md5sum
= idxmd5str
;
925 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
926 if (unlikely(idxmd5sum
== 0))
928 Desc
->md5sum
= idxmd5sum
;
934 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
935 // ---------------------------------------------------------------------
936 /* This creates a dependency element in the tree. It is linked to the
937 version and to the package that it is pointing to. */
938 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
939 pkgCache::VerIterator
&Ver
,
940 map_pointer_t
const Version
,
943 map_pointer_t
* &OldDepLast
)
945 void const * const oldMap
= Map
.Data();
947 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
948 if (unlikely(Dependency
== 0))
951 bool isDuplicate
= false;
952 map_pointer_t DependencyData
= 0;
953 map_pointer_t PreviousData
= 0;
954 if (Pkg
->RevDepends
!= 0)
956 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
957 DependencyData
= L
->DependencyData
;
959 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
960 if (Version
> D
->Version
)
962 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
967 PreviousData
= DependencyData
;
968 DependencyData
= D
->NextData
;
969 } while (DependencyData
!= 0);
972 if (isDuplicate
== false)
974 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
975 if (unlikely(DependencyData
== 0))
979 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
980 Link
->ParentVer
= Ver
.Index();
981 Link
->DependencyData
= DependencyData
;
982 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
984 pkgCache::DepIterator
Dep(Cache
, Link
);
985 if (isDuplicate
== false)
989 Dep
->Version
= Version
;
990 Dep
->Package
= Pkg
.Index();
991 ++Cache
.HeaderP
->DependsDataCount
;
992 if (PreviousData
!= 0)
994 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
995 Dep
->NextData
= D
->NextData
;
996 D
->NextData
= DependencyData
;
998 else if (Pkg
->RevDepends
!= 0)
1000 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
1001 Dep
->NextData
= D
->DependencyData
;
1005 if (isDuplicate
== true || PreviousData
!= 0)
1007 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
1008 Link
->NextRevDepends
= L
->NextRevDepends
;
1009 L
->NextRevDepends
= Dependency
;
1013 Link
->NextRevDepends
= Pkg
->RevDepends
;
1014 Pkg
->RevDepends
= Dependency
;
1018 // Do we know where to link the Dependency to?
1019 if (OldDepLast
== NULL
)
1021 OldDepLast
= &Ver
->DependsList
;
1022 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
1023 OldDepLast
= &D
->NextDepends
;
1024 } else if (oldMap
!= Map
.Data())
1025 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
1027 Dep
->NextDepends
= *OldDepLast
;
1028 *OldDepLast
= Dependency
;
1029 OldDepLast
= &Dep
->NextDepends
;
1033 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1034 // ---------------------------------------------------------------------
1035 /* This creates a Group and the Package to link this dependency to if
1036 needed and handles also the caching of the old endpoint */
1037 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1038 StringView PackageName
,
1044 pkgCache::GrpIterator Grp
;
1045 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1046 Dynamic
<StringView
> DynPackageName(PackageName
);
1047 Dynamic
<StringView
> DynArch(Arch
);
1048 Dynamic
<StringView
> DynVersion(Version
);
1049 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1052 map_stringitem_t idxVersion
= 0;
1053 if (Version
.empty() == false)
1055 int const CmpOp
= Op
& 0x0F;
1056 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1057 if (CmpOp
== pkgCache::Dep::Equals
&& Version
== Ver
.VerStr())
1058 idxVersion
= Ver
->VerStr
;
1060 if (idxVersion
== 0)
1062 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1063 if (unlikely(idxVersion
== 0))
1068 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1069 Type
== pkgCache::Dep::Conflicts
||
1070 Type
== pkgCache::Dep::Replaces
);
1072 pkgCache::PkgIterator Pkg
;
1073 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1074 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1076 // Locate the target package
1077 Pkg
= Grp
.FindPkg(Arch
);
1078 if (Pkg
.end() == true) {
1079 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1083 /* Caching the old end point speeds up generation substantially */
1084 if (OldDepVer
!= Ver
) {
1089 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1093 /* Caching the old end point speeds up generation substantially */
1094 if (OldDepVer
!= Ver
) {
1099 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1101 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1108 // ListParser::NewProvides - Create a Provides element /*{{{*/
1109 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1113 uint8_t const Flags
)
1115 pkgCache
const &Cache
= Owner
->Cache
;
1116 Dynamic
<StringView
> DynPkgName(PkgName
);
1117 Dynamic
<StringView
> DynArch(PkgArch
);
1118 Dynamic
<StringView
> DynVersion(Version
);
1120 // We do not add self referencing provides
1121 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1122 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1123 (Version
.empty() || Version
== Ver
.VerStr()))
1126 // Locate the target package
1127 pkgCache::PkgIterator Pkg
;
1128 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1129 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1132 map_stringitem_t idxProvideVersion
= 0;
1133 if (Version
.empty() == false) {
1134 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1135 if (unlikely(idxProvideVersion
== 0))
1138 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1140 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1141 pkgCache::PkgIterator
&Pkg
,
1142 map_pointer_t
const ProvideVersion
,
1143 uint8_t const Flags
)
1146 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1147 if (unlikely(Provides
== 0))
1149 ++Cache
.HeaderP
->ProvidesCount
;
1152 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1153 Prv
->Version
= Ver
.Index();
1154 Prv
->ProvideVersion
= ProvideVersion
;
1156 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1157 Ver
->ProvidesList
= Prv
.Index();
1159 // Link it to the package
1160 Prv
->ParentPkg
= Pkg
.Index();
1161 Prv
->NextProvides
= Pkg
->ProvidesList
;
1162 Pkg
->ProvidesList
= Prv
.Index();
1166 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1167 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, StringView Package
,
1168 StringView Version
, uint8_t const Flags
) {
1169 pkgCache
&Cache
= Owner
->Cache
;
1170 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1171 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1172 Dynamic
<StringView
> DynPackage(Package
);
1173 Dynamic
<StringView
> DynVersion(Version
);
1175 if (Grp
.end() == true)
1176 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1179 map_stringitem_t idxProvideVersion
= 0;
1180 if (Version
.empty() == false) {
1181 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1182 if (unlikely(idxProvideVersion
== 0))
1186 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1187 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1188 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1189 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1190 pkgCache::PkgIterator Pkg
;
1191 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1192 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1194 if (isImplicit
&& OwnerPkg
== Pkg
)
1196 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1198 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1205 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1206 pkgCache::VerIterator
const &Ver
)
1208 return Hash
== Ver
->Hash
;
1211 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1212 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1213 unsigned long Flags
)
1215 if (File
.empty() && Site
.empty())
1217 CurrentRlsFile
= NULL
;
1221 // Get some space for the structure
1222 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1223 if (unlikely(idxFile
== 0))
1225 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1228 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1229 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1230 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1232 CurrentRlsFile
->FileName
= idxFileName
;
1233 CurrentRlsFile
->Site
= idxSite
;
1234 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1235 CurrentRlsFile
->Flags
= Flags
;
1236 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1238 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1239 Cache
.HeaderP
->ReleaseFileCount
++;
1244 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1245 // ---------------------------------------------------------------------
1246 /* This is used to select which file is to be associated with all newly
1247 added versions. The caller is responsible for setting the IMS fields. */
1248 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1249 pkgIndexFile
const &Index
,
1250 std::string
const &Architecture
,
1251 std::string
const &Component
,
1252 unsigned long const Flags
)
1254 // Get some space for the structure
1255 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1256 if (unlikely(idxFile
== 0))
1258 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1261 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1262 if (unlikely(idxFileName
== 0))
1264 CurrentFile
->FileName
= idxFileName
;
1265 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1266 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1267 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1268 if (unlikely(idxIndexType
== 0))
1270 CurrentFile
->IndexType
= idxIndexType
;
1271 if (Architecture
.empty())
1272 CurrentFile
->Architecture
= 0;
1275 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1276 if (unlikely(arch
== 0))
1278 CurrentFile
->Architecture
= arch
;
1280 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1281 if (unlikely(component
== 0))
1283 CurrentFile
->Component
= component
;
1284 CurrentFile
->Flags
= Flags
;
1285 if (CurrentRlsFile
!= NULL
)
1286 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1288 CurrentFile
->Release
= 0;
1290 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1291 Cache
.HeaderP
->PackageFileCount
++;
1294 Progress
->SubProgress(Index
.Size());
1298 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1299 // ---------------------------------------------------------------------
1300 /* This is used to create handles to strings. Given the same text it
1301 always returns the same number */
1302 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1305 auto strings
= &strMixed
;
1307 case MIXED
: strings
= &strMixed
; break;
1308 case PKGNAME
: strings
= &strPkgNames
; break;
1309 case VERSIONNUMBER
: strings
= &strVersions
; break;
1310 case SECTION
: strings
= &strSections
; break;
1311 default: _error
->Fatal("Unknown enum type used for string storage of '%.*s'", Size
, S
); return 0;
1314 auto const item
= strings
->find({S
, Size
, nullptr, 0});
1315 if (item
!= strings
->end())
1318 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1319 strings
->insert({nullptr, Size
, this, idxString
});
1323 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1324 // ---------------------------------------------------------------------
1325 /* This just verifies that each file in the list of index files exists,
1326 has matching attributes with the cache and the cache does not have
1328 class APT_HIDDEN ScopedErrorRevert
{
1330 ScopedErrorRevert() { _error
->PushToStack(); }
1331 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1333 static bool CheckValidity(const string
&CacheFile
,
1334 pkgSourceList
&List
,
1335 FileIterator
const Start
,
1336 FileIterator
const End
,
1338 pkgCache
**OutCache
= 0)
1340 ScopedErrorRevert ser
;
1341 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1342 // No file, certainly invalid
1343 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1346 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1350 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1353 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1358 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1359 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1360 if (unlikely(Map
->validData()) == false)
1362 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1363 pkgCache
&Cache
= *CacheP
.get();
1364 if (_error
->PendingError() || Map
->Size() == 0)
1367 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1371 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1372 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1373 std::vector
<pkgIndexFile
*> Files
;
1374 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1377 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1378 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1379 if (RlsFile
.end() == true)
1382 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1386 RlsVisited
[RlsFile
->ID
] = true;
1388 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1390 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1391 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1392 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1394 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1395 if (RlsVisited
[I
] == false)
1398 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1402 std::copy(Start
, End
, std::back_inserter(Files
));
1404 /* Now we check every index file, see if it is in the cache,
1405 verify the IMS data and check that it is on the disk too.. */
1406 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1407 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1408 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1411 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1412 if ((*PkgFile
)->Exists() == false)
1415 std::clog
<< "file doesn't exist" << std::endl
;
1419 // FindInCache is also expected to do an IMS check.
1420 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1421 if (File
.end() == true)
1424 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1428 Visited
[File
->ID
] = true;
1430 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1433 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1434 if (Visited
[I
] == false)
1437 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1441 if (_error
->PendingError() == true)
1445 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1446 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1452 *OutMap
= Map
.release();
1454 *OutCache
= CacheP
.release();
1458 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1459 // ---------------------------------------------------------------------
1460 /* Size is kind of an abstract notion that is only used for the progress
1462 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1464 map_filesize_t TotalSize
= 0;
1467 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1469 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1470 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1471 if ((*j
)->HasPackages() == true)
1472 TotalSize
+= (*j
)->Size();
1476 for (; Start
< End
; ++Start
)
1478 if ((*Start
)->HasPackages() == false)
1480 TotalSize
+= (*Start
)->Size();
1485 // BuildCache - Merge the list of index files into the cache /*{{{*/
1486 static bool BuildCache(pkgCacheGenerator
&Gen
,
1487 OpProgress
* const Progress
,
1488 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1489 pkgSourceList
const * const List
,
1490 FileIterator
const Start
, FileIterator
const End
)
1492 bool mergeFailure
= false;
1494 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1495 if (I
->HasPackages() == false || mergeFailure
)
1498 if (I
->Exists() == false)
1501 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1503 _error
->Warning("Duplicate sources.list entry %s",
1504 I
->Describe().c_str());
1508 map_filesize_t
const Size
= I
->Size();
1509 if (Progress
!= NULL
)
1510 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1511 CurrentSize
+= Size
;
1513 if (I
->Merge(Gen
,Progress
) == false)
1514 mergeFailure
= true;
1519 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1521 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1523 _error
->Warning("Duplicate sources.list entry %s",
1524 (*i
)->Describe().c_str());
1528 if ((*i
)->Merge(Gen
, Progress
) == false)
1531 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1532 if (Indexes
!= NULL
)
1533 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1541 Gen
.SelectReleaseFile("", "");
1542 std::for_each(Start
, End
, indexFileMerge
);
1549 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1550 // ---------------------------------------------------------------------
1551 /* This makes sure that the status cache (the cache that has all
1552 index files from the sources list and all local ones) is ready
1553 to be mmaped. If OutMap is not zero then a MMap object representing
1554 the cache will be stored there. This is pretty much mandetory if you
1555 are using AllowMem. AllowMem lets the function be run as non-root
1556 where it builds the cache 'fast' into a memory buffer. */
1557 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1559 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1560 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1561 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1562 Flags
|= MMap::Moveable
;
1563 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1564 Flags
|= MMap::Fallback
;
1566 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1568 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1570 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1571 std::string
const &FileName
)
1573 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1574 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1577 fchmod(SCacheF
.Fd(),0644);
1579 // Write out the main data
1580 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1581 return _error
->Error(_("IO Error saving source cache"));
1583 // Write out the proper header
1584 Gen
->GetCache().HeaderP
->Dirty
= false;
1585 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1586 if (SCacheF
.Seek(0) == false ||
1587 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1588 return _error
->Error(_("IO Error saving source cache"));
1589 Gen
->GetCache().HeaderP
->Dirty
= true;
1592 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1593 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1595 Map
.reset(CreateDynamicMMap(NULL
, 0));
1596 if (unlikely(Map
->validData()) == false)
1598 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1599 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1601 _error
->PushToStack();
1602 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1603 bool const newError
= _error
->PendingError();
1604 _error
->MergeWithStack();
1605 if (alloc
== 0 && newError
)
1607 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1609 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1612 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1613 MMap
**OutMap
, bool AllowMem
)
1614 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1615 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1618 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1620 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1621 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1623 // FIXME: deprecate the ignored AllowMem parameter
1624 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1626 std::vector
<pkgIndexFile
*> Files
;
1627 if (_system
->AddStatusFiles(Files
) == false)
1630 // Decide if we can write to the files..
1631 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1632 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1634 // ensure the cache directory exists
1635 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1637 string dir
= _config
->FindDir("Dir::Cache");
1638 size_t const len
= dir
.size();
1639 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1640 dir
= dir
.substr(0, len
- 5);
1641 if (CacheFile
.empty() == false)
1642 CreateDirectory(dir
, flNotFile(CacheFile
));
1643 if (SrcCacheFile
.empty() == false)
1644 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1647 if (Progress
!= NULL
)
1648 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1650 bool pkgcache_fine
= false;
1651 bool srcpkgcache_fine
= false;
1652 bool volatile_fine
= List
.GetVolatileFiles().empty();
1654 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1655 volatile_fine
? OutCache
: NULL
) == true)
1658 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1659 pkgcache_fine
= true;
1660 srcpkgcache_fine
= true;
1662 if (pkgcache_fine
== false)
1664 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1667 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1668 srcpkgcache_fine
= true;
1672 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1674 if (Progress
!= NULL
)
1675 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1679 bool Writeable
= false;
1680 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1682 if (CacheFile
.empty() == false)
1683 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1684 else if (SrcCacheFile
.empty() == false)
1685 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1688 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1691 // At this point we know we need to construct something, so get storage ready
1692 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1693 if (unlikely(Map
->validData()) == false)
1696 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1698 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1699 map_filesize_t CurrentSize
= 0;
1700 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1701 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1702 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1705 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1706 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1708 srcpkgcache_fine
= true;
1709 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1711 else if (srcpkgcache_fine
== false)
1714 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1715 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1717 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1718 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1719 Files
.end(),Files
.end()) == false)
1722 if (Writeable
== true && SrcCacheFile
.empty() == false)
1723 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1727 if (pkgcache_fine
== false)
1730 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1731 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1732 Files
.begin(), Files
.end()) == false)
1735 if (Writeable
== true && CacheFile
.empty() == false)
1736 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1741 std::clog
<< "Caches done. " << (volatile_fine
? "No volatile files, so we are done here." : "Now bring in the volatile files") << std::endl
;
1743 if (volatile_fine
== false)
1748 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1749 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1753 Files
= List
.GetVolatileFiles();
1754 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1755 Files
.begin(), Files
.end()) == false)
1759 if (OutMap
!= nullptr)
1760 *OutMap
= Map
.release();
1763 std::clog
<< "Everything is ready for shipping" << std::endl
;
1767 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1768 class APT_HIDDEN ScopedErrorMerge
{
1770 ScopedErrorMerge() { _error
->PushToStack(); }
1771 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1773 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1774 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1775 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1777 std::vector
<pkgIndexFile
*> Files
;
1778 if (_system
->AddStatusFiles(Files
) == false)
1781 ScopedErrorMerge sem
;
1782 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1783 if (unlikely(Map
->validData()) == false)
1785 map_filesize_t CurrentSize
= 0;
1786 map_filesize_t TotalSize
= 0;
1787 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1789 // Build the status cache
1790 if (Progress
!= NULL
)
1791 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1792 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1793 if (_error
->PendingError() == true)
1795 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1796 Files
.begin(), Files
.end()) == false)
1799 if (_error
->PendingError() == true)
1801 *OutMap
= Map
.release();
1806 // IsDuplicateDescription /*{{{*/
1807 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1808 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1810 // Descriptions in the same link-list have all the same md5
1811 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1813 for (; Desc
.end() == false; ++Desc
)
1814 if (Desc
.LanguageCode() == CurLang
)
1820 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1821 pkgCacheListParser::~pkgCacheListParser() {}