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/strutl.h>
22 #include <apt-pkg/sptr.h>
23 #include <apt-pkg/pkgsystem.h>
24 #include <apt-pkg/macros.h>
25 #include <apt-pkg/metaindex.h>
26 #include <apt-pkg/fileutl.h>
27 #include <apt-pkg/hashsum_template.h>
28 #include <apt-pkg/indexfile.h>
29 #include <apt-pkg/md5.h>
30 #include <apt-pkg/mmap.h>
31 #include <apt-pkg/pkgcache.h>
32 #include <apt-pkg/cacheiterators.h>
46 typedef std::vector
<pkgIndexFile
*>::iterator FileIterator
;
47 template <typename Iter
> std::vector
<Iter
*> pkgCacheGenerator::Dynamic
<Iter
>::toReMap
;
49 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
50 MD5SumValue
const &CurMd5
, std::string
const &CurLang
);
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
), FoundFileDeps(0), d(NULL
)
61 if (_error
->PendingError() == true)
66 // Setup the map interface..
67 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
68 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
71 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
74 *Cache
.HeaderP
= pkgCache::Header();
76 // make room for the hashtables for packages and groups
77 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
80 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
81 if (unlikely(idxVerSysName
== 0))
83 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
84 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
85 if (unlikely(idxArchitecture
== 0))
87 Cache
.HeaderP
->Architecture
= idxArchitecture
;
89 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
92 std::vector
<std::string
>::const_iterator a
= archs
.begin();
93 std::string list
= *a
;
94 for (++a
; a
!= archs
.end(); ++a
)
95 list
.append(",").append(*a
);
96 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
97 if (unlikely(idxArchitectures
== 0))
99 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
102 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
108 // Map directly from the existing file
110 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
111 if (Cache
.VS
!= _system
->VS
)
113 _error
->Error(_("Cache has an incompatible versioning system"));
118 Cache
.HeaderP
->Dirty
= true;
119 Map
.Sync(0,sizeof(pkgCache::Header
));
122 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
123 // ---------------------------------------------------------------------
124 /* We sync the data then unset the dirty flag in two steps so as to
125 advoid a problem during a crash */
126 pkgCacheGenerator::~pkgCacheGenerator()
128 if (_error
->PendingError() == true)
130 if (Map
.Sync() == false)
133 Cache
.HeaderP
->Dirty
= false;
134 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
135 Map
.Sync(0,sizeof(pkgCache::Header
));
138 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
139 if (oldMap
== newMap
)
142 if (_config
->FindB("Debug::pkgCacheGen", false))
143 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
147 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
148 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
150 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
151 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
152 (*i
)->ReMap(oldMap
, newMap
);
153 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
154 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
155 (*i
)->ReMap(oldMap
, newMap
);
156 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
157 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
158 (*i
)->ReMap(oldMap
, newMap
);
159 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
160 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
161 (*i
)->ReMap(oldMap
, newMap
);
162 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
163 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
164 (*i
)->ReMap(oldMap
, newMap
);
165 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
166 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
167 (*i
)->ReMap(oldMap
, newMap
);
168 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
169 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
170 (*i
)->ReMap(oldMap
, newMap
);
171 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
172 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
173 (*i
)->ReMap(oldMap
, newMap
);
175 // CacheGenerator::WriteStringInMap /*{{{*/
176 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
177 const unsigned long &Len
) {
178 void const * const oldMap
= Map
.Data();
179 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
181 ReMap(oldMap
, Map
.Data());
185 // CacheGenerator::WriteStringInMap /*{{{*/
186 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
187 void const * const oldMap
= Map
.Data();
188 map_stringitem_t
const index
= Map
.WriteString(String
);
190 ReMap(oldMap
, Map
.Data());
194 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
195 void const * const oldMap
= Map
.Data();
196 map_pointer_t
const index
= Map
.Allocate(size
);
198 ReMap(oldMap
, Map
.Data());
202 // CacheGenerator::MergeList - Merge the package list /*{{{*/
203 // ---------------------------------------------------------------------
204 /* This provides the generation of the entries in the cache. Each loop
205 goes through a single package record from the underlying parse engine. */
206 bool pkgCacheGenerator::MergeList(ListParser
&List
,
207 pkgCache::VerIterator
*OutVer
)
211 unsigned int Counter
= 0;
212 while (List
.Step() == true)
214 string
const PackageName
= List
.Package();
215 if (PackageName
.empty() == true)
219 if (Counter
% 100 == 0 && Progress
!= 0)
220 Progress
->Progress(List
.Offset());
222 string Arch
= List
.Architecture();
223 string
const Version
= List
.Version();
224 if (Version
.empty() == true && Arch
.empty() == true)
226 // package descriptions
227 if (MergeListGroup(List
, PackageName
) == false)
232 if (Arch
.empty() == true)
234 // use the pseudo arch 'none' for arch-less packages
236 /* We might built a SingleArchCache here, which we don't want to blow up
237 just for these :none packages to a proper MultiArchCache, so just ensure
238 that we have always a native package structure first for SingleArch */
239 pkgCache::PkgIterator NP
;
240 Dynamic
<pkgCache::PkgIterator
> DynPkg(NP
);
241 if (NewPackage(NP
, PackageName
, _config
->Find("APT::Architecture")) == false)
242 // TRANSLATOR: The first placeholder is a package name,
243 // the other two should be copied verbatim as they include debug info
244 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
245 PackageName
.c_str(), "NewPackage", 0);
248 // Get a pointer to the package structure
249 pkgCache::PkgIterator Pkg
;
250 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
251 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
252 // TRANSLATOR: The first placeholder is a package name,
253 // the other two should be copied verbatim as they include debug info
254 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
255 PackageName
.c_str(), "NewPackage", 1);
258 if (Version
.empty() == true)
260 if (MergeListPackage(List
, Pkg
) == false)
265 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
271 FoundFileDeps
|= List
.HasFileDeps();
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."));
289 FoundFileDeps
|= List
.HasFileDeps();
292 // CacheGenerator::MergeListGroup /*{{{*/
293 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
295 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
296 // a group has no data on it's own, only packages have it but these
297 // stanzas like this come from Translation- files to add descriptions,
298 // but without a version we don't need a description for it…
299 if (Grp
.end() == true)
301 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
303 pkgCache::PkgIterator Pkg
;
304 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
305 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
306 if (MergeListPackage(List
, Pkg
) == false)
312 // CacheGenerator::MergeListPackage /*{{{*/
313 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
315 // we first process the package, then the descriptions
316 // (for deb this package processing is in fact a no-op)
317 pkgCache::VerIterator
Ver(Cache
);
318 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
319 if (List
.UsePackage(Pkg
, Ver
) == false)
320 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
321 Pkg
.Name(), "UsePackage", 1);
323 // Find the right version to write the description
324 MD5SumValue CurMd5
= List
.Description_md5();
325 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
327 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
328 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
330 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
332 // a version can only have one md5 describing it
333 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
336 map_stringitem_t md5idx
= VerDesc
->md5sum
;
337 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
339 // don't add a new description if we have one for the given
341 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
344 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
347 // we can stop here as all "same" versions will share the description
354 // CacheGenerator::MergeListVersion /*{{{*/
355 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
356 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
358 pkgCache::VerIterator Ver
= Pkg
.VersionList();
359 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
360 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
361 void const * oldMap
= Map
.Data();
363 unsigned short const Hash
= List
.VersionHash();
364 if (Ver
.end() == false)
366 /* We know the list is sorted so we use that fact in the search.
367 Insertion of new versions is done with correct sorting */
369 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
371 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
372 // Version is higher as current version - insert here
375 // Versionstrings are equal - is hash also equal?
376 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
378 // proceed with the next till we have either the right
379 // or we found another version (which will be lower)
382 /* We already have a version for this item, record that we saw it */
383 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
385 if (List
.UsePackage(Pkg
,Ver
) == false)
386 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
387 Pkg
.Name(), "UsePackage", 2);
389 if (NewFileVer(Ver
,List
) == false)
390 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
391 Pkg
.Name(), "NewFileVer", 1);
393 // Read only a single record and return
405 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
406 if (verindex
== 0 && _error
->PendingError())
407 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
408 Pkg
.Name(), "NewVersion", 1);
410 if (oldMap
!= Map
.Data())
411 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
414 if (unlikely(List
.NewVersion(Ver
) == false))
415 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
416 Pkg
.Name(), "NewVersion", 2);
418 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
419 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
420 Pkg
.Name(), "UsePackage", 3);
422 if (unlikely(NewFileVer(Ver
,List
) == false))
423 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
424 Pkg
.Name(), "NewFileVer", 2);
426 pkgCache::GrpIterator Grp
= Pkg
.Group();
427 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
429 /* If it is the first version of this package we need to add implicit
430 Multi-Arch dependencies to all other package versions in the group now -
431 otherwise we just add them for this new version */
432 if (Pkg
.VersionList()->NextVer
== 0)
434 pkgCache::PkgIterator P
= Grp
.PackageList();
435 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
436 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
438 if (P
->ID
== Pkg
->ID
)
440 pkgCache::VerIterator V
= P
.VersionList();
441 Dynamic
<pkgCache::VerIterator
> DynV(V
);
442 for (; V
.end() != true; ++V
)
443 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
444 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
445 Pkg
.Name(), "AddImplicitDepends", 1);
447 /* :none packages are packages without an architecture. They are forbidden by
448 debian-policy, so usually they will only be in (old) dpkg status files -
449 and dpkg will complain about them - and are pretty rare. We therefore do
450 usually not create conflicts while the parent is created, but only if a :none
451 package (= the target) appears. This creates incorrect dependencies on :none
452 for architecture-specific dependencies on the package we copy from, but we
453 will ignore this bug as architecture-specific dependencies are only allowed
454 in jessie and until then the :none packages should be extinct (hopefully).
455 In other words: This should work long enough to allow graceful removal of
456 these packages, it is not supposed to allow users to keep using them … */
457 if (strcmp(Pkg
.Arch(), "none") == 0)
459 pkgCache::PkgIterator M
= Grp
.FindPreferredPkg();
460 if (M
.end() == false && Pkg
!= M
)
462 pkgCache::DepIterator D
= M
.RevDependsList();
463 Dynamic
<pkgCache::DepIterator
> DynD(D
);
464 for (; D
.end() == false; ++D
)
466 if ((D
->Type
!= pkgCache::Dep::Conflicts
&&
467 D
->Type
!= pkgCache::Dep::DpkgBreaks
&&
468 D
->Type
!= pkgCache::Dep::Replaces
) ||
469 D
.ParentPkg().Group() == Grp
)
472 map_pointer_t
*OldDepLast
= NULL
;
473 pkgCache::VerIterator ConVersion
= D
.ParentVer();
474 Dynamic
<pkgCache::VerIterator
> DynV(ConVersion
);
475 // duplicate the Conflicts/Breaks/Replaces for :none arch
476 NewDepends(Pkg
, ConVersion
, D
->Version
,
477 D
->CompareOp
, D
->Type
, OldDepLast
);
482 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
483 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
484 Pkg
.Name(), "AddImplicitDepends", 2);
486 // Read only a single record and return
493 /* Record the Description(s) based on their master md5sum */
494 MD5SumValue CurMd5
= List
.Description_md5();
495 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
498 /* Before we add a new description we first search in the group for
499 a version with a description of the same MD5 - if so we reuse this
500 description group instead of creating our own for this version */
501 for (pkgCache::PkgIterator P
= Grp
.PackageList();
502 P
.end() == false; P
= Grp
.NextPkg(P
))
504 for (pkgCache::VerIterator V
= P
.VersionList();
505 V
.end() == false; ++V
)
507 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
509 Ver
->DescriptionList
= V
->DescriptionList
;
513 // We haven't found reusable descriptions, so add the first description(s)
514 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
515 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
516 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
517 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
522 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
524 pkgCache::DescIterator Desc
;
525 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
527 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
528 if (unlikely(descindex
== 0 && _error
->PendingError()))
529 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
530 Ver
.ParentPkg().Name(), "NewDescription", 1);
532 md5idx
= Desc
->md5sum
;
533 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
535 // we add at the end, so that the start is constant as we need
536 // that to be able to efficiently share these lists
537 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
538 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
539 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
540 *LastNextDesc
= descindex
;
542 if (NewFileDesc(Desc
,List
) == false)
543 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
544 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
550 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
551 // ---------------------------------------------------------------------
552 /* If we found any file depends while parsing the main list we need to
553 resolve them. Since it is undesired to load the entire list of files
554 into the cache as virtual packages we do a two stage effort. MergeList
555 identifies the file depends and this creates Provdies for them by
556 re-parsing all the indexs. */
557 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
561 unsigned int Counter
= 0;
562 while (List
.Step() == true)
564 string PackageName
= List
.Package();
565 if (PackageName
.empty() == true)
567 string Version
= List
.Version();
568 if (Version
.empty() == true)
571 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
572 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
573 if (Pkg
.end() == true)
574 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
575 PackageName
.c_str(), "FindPkg", 1);
577 if (Counter
% 100 == 0 && Progress
!= 0)
578 Progress
->Progress(List
.Offset());
580 unsigned short Hash
= List
.VersionHash();
581 pkgCache::VerIterator Ver
= Pkg
.VersionList();
582 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
583 for (; Ver
.end() == false; ++Ver
)
585 if (List
.SameVersion(Hash
, Ver
) == true && Version
== Ver
.VerStr())
587 if (List
.CollectFileProvides(Cache
,Ver
) == false)
588 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
589 PackageName
.c_str(), "CollectFileProvides", 1);
594 if (Ver
.end() == true)
595 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
601 // CacheGenerator::NewGroup - Add a new group /*{{{*/
602 // ---------------------------------------------------------------------
603 /* This creates a new group structure and adds it to the hash table */
604 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
606 Grp
= Cache
.FindGrp(Name
);
607 if (Grp
.end() == false)
611 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
612 if (unlikely(Group
== 0))
615 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
616 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
617 if (unlikely(idxName
== 0))
621 // Insert it into the hash table
622 unsigned long const Hash
= Cache
.Hash(Name
);
623 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
624 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
625 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
626 Grp
->Next
= *insertAt
;
629 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
633 // CacheGenerator::NewPackage - Add a new package /*{{{*/
634 // ---------------------------------------------------------------------
635 /* This creates a new package structure and adds it to the hash table */
636 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
637 const string
&Arch
) {
638 pkgCache::GrpIterator Grp
;
639 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
640 if (unlikely(NewGroup(Grp
, Name
) == false))
643 Pkg
= Grp
.FindPkg(Arch
);
644 if (Pkg
.end() == false)
648 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
649 if (unlikely(Package
== 0))
651 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
653 // Set the name, arch and the ID
654 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
655 Pkg
->Group
= Grp
.Index();
656 // all is mapped to the native architecture
657 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
658 if (unlikely(idxArch
== 0))
661 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
663 // Insert the package into our package list
664 if (Grp
->FirstPackage
== 0) // the group is new
666 Grp
->FirstPackage
= Package
;
667 // Insert it into the hash table
668 map_id_t
const Hash
= Cache
.Hash(Name
);
669 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
670 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
671 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
672 Pkg
->NextPackage
= *insertAt
;
675 else // Group the Packages together
677 // but first get implicit provides done
678 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
680 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
681 if (M
.end() == false)
682 for (pkgCache::PrvIterator Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
684 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
686 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
687 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
688 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
689 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
690 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
694 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
695 for (pkgCache::VerIterator Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
696 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
697 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
700 // and negative dependencies, don't forget negative dependencies
702 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
703 if (M
.end() == false)
704 for (pkgCache::DepIterator Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
706 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
708 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
709 Dep
->Type
!= pkgCache::Dep::Replaces
)
711 pkgCache::VerIterator Ver
= Dep
.ParentVer();
712 map_pointer_t
* unused
= NULL
;
713 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
718 // this package is the new last package
719 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
720 Pkg
->NextPackage
= LastPkg
->NextPackage
;
721 LastPkg
->NextPackage
= Package
;
723 Grp
->LastPackage
= Package
;
727 // CacheGenerator::AddImplicitDepends /*{{{*/
728 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
729 pkgCache::PkgIterator
&P
,
730 pkgCache::VerIterator
&V
)
732 // copy P.Arch() into a string here as a cache remap
733 // in NewDepends() later may alter the pointer location
734 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
735 map_pointer_t
*OldDepLast
= NULL
;
736 /* MultiArch handling introduces a lot of implicit Dependencies:
737 - MultiArch: same → Co-Installable if they have the same version
738 - All others conflict with all other group members */
739 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
740 pkgCache::PkgIterator D
= G
.PackageList();
741 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
742 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
743 for (; D
.end() != true; D
= G
.NextPkg(D
))
745 if (Arch
== D
.Arch() || D
->VersionList
== 0)
747 /* We allow only one installed arch at the time
748 per group, therefore each group member conflicts
749 with all other group members */
750 if (coInstall
== true)
752 // Replaces: ${self}:other ( << ${binary:Version})
753 NewDepends(D
, V
, VerStrIdx
,
754 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
756 // Breaks: ${self}:other (!= ${binary:Version})
757 NewDepends(D
, V
, VerStrIdx
,
758 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
761 // Conflicts: ${self}:other
763 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
769 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
770 pkgCache::PkgIterator
&D
)
772 /* MultiArch handling introduces a lot of implicit Dependencies:
773 - MultiArch: same → Co-Installable if they have the same version
774 - All others conflict with all other group members */
775 map_pointer_t
*OldDepLast
= NULL
;
776 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
777 if (coInstall
== true)
779 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
780 // Replaces: ${self}:other ( << ${binary:Version})
781 NewDepends(D
, V
, VerStrIdx
,
782 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
784 // Breaks: ${self}:other (!= ${binary:Version})
785 NewDepends(D
, V
, VerStrIdx
,
786 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
789 // Conflicts: ${self}:other
791 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
798 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
799 // ---------------------------------------------------------------------
801 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
804 if (CurrentFile
== 0)
808 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
812 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
813 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
815 // Link it to the end of the list
816 map_pointer_t
*Last
= &Ver
->FileList
;
817 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
819 VF
->NextFile
= *Last
;
822 VF
->Offset
= List
.Offset();
823 VF
->Size
= List
.Size();
824 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
825 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
826 Cache
.HeaderP
->VerFileCount
++;
831 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
832 // ---------------------------------------------------------------------
833 /* This puts a version structure in the linked list */
834 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
835 const string
&VerStr
,
836 map_pointer_t
const ParentPkg
,
837 unsigned short const Hash
,
838 map_pointer_t
const Next
)
841 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
846 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
847 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
849 Ver
->ParentPkg
= ParentPkg
;
851 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
853 // try to find the version string in the group for reuse
854 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
855 pkgCache::GrpIterator Grp
= Pkg
.Group();
856 if (Pkg
.end() == false && Grp
.end() == false)
858 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
862 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
864 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
867 Ver
->VerStr
= V
->VerStr
;
875 // haven't found the version string, so create
876 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
877 if (unlikely(idxVerStr
== 0))
879 Ver
->VerStr
= idxVerStr
;
883 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
884 // ---------------------------------------------------------------------
886 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
889 if (CurrentFile
== 0)
893 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
897 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
898 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
900 // Link it to the end of the list
901 map_pointer_t
*Last
= &Desc
->FileList
;
902 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
905 DF
->NextFile
= *Last
;
908 DF
->Offset
= List
.Offset();
909 DF
->Size
= List
.Size();
910 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
911 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
912 Cache
.HeaderP
->DescFileCount
++;
917 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
918 // ---------------------------------------------------------------------
919 /* This puts a description structure in the linked list */
920 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
922 const MD5SumValue
&md5sum
,
923 map_stringitem_t
const idxmd5str
)
926 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
927 if (Description
== 0)
931 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
932 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
933 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
934 if (unlikely(idxlanguage_code
== 0))
936 Desc
->language_code
= idxlanguage_code
;
939 Desc
->md5sum
= idxmd5str
;
942 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
943 if (unlikely(idxmd5sum
== 0))
945 Desc
->md5sum
= idxmd5sum
;
951 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
952 // ---------------------------------------------------------------------
953 /* This creates a dependency element in the tree. It is linked to the
954 version and to the package that it is pointing to. */
955 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
956 pkgCache::VerIterator
&Ver
,
957 map_pointer_t
const Version
,
960 map_pointer_t
* &OldDepLast
)
962 void const * const oldMap
= Map
.Data();
964 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
965 if (unlikely(Dependency
== 0))
968 bool isDuplicate
= false;
969 map_pointer_t DependencyData
= 0;
970 map_pointer_t PreviousData
= 0;
971 if (Pkg
->RevDepends
!= 0)
973 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
974 DependencyData
= L
->DependencyData
;
976 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
977 if (Version
> D
->Version
)
979 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
984 PreviousData
= DependencyData
;
985 DependencyData
= D
->NextData
;
986 } while (DependencyData
!= 0);
989 if (isDuplicate
== false)
991 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
992 if (unlikely(DependencyData
== 0))
996 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
997 Link
->ParentVer
= Ver
.Index();
998 Link
->DependencyData
= DependencyData
;
999 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
1001 pkgCache::DepIterator
Dep(Cache
, Link
);
1002 if (isDuplicate
== false)
1005 Dep
->CompareOp
= Op
;
1006 Dep
->Version
= Version
;
1007 Dep
->Package
= Pkg
.Index();
1008 ++Cache
.HeaderP
->DependsDataCount
;
1009 if (PreviousData
!= 0)
1011 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
1012 Dep
->NextData
= D
->NextData
;
1013 D
->NextData
= DependencyData
;
1015 else if (Pkg
->RevDepends
!= 0)
1017 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
1018 Dep
->NextData
= D
->DependencyData
;
1022 if (isDuplicate
== true || PreviousData
!= 0)
1024 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
1025 Link
->NextRevDepends
= L
->NextRevDepends
;
1026 L
->NextRevDepends
= Dependency
;
1030 Link
->NextRevDepends
= Pkg
->RevDepends
;
1031 Pkg
->RevDepends
= Dependency
;
1035 // Do we know where to link the Dependency to?
1036 if (OldDepLast
== NULL
)
1038 OldDepLast
= &Ver
->DependsList
;
1039 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
1040 OldDepLast
= &D
->NextDepends
;
1041 } else if (oldMap
!= Map
.Data())
1042 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
1044 Dep
->NextDepends
= *OldDepLast
;
1045 *OldDepLast
= Dependency
;
1046 OldDepLast
= &Dep
->NextDepends
;
1050 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1051 // ---------------------------------------------------------------------
1052 /* This creates a Group and the Package to link this dependency to if
1053 needed and handles also the caching of the old endpoint */
1054 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1055 const string
&PackageName
,
1057 const string
&Version
,
1061 pkgCache::GrpIterator Grp
;
1062 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1063 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1066 // Is it a file dependency?
1067 if (unlikely(PackageName
[0] == '/'))
1068 FoundFileDeps
= true;
1070 map_stringitem_t idxVersion
= 0;
1071 if (Version
.empty() == false)
1073 int const CmpOp
= Op
& 0x0F;
1074 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1075 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
1076 idxVersion
= Ver
->VerStr
;
1078 if (idxVersion
== 0)
1080 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1081 if (unlikely(idxVersion
== 0))
1086 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1087 Type
== pkgCache::Dep::Conflicts
||
1088 Type
== pkgCache::Dep::Replaces
);
1090 pkgCache::PkgIterator Pkg
;
1091 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1092 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1094 // Locate the target package
1095 Pkg
= Grp
.FindPkg(Arch
);
1096 if (Pkg
.end() == true) {
1097 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1101 /* Caching the old end point speeds up generation substantially */
1102 if (OldDepVer
!= Ver
) {
1107 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1111 /* Caching the old end point speeds up generation substantially */
1112 if (OldDepVer
!= Ver
) {
1117 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1119 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1126 // ListParser::NewProvides - Create a Provides element /*{{{*/
1127 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1128 const string
&PkgName
,
1129 const string
&PkgArch
,
1130 const string
&Version
,
1131 uint8_t const Flags
)
1133 pkgCache
const &Cache
= Owner
->Cache
;
1135 // We do not add self referencing provides
1136 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1137 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1140 // Locate the target package
1141 pkgCache::PkgIterator Pkg
;
1142 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1143 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1146 map_stringitem_t idxProvideVersion
= 0;
1147 if (Version
.empty() == false) {
1148 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1149 if (unlikely(idxProvideVersion
== 0))
1152 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1154 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1155 pkgCache::PkgIterator
&Pkg
,
1156 map_pointer_t
const ProvideVersion
,
1157 uint8_t const Flags
)
1160 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1161 if (unlikely(Provides
== 0))
1163 ++Cache
.HeaderP
->ProvidesCount
;
1166 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1167 Prv
->Version
= Ver
.Index();
1168 Prv
->ProvideVersion
= ProvideVersion
;
1170 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1171 Ver
->ProvidesList
= Prv
.Index();
1173 // Link it to the package
1174 Prv
->ParentPkg
= Pkg
.Index();
1175 Prv
->NextProvides
= Pkg
->ProvidesList
;
1176 Pkg
->ProvidesList
= Prv
.Index();
1180 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1181 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, string
const &Package
,
1182 string
const &Version
, uint8_t const Flags
) {
1183 pkgCache
&Cache
= Owner
->Cache
;
1184 pkgCache::GrpIterator
const Grp
= Cache
.FindGrp(Package
);
1185 if (Grp
.end() == true)
1186 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1189 map_stringitem_t idxProvideVersion
= 0;
1190 if (Version
.empty() == false) {
1191 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1192 if (unlikely(idxProvideVersion
== 0))
1196 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1197 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1198 pkgCache::PkgIterator
const OwnerPkg
= Ver
.ParentPkg();
1199 for (pkgCache::PkgIterator Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1201 if (isImplicit
&& OwnerPkg
== Pkg
)
1203 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1205 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1212 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1213 pkgCache::VerIterator
const &Ver
)
1215 return Hash
== Ver
->Hash
;
1218 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1219 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1220 unsigned long Flags
)
1222 if (File
.empty() && Site
.empty())
1224 CurrentRlsFile
= NULL
;
1228 // Get some space for the structure
1229 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1230 if (unlikely(idxFile
== 0))
1232 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1235 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1236 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1237 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1239 CurrentRlsFile
->FileName
= idxFileName
;
1240 CurrentRlsFile
->Site
= idxSite
;
1241 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1242 CurrentRlsFile
->Flags
= Flags
;
1243 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1245 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1246 Cache
.HeaderP
->ReleaseFileCount
++;
1251 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1252 // ---------------------------------------------------------------------
1253 /* This is used to select which file is to be associated with all newly
1254 added versions. The caller is responsible for setting the IMS fields. */
1255 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1256 pkgIndexFile
const &Index
,
1257 std::string
const &Architecture
,
1258 std::string
const &Component
,
1259 unsigned long const Flags
)
1261 // Get some space for the structure
1262 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1263 if (unlikely(idxFile
== 0))
1265 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1268 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1269 if (unlikely(idxFileName
== 0))
1271 CurrentFile
->FileName
= idxFileName
;
1272 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1273 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1274 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1275 if (unlikely(idxIndexType
== 0))
1277 CurrentFile
->IndexType
= idxIndexType
;
1278 if (Architecture
.empty())
1279 CurrentFile
->Architecture
= 0;
1282 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1283 if (unlikely(arch
== 0))
1285 CurrentFile
->Architecture
= arch
;
1287 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1288 if (unlikely(component
== 0))
1290 CurrentFile
->Component
= component
;
1291 CurrentFile
->Flags
= Flags
;
1292 if (CurrentRlsFile
!= NULL
)
1293 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1295 CurrentFile
->Release
= 0;
1297 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1298 Cache
.HeaderP
->PackageFileCount
++;
1301 Progress
->SubProgress(Index
.Size());
1305 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1306 // ---------------------------------------------------------------------
1307 /* This is used to create handles to strings. Given the same text it
1308 always returns the same number */
1309 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1312 std::string
const key(S
, Size
);
1314 std::map
<std::string
,map_stringitem_t
> * strings
;
1316 case MIXED
: strings
= &strMixed
; break;
1317 case PKGNAME
: strings
= &strPkgNames
; break;
1318 case VERSIONNUMBER
: strings
= &strVersions
; break;
1319 case SECTION
: strings
= &strSections
; break;
1320 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1323 std::map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1324 if (item
!= strings
->end())
1325 return item
->second
;
1327 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1328 strings
->insert(std::make_pair(key
, idxString
));
1332 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1333 // ---------------------------------------------------------------------
1334 /* This just verifies that each file in the list of index files exists,
1335 has matching attributes with the cache and the cache does not have
1337 static bool CheckValidity(const string
&CacheFile
,
1338 pkgSourceList
&List
,
1339 FileIterator
const Start
,
1340 FileIterator
const End
,
1343 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1344 // No file, certainly invalid
1345 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1348 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1352 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1355 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1360 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1361 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
1362 pkgCache
Cache(Map
);
1363 if (_error
->PendingError() == true || Map
->Size() == 0)
1366 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1371 SPtrArray
<bool> RlsVisited
= new bool[Cache
.HeaderP
->ReleaseFileCount
];
1372 memset(RlsVisited
,0,sizeof(*RlsVisited
)*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 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
1407 memset(Visited
,0,sizeof(*Visited
)*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();
1453 *OutMap
= Map
.UnGuard();
1457 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1458 // ---------------------------------------------------------------------
1459 /* Size is kind of an abstract notion that is only used for the progress
1461 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1463 map_filesize_t TotalSize
= 0;
1466 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1468 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1469 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1470 if ((*j
)->HasPackages() == true)
1471 TotalSize
+= (*j
)->Size();
1475 for (; Start
< End
; ++Start
)
1477 if ((*Start
)->HasPackages() == false)
1479 TotalSize
+= (*Start
)->Size();
1484 // BuildCache - Merge the list of index files into the cache /*{{{*/
1485 static bool BuildCache(pkgCacheGenerator
&Gen
,
1486 OpProgress
* const Progress
,
1487 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1488 pkgSourceList
const * const List
,
1489 FileIterator
const Start
, FileIterator
const End
)
1491 std::vector
<pkgIndexFile
*> Files
;
1492 bool const HasFileDeps
= Gen
.HasFileDeps();
1493 bool mergeFailure
= false;
1495 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1499 if (I
->HasPackages() == false || mergeFailure
)
1502 if (I
->Exists() == false)
1505 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1507 _error
->Warning("Duplicate sources.list entry %s",
1508 I
->Describe().c_str());
1512 map_filesize_t
const Size
= I
->Size();
1513 if (Progress
!= NULL
)
1514 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1515 CurrentSize
+= Size
;
1517 if (I
->Merge(Gen
,Progress
) == false)
1518 mergeFailure
= true;
1523 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1525 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1527 _error
->Warning("Duplicate sources.list entry %s",
1528 (*i
)->Describe().c_str());
1532 if ((*i
)->Merge(Gen
, Progress
) == false)
1535 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1536 if (Indexes
!= NULL
)
1537 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1545 Gen
.SelectReleaseFile("", "");
1546 std::for_each(Start
, End
, indexFileMerge
);
1551 if (HasFileDeps
== true)
1553 if (Progress
!= NULL
)
1555 TotalSize
= ComputeSize(List
, Start
, End
);
1557 for (std::vector
<pkgIndexFile
*>::const_iterator I
= Files
.begin(); I
!= Files
.end(); ++I
)
1559 map_filesize_t Size
= (*I
)->Size();
1560 if (Progress
!= NULL
)
1561 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
1562 CurrentSize
+= Size
;
1563 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
1571 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1572 // ---------------------------------------------------------------------
1573 /* This makes sure that the status cache (the cache that has all
1574 index files from the sources list and all local ones) is ready
1575 to be mmaped. If OutMap is not zero then a MMap object representing
1576 the cache will be stored there. This is pretty much mandetory if you
1577 are using AllowMem. AllowMem lets the function be run as non-root
1578 where it builds the cache 'fast' into a memory buffer. */
1579 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1581 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1582 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1583 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1584 Flags
|= MMap::Moveable
;
1585 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1586 Flags
|= MMap::Fallback
;
1588 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1590 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1592 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1593 std::string
const &FileName
)
1595 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1596 if (_error
->PendingError() == true)
1599 fchmod(SCacheF
.Fd(),0644);
1601 // Write out the main data
1602 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1603 return _error
->Error(_("IO Error saving source cache"));
1606 // Write out the proper header
1607 Gen
->GetCache().HeaderP
->Dirty
= false;
1608 if (SCacheF
.Seek(0) == false ||
1609 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1610 return _error
->Error(_("IO Error saving source cache"));
1611 Gen
->GetCache().HeaderP
->Dirty
= true;
1615 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1616 SPtr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1618 Map
= CreateDynamicMMap(NULL
, 0);
1619 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1620 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1621 if ((alloc
== 0 && _error
->PendingError())
1622 || CacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1623 CacheF
.Size()) == false)
1625 Gen
.reset(new pkgCacheGenerator(Map
.Get(),Progress
));
1628 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1629 MMap
**OutMap
, bool AllowMem
)
1630 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1631 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1632 MMap
**OutMap
,bool AllowMem
)
1634 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1636 std::vector
<pkgIndexFile
*> Files
;
1637 if (_system
->AddStatusFiles(Files
) == false)
1640 // Decide if we can write to the files..
1641 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1642 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1644 // ensure the cache directory exists
1645 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1647 string dir
= _config
->FindDir("Dir::Cache");
1648 size_t const len
= dir
.size();
1649 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1650 dir
= dir
.substr(0, len
- 5);
1651 if (CacheFile
.empty() == false)
1652 CreateDirectory(dir
, flNotFile(CacheFile
));
1653 if (SrcCacheFile
.empty() == false)
1654 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1657 if (Progress
!= NULL
)
1658 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1660 bool pkgcache_fine
= false;
1661 bool srcpkgcache_fine
= false;
1662 bool volatile_fine
= List
.GetVolatileFiles().empty();
1664 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
) == true)
1667 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1668 pkgcache_fine
= true;
1669 srcpkgcache_fine
= true;
1671 if (pkgcache_fine
== false)
1673 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1676 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1677 srcpkgcache_fine
= true;
1681 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1683 if (Progress
!= NULL
)
1684 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1688 bool Writeable
= false;
1689 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1691 if (CacheFile
.empty() == false)
1692 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1693 else if (SrcCacheFile
.empty() == false)
1694 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1697 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1699 if (Writeable
== false && AllowMem
== false)
1701 if (CacheFile
.empty() == false)
1702 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1703 else if (SrcCacheFile
.empty() == false)
1704 return _error
->Error(_("Unable to write to %s"),flNotFile(SrcCacheFile
).c_str());
1706 return _error
->Error("Unable to create caches as file usage is disabled, but memory not allowed either!");
1710 // At this point we know we need to construct something, so get storage ready
1711 SPtr
<DynamicMMap
> Map
= CreateDynamicMMap(NULL
, 0);
1713 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1715 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1716 map_filesize_t CurrentSize
= 0;
1717 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1718 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1719 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1722 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1723 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1725 srcpkgcache_fine
= true;
1726 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1728 else if (srcpkgcache_fine
== false)
1731 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1732 Gen
.reset(new pkgCacheGenerator(Map
.Get(),Progress
));
1734 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1735 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1736 Files
.end(),Files
.end()) == false)
1739 if (Writeable
== true && SrcCacheFile
.empty() == false)
1740 if (writeBackMMapToFile(Gen
.get(), Map
.Get(), SrcCacheFile
) == false)
1744 if (pkgcache_fine
== false)
1747 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1748 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1749 Files
.begin(), Files
.end()) == false)
1752 if (Writeable
== true && CacheFile
.empty() == false)
1753 if (writeBackMMapToFile(Gen
.get(), Map
.Get(), CacheFile
) == false)
1758 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1760 if (volatile_fine
== false)
1765 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1766 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1770 Files
= List
.GetVolatileFiles();
1771 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1772 Files
.begin(), Files
.end()) == false)
1776 if (OutMap
!= nullptr)
1777 *OutMap
= Map
.UnGuard();
1780 std::clog
<< "Everything is ready for shipping" << std::endl
;
1784 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1785 // ---------------------------------------------------------------------
1787 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1788 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1789 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1791 std::vector
<pkgIndexFile
*> Files
;
1792 if (_system
->AddStatusFiles(Files
) == false)
1795 SPtr
<DynamicMMap
> Map
= CreateDynamicMMap(NULL
, 0);
1796 map_filesize_t CurrentSize
= 0;
1797 map_filesize_t TotalSize
= 0;
1799 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1801 // Build the status cache
1802 if (Progress
!= NULL
)
1803 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1804 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1805 if (_error
->PendingError() == true)
1807 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1808 Files
.begin(), Files
.end()) == false)
1811 if (_error
->PendingError() == true)
1813 *OutMap
= Map
.UnGuard();
1818 // IsDuplicateDescription /*{{{*/
1819 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1820 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1822 // Descriptions in the same link-list have all the same md5
1823 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1825 for (; Desc
.end() == false; ++Desc
)
1826 if (Desc
.LanguageCode() == CurLang
)
1831 // CacheGenerator::FinishCache /*{{{*/
1832 bool pkgCacheGenerator::FinishCache(OpProgress
* /*Progress*/)
1838 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), FoundFileDeps(false), d(NULL
) {}
1839 pkgCacheListParser::~pkgCacheListParser() {}