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
);
53 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
54 // ---------------------------------------------------------------------
55 /* We set the dirty flag and make sure that is written to the disk */
56 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
57 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
58 CurrentRlsFile(NULL
), CurrentFile(NULL
), d(NULL
)
60 if (_error
->PendingError() == true)
65 // Setup the map interface..
66 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
67 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
70 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
73 *Cache
.HeaderP
= pkgCache::Header();
75 // make room for the hashtables for packages and groups
76 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
79 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
80 if (unlikely(idxVerSysName
== 0))
82 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
83 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
84 if (unlikely(idxArchitecture
== 0))
86 Cache
.HeaderP
->Architecture
= idxArchitecture
;
88 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
91 std::vector
<std::string
>::const_iterator a
= archs
.begin();
92 std::string list
= *a
;
93 for (++a
; a
!= archs
.end(); ++a
)
94 list
.append(",").append(*a
);
95 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
96 if (unlikely(idxArchitectures
== 0))
98 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
101 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
107 // Map directly from the existing file
109 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
110 if (Cache
.VS
!= _system
->VS
)
112 _error
->Error(_("Cache has an incompatible versioning system"));
117 Cache
.HeaderP
->Dirty
= true;
118 Map
.Sync(0,sizeof(pkgCache::Header
));
121 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
122 // ---------------------------------------------------------------------
123 /* We sync the data then unset the dirty flag in two steps so as to
124 advoid a problem during a crash */
125 pkgCacheGenerator::~pkgCacheGenerator()
127 if (_error
->PendingError() == true)
129 if (Map
.Sync() == false)
132 Cache
.HeaderP
->Dirty
= false;
133 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
134 Map
.Sync(0,sizeof(pkgCache::Header
));
137 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
138 if (oldMap
== newMap
)
141 if (_config
->FindB("Debug::pkgCacheGen", false))
142 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
146 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
147 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
149 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
150 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
151 (*i
)->ReMap(oldMap
, newMap
);
152 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
153 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
154 (*i
)->ReMap(oldMap
, newMap
);
155 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
156 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
157 (*i
)->ReMap(oldMap
, newMap
);
158 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
159 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
160 (*i
)->ReMap(oldMap
, newMap
);
161 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
162 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
163 (*i
)->ReMap(oldMap
, newMap
);
164 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
165 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
166 (*i
)->ReMap(oldMap
, newMap
);
167 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
168 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
169 (*i
)->ReMap(oldMap
, newMap
);
170 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
171 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
172 (*i
)->ReMap(oldMap
, newMap
);
174 // CacheGenerator::WriteStringInMap /*{{{*/
175 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
176 const unsigned long &Len
) {
177 void const * const oldMap
= Map
.Data();
178 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
180 ReMap(oldMap
, Map
.Data());
184 // CacheGenerator::WriteStringInMap /*{{{*/
185 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
186 void const * const oldMap
= Map
.Data();
187 map_stringitem_t
const index
= Map
.WriteString(String
);
189 ReMap(oldMap
, Map
.Data());
193 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
194 void const * const oldMap
= Map
.Data();
195 map_pointer_t
const index
= Map
.Allocate(size
);
197 ReMap(oldMap
, Map
.Data());
201 // CacheGenerator::MergeList - Merge the package list /*{{{*/
202 // ---------------------------------------------------------------------
203 /* This provides the generation of the entries in the cache. Each loop
204 goes through a single package record from the underlying parse engine. */
205 bool pkgCacheGenerator::MergeList(ListParser
&List
,
206 pkgCache::VerIterator
*OutVer
)
210 unsigned int Counter
= 0;
211 while (List
.Step() == true)
213 string
const PackageName
= List
.Package();
214 if (PackageName
.empty() == true)
218 if (Counter
% 100 == 0 && Progress
!= 0)
219 Progress
->Progress(List
.Offset());
221 string Arch
= List
.Architecture();
222 string
const Version
= List
.Version();
223 if (Version
.empty() == true && Arch
.empty() == true)
225 // package descriptions
226 if (MergeListGroup(List
, PackageName
) == false)
231 // Get a pointer to the package structure
232 pkgCache::PkgIterator Pkg
;
233 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
234 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
235 // TRANSLATOR: The first placeholder is a package name,
236 // the other two should be copied verbatim as they include debug info
237 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
238 PackageName
.c_str(), "NewPackage", 1);
241 if (Version
.empty() == true)
243 if (MergeListPackage(List
, Pkg
) == false)
248 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
256 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
257 return _error
->Error(_("Wow, you exceeded the number of package "
258 "names this APT is capable of."));
259 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
260 return _error
->Error(_("Wow, you exceeded the number of versions "
261 "this APT is capable of."));
262 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
263 return _error
->Error(_("Wow, you exceeded the number of descriptions "
264 "this APT is capable of."));
265 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
266 return _error
->Error(_("Wow, you exceeded the number of dependencies "
267 "this APT is capable of."));
271 // CacheGenerator::MergeListGroup /*{{{*/
272 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
274 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
275 // a group has no data on it's own, only packages have it but these
276 // stanzas like this come from Translation- files to add descriptions,
277 // but without a version we don't need a description for it…
278 if (Grp
.end() == true)
280 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
282 pkgCache::PkgIterator Pkg
;
283 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
284 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
285 if (MergeListPackage(List
, Pkg
) == false)
291 // CacheGenerator::MergeListPackage /*{{{*/
292 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
294 // we first process the package, then the descriptions
295 // (for deb this package processing is in fact a no-op)
296 pkgCache::VerIterator
Ver(Cache
);
297 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
298 if (List
.UsePackage(Pkg
, Ver
) == false)
299 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
300 Pkg
.Name(), "UsePackage", 1);
302 // Find the right version to write the description
303 MD5SumValue CurMd5
= List
.Description_md5();
304 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
306 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
307 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
309 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
311 // a version can only have one md5 describing it
312 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
315 map_stringitem_t md5idx
= VerDesc
->md5sum
;
316 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
318 // don't add a new description if we have one for the given
320 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
323 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
326 // we can stop here as all "same" versions will share the description
333 // CacheGenerator::MergeListVersion /*{{{*/
334 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
335 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
337 pkgCache::VerIterator Ver
= Pkg
.VersionList();
338 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
339 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
340 void const * oldMap
= Map
.Data();
342 unsigned short const Hash
= List
.VersionHash();
343 if (Ver
.end() == false)
345 /* We know the list is sorted so we use that fact in the search.
346 Insertion of new versions is done with correct sorting */
348 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
350 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
351 // Version is higher as current version - insert here
354 // Versionstrings are equal - is hash also equal?
355 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
357 // proceed with the next till we have either the right
358 // or we found another version (which will be lower)
361 /* We already have a version for this item, record that we saw it */
362 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
364 if (List
.UsePackage(Pkg
,Ver
) == false)
365 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
366 Pkg
.Name(), "UsePackage", 2);
368 if (NewFileVer(Ver
,List
) == false)
369 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
370 Pkg
.Name(), "NewFileVer", 1);
372 // Read only a single record and return
384 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
385 if (verindex
== 0 && _error
->PendingError())
386 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
387 Pkg
.Name(), "NewVersion", 1);
389 if (oldMap
!= Map
.Data())
390 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
393 if (unlikely(List
.NewVersion(Ver
) == false))
394 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
395 Pkg
.Name(), "NewVersion", 2);
397 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
398 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
399 Pkg
.Name(), "UsePackage", 3);
401 if (unlikely(NewFileVer(Ver
,List
) == false))
402 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
403 Pkg
.Name(), "NewFileVer", 2);
405 pkgCache::GrpIterator Grp
= Pkg
.Group();
406 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
408 /* If it is the first version of this package we need to add implicit
409 Multi-Arch dependencies to all other package versions in the group now -
410 otherwise we just add them for this new version */
411 if (Pkg
.VersionList()->NextVer
== 0)
413 pkgCache::PkgIterator P
= Grp
.PackageList();
414 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
415 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
417 if (P
->ID
== Pkg
->ID
)
419 pkgCache::VerIterator V
= P
.VersionList();
420 Dynamic
<pkgCache::VerIterator
> DynV(V
);
421 for (; V
.end() != true; ++V
)
422 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
423 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
424 Pkg
.Name(), "AddImplicitDepends", 1);
427 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
428 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
429 Pkg
.Name(), "AddImplicitDepends", 2);
431 // Read only a single record and return
438 /* Record the Description(s) based on their master md5sum */
439 MD5SumValue CurMd5
= List
.Description_md5();
440 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
443 /* Before we add a new description we first search in the group for
444 a version with a description of the same MD5 - if so we reuse this
445 description group instead of creating our own for this version */
446 for (pkgCache::PkgIterator P
= Grp
.PackageList();
447 P
.end() == false; P
= Grp
.NextPkg(P
))
449 for (pkgCache::VerIterator V
= P
.VersionList();
450 V
.end() == false; ++V
)
452 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
454 Ver
->DescriptionList
= V
->DescriptionList
;
458 // We haven't found reusable descriptions, so add the first description(s)
459 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
460 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
461 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
462 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
467 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
469 pkgCache::DescIterator Desc
;
470 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
472 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
473 if (unlikely(descindex
== 0 && _error
->PendingError()))
474 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
475 Ver
.ParentPkg().Name(), "NewDescription", 1);
477 md5idx
= Desc
->md5sum
;
478 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
480 // we add at the end, so that the start is constant as we need
481 // that to be able to efficiently share these lists
482 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
483 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
484 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
485 *LastNextDesc
= descindex
;
487 if (NewFileDesc(Desc
,List
) == false)
488 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
489 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
495 // CacheGenerator::NewGroup - Add a new group /*{{{*/
496 // ---------------------------------------------------------------------
497 /* This creates a new group structure and adds it to the hash table */
498 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
500 Grp
= Cache
.FindGrp(Name
);
501 if (Grp
.end() == false)
505 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
506 if (unlikely(Group
== 0))
509 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
510 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
511 if (unlikely(idxName
== 0))
515 // Insert it into the hash table
516 unsigned long const Hash
= Cache
.Hash(Name
);
517 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
518 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
519 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
520 Grp
->Next
= *insertAt
;
523 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
527 // CacheGenerator::NewPackage - Add a new package /*{{{*/
528 // ---------------------------------------------------------------------
529 /* This creates a new package structure and adds it to the hash table */
530 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
531 const string
&Arch
) {
532 pkgCache::GrpIterator Grp
;
533 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
534 if (unlikely(NewGroup(Grp
, Name
) == false))
537 Pkg
= Grp
.FindPkg(Arch
);
538 if (Pkg
.end() == false)
542 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
543 if (unlikely(Package
== 0))
545 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
547 // Set the name, arch and the ID
548 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
549 Pkg
->Group
= Grp
.Index();
550 // all is mapped to the native architecture
551 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
552 if (unlikely(idxArch
== 0))
555 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
557 // Insert the package into our package list
558 if (Grp
->FirstPackage
== 0) // the group is new
560 Grp
->FirstPackage
= Package
;
561 // Insert it into the hash table
562 map_id_t
const Hash
= Cache
.Hash(Name
);
563 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
564 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
565 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
566 Pkg
->NextPackage
= *insertAt
;
569 else // Group the Packages together
571 // but first get implicit provides done
572 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
574 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
575 if (M
.end() == false)
576 for (pkgCache::PrvIterator Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
578 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
580 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
581 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
582 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
583 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
584 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
588 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
589 for (pkgCache::VerIterator Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
590 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
591 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
594 // and negative dependencies, don't forget negative dependencies
596 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
597 if (M
.end() == false) {
598 pkgCache::DepIterator Dep
;
599 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
600 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
602 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
604 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
605 Dep
->Type
!= pkgCache::Dep::Replaces
)
607 pkgCache::VerIterator Ver
= Dep
.ParentVer();
608 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
609 map_pointer_t
* unused
= NULL
;
610 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
616 // this package is the new last package
617 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
618 Pkg
->NextPackage
= LastPkg
->NextPackage
;
619 LastPkg
->NextPackage
= Package
;
621 Grp
->LastPackage
= Package
;
625 // CacheGenerator::AddImplicitDepends /*{{{*/
626 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
627 pkgCache::PkgIterator
&P
,
628 pkgCache::VerIterator
&V
)
630 // copy P.Arch() into a string here as a cache remap
631 // in NewDepends() later may alter the pointer location
632 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
633 map_pointer_t
*OldDepLast
= NULL
;
634 /* MultiArch handling introduces a lot of implicit Dependencies:
635 - MultiArch: same → Co-Installable if they have the same version
636 - All others conflict with all other group members */
637 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
638 pkgCache::PkgIterator D
= G
.PackageList();
639 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
640 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
641 for (; D
.end() != true; D
= G
.NextPkg(D
))
643 if (Arch
== D
.Arch() || D
->VersionList
== 0)
645 /* We allow only one installed arch at the time
646 per group, therefore each group member conflicts
647 with all other group members */
648 if (coInstall
== true)
650 // Replaces: ${self}:other ( << ${binary:Version})
651 NewDepends(D
, V
, VerStrIdx
,
652 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
654 // Breaks: ${self}:other (!= ${binary:Version})
655 NewDepends(D
, V
, VerStrIdx
,
656 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
659 // Conflicts: ${self}:other
661 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
667 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
668 pkgCache::PkgIterator
&D
)
670 /* MultiArch handling introduces a lot of implicit Dependencies:
671 - MultiArch: same → Co-Installable if they have the same version
672 - All others conflict with all other group members */
673 map_pointer_t
*OldDepLast
= NULL
;
674 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
675 if (coInstall
== true)
677 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
678 // Replaces: ${self}:other ( << ${binary:Version})
679 NewDepends(D
, V
, VerStrIdx
,
680 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
682 // Breaks: ${self}:other (!= ${binary:Version})
683 NewDepends(D
, V
, VerStrIdx
,
684 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
687 // Conflicts: ${self}:other
689 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
696 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
697 // ---------------------------------------------------------------------
699 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
702 if (CurrentFile
== 0)
706 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
710 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
711 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
713 // Link it to the end of the list
714 map_pointer_t
*Last
= &Ver
->FileList
;
715 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
717 VF
->NextFile
= *Last
;
720 VF
->Offset
= List
.Offset();
721 VF
->Size
= List
.Size();
722 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
723 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
724 Cache
.HeaderP
->VerFileCount
++;
729 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
730 // ---------------------------------------------------------------------
731 /* This puts a version structure in the linked list */
732 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
733 const string
&VerStr
,
734 map_pointer_t
const ParentPkg
,
735 unsigned short const Hash
,
736 map_pointer_t
const Next
)
739 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
744 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
745 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
747 Ver
->ParentPkg
= ParentPkg
;
749 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
751 // try to find the version string in the group for reuse
752 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
753 pkgCache::GrpIterator Grp
= Pkg
.Group();
754 if (Pkg
.end() == false && Grp
.end() == false)
756 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
760 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
762 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
765 Ver
->VerStr
= V
->VerStr
;
773 // haven't found the version string, so create
774 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
775 if (unlikely(idxVerStr
== 0))
777 Ver
->VerStr
= idxVerStr
;
781 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
782 // ---------------------------------------------------------------------
784 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
787 if (CurrentFile
== 0)
791 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
795 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
796 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
798 // Link it to the end of the list
799 map_pointer_t
*Last
= &Desc
->FileList
;
800 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
803 DF
->NextFile
= *Last
;
806 DF
->Offset
= List
.Offset();
807 DF
->Size
= List
.Size();
808 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
809 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
810 Cache
.HeaderP
->DescFileCount
++;
815 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
816 // ---------------------------------------------------------------------
817 /* This puts a description structure in the linked list */
818 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
820 const MD5SumValue
&md5sum
,
821 map_stringitem_t
const idxmd5str
)
824 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
825 if (Description
== 0)
829 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
830 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
831 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
832 if (unlikely(idxlanguage_code
== 0))
834 Desc
->language_code
= idxlanguage_code
;
837 Desc
->md5sum
= idxmd5str
;
840 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
841 if (unlikely(idxmd5sum
== 0))
843 Desc
->md5sum
= idxmd5sum
;
849 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
850 // ---------------------------------------------------------------------
851 /* This creates a dependency element in the tree. It is linked to the
852 version and to the package that it is pointing to. */
853 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
854 pkgCache::VerIterator
&Ver
,
855 map_pointer_t
const Version
,
858 map_pointer_t
* &OldDepLast
)
860 void const * const oldMap
= Map
.Data();
862 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
863 if (unlikely(Dependency
== 0))
866 bool isDuplicate
= false;
867 map_pointer_t DependencyData
= 0;
868 map_pointer_t PreviousData
= 0;
869 if (Pkg
->RevDepends
!= 0)
871 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
872 DependencyData
= L
->DependencyData
;
874 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
875 if (Version
> D
->Version
)
877 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
882 PreviousData
= DependencyData
;
883 DependencyData
= D
->NextData
;
884 } while (DependencyData
!= 0);
887 if (isDuplicate
== false)
889 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
890 if (unlikely(DependencyData
== 0))
894 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
895 Link
->ParentVer
= Ver
.Index();
896 Link
->DependencyData
= DependencyData
;
897 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
899 pkgCache::DepIterator
Dep(Cache
, Link
);
900 if (isDuplicate
== false)
904 Dep
->Version
= Version
;
905 Dep
->Package
= Pkg
.Index();
906 ++Cache
.HeaderP
->DependsDataCount
;
907 if (PreviousData
!= 0)
909 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
910 Dep
->NextData
= D
->NextData
;
911 D
->NextData
= DependencyData
;
913 else if (Pkg
->RevDepends
!= 0)
915 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
916 Dep
->NextData
= D
->DependencyData
;
920 if (isDuplicate
== true || PreviousData
!= 0)
922 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
923 Link
->NextRevDepends
= L
->NextRevDepends
;
924 L
->NextRevDepends
= Dependency
;
928 Link
->NextRevDepends
= Pkg
->RevDepends
;
929 Pkg
->RevDepends
= Dependency
;
933 // Do we know where to link the Dependency to?
934 if (OldDepLast
== NULL
)
936 OldDepLast
= &Ver
->DependsList
;
937 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
938 OldDepLast
= &D
->NextDepends
;
939 } else if (oldMap
!= Map
.Data())
940 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
942 Dep
->NextDepends
= *OldDepLast
;
943 *OldDepLast
= Dependency
;
944 OldDepLast
= &Dep
->NextDepends
;
948 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
949 // ---------------------------------------------------------------------
950 /* This creates a Group and the Package to link this dependency to if
951 needed and handles also the caching of the old endpoint */
952 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
953 const string
&PackageName
,
955 const string
&Version
,
959 pkgCache::GrpIterator Grp
;
960 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
961 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
964 map_stringitem_t idxVersion
= 0;
965 if (Version
.empty() == false)
967 int const CmpOp
= Op
& 0x0F;
968 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
969 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
970 idxVersion
= Ver
->VerStr
;
974 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
975 if (unlikely(idxVersion
== 0))
980 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
981 Type
== pkgCache::Dep::Conflicts
||
982 Type
== pkgCache::Dep::Replaces
);
984 pkgCache::PkgIterator Pkg
;
985 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
986 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
988 // Locate the target package
989 Pkg
= Grp
.FindPkg(Arch
);
990 if (Pkg
.end() == true) {
991 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
995 /* Caching the old end point speeds up generation substantially */
996 if (OldDepVer
!= Ver
) {
1001 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1005 /* Caching the old end point speeds up generation substantially */
1006 if (OldDepVer
!= Ver
) {
1011 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1013 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1020 // ListParser::NewProvides - Create a Provides element /*{{{*/
1021 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1022 const string
&PkgName
,
1023 const string
&PkgArch
,
1024 const string
&Version
,
1025 uint8_t const Flags
)
1027 pkgCache
const &Cache
= Owner
->Cache
;
1029 // We do not add self referencing provides
1030 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1031 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1034 // Locate the target package
1035 pkgCache::PkgIterator Pkg
;
1036 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1037 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1040 map_stringitem_t idxProvideVersion
= 0;
1041 if (Version
.empty() == false) {
1042 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1043 if (unlikely(idxProvideVersion
== 0))
1046 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1048 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1049 pkgCache::PkgIterator
&Pkg
,
1050 map_pointer_t
const ProvideVersion
,
1051 uint8_t const Flags
)
1054 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1055 if (unlikely(Provides
== 0))
1057 ++Cache
.HeaderP
->ProvidesCount
;
1060 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1061 Prv
->Version
= Ver
.Index();
1062 Prv
->ProvideVersion
= ProvideVersion
;
1064 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1065 Ver
->ProvidesList
= Prv
.Index();
1067 // Link it to the package
1068 Prv
->ParentPkg
= Pkg
.Index();
1069 Prv
->NextProvides
= Pkg
->ProvidesList
;
1070 Pkg
->ProvidesList
= Prv
.Index();
1074 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1075 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, string
const &Package
,
1076 string
const &Version
, uint8_t const Flags
) {
1077 pkgCache
&Cache
= Owner
->Cache
;
1078 pkgCache::GrpIterator
const Grp
= Cache
.FindGrp(Package
);
1079 if (Grp
.end() == true)
1080 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1083 map_stringitem_t idxProvideVersion
= 0;
1084 if (Version
.empty() == false) {
1085 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1086 if (unlikely(idxProvideVersion
== 0))
1090 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1091 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1092 pkgCache::PkgIterator
const OwnerPkg
= Ver
.ParentPkg();
1093 for (pkgCache::PkgIterator Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1095 if (isImplicit
&& OwnerPkg
== Pkg
)
1097 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1099 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1106 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1107 pkgCache::VerIterator
const &Ver
)
1109 return Hash
== Ver
->Hash
;
1112 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1113 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1114 unsigned long Flags
)
1116 if (File
.empty() && Site
.empty())
1118 CurrentRlsFile
= NULL
;
1122 // Get some space for the structure
1123 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1124 if (unlikely(idxFile
== 0))
1126 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1129 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1130 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1131 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1133 CurrentRlsFile
->FileName
= idxFileName
;
1134 CurrentRlsFile
->Site
= idxSite
;
1135 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1136 CurrentRlsFile
->Flags
= Flags
;
1137 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1139 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1140 Cache
.HeaderP
->ReleaseFileCount
++;
1145 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1146 // ---------------------------------------------------------------------
1147 /* This is used to select which file is to be associated with all newly
1148 added versions. The caller is responsible for setting the IMS fields. */
1149 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1150 pkgIndexFile
const &Index
,
1151 std::string
const &Architecture
,
1152 std::string
const &Component
,
1153 unsigned long const Flags
)
1155 // Get some space for the structure
1156 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1157 if (unlikely(idxFile
== 0))
1159 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1162 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1163 if (unlikely(idxFileName
== 0))
1165 CurrentFile
->FileName
= idxFileName
;
1166 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1167 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1168 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1169 if (unlikely(idxIndexType
== 0))
1171 CurrentFile
->IndexType
= idxIndexType
;
1172 if (Architecture
.empty())
1173 CurrentFile
->Architecture
= 0;
1176 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1177 if (unlikely(arch
== 0))
1179 CurrentFile
->Architecture
= arch
;
1181 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1182 if (unlikely(component
== 0))
1184 CurrentFile
->Component
= component
;
1185 CurrentFile
->Flags
= Flags
;
1186 if (CurrentRlsFile
!= NULL
)
1187 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1189 CurrentFile
->Release
= 0;
1191 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1192 Cache
.HeaderP
->PackageFileCount
++;
1195 Progress
->SubProgress(Index
.Size());
1199 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1200 // ---------------------------------------------------------------------
1201 /* This is used to create handles to strings. Given the same text it
1202 always returns the same number */
1203 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1206 std::string
const key(S
, Size
);
1208 std::map
<std::string
,map_stringitem_t
> * strings
;
1210 case MIXED
: strings
= &strMixed
; break;
1211 case PKGNAME
: strings
= &strPkgNames
; break;
1212 case VERSIONNUMBER
: strings
= &strVersions
; break;
1213 case SECTION
: strings
= &strSections
; break;
1214 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1217 std::map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1218 if (item
!= strings
->end())
1219 return item
->second
;
1221 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1222 strings
->insert(std::make_pair(key
, idxString
));
1226 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1227 // ---------------------------------------------------------------------
1228 /* This just verifies that each file in the list of index files exists,
1229 has matching attributes with the cache and the cache does not have
1231 static bool CheckValidity(const string
&CacheFile
,
1232 pkgSourceList
&List
,
1233 FileIterator
const Start
,
1234 FileIterator
const End
,
1237 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1238 // No file, certainly invalid
1239 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1242 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1246 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1249 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1254 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1255 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1256 pkgCache
Cache(Map
.get());
1257 if (_error
->PendingError() == true || Map
->Size() == 0)
1260 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1265 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1266 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1267 std::vector
<pkgIndexFile
*> Files
;
1268 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1271 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1272 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1273 if (RlsFile
.end() == true)
1276 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1280 RlsVisited
[RlsFile
->ID
] = true;
1282 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1284 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1285 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1286 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1288 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1289 if (RlsVisited
[I
] == false)
1292 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1296 std::copy(Start
, End
, std::back_inserter(Files
));
1298 /* Now we check every index file, see if it is in the cache,
1299 verify the IMS data and check that it is on the disk too.. */
1300 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1301 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1302 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1305 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1306 if ((*PkgFile
)->Exists() == false)
1309 std::clog
<< "file doesn't exist" << std::endl
;
1313 // FindInCache is also expected to do an IMS check.
1314 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1315 if (File
.end() == true)
1318 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1322 Visited
[File
->ID
] = true;
1324 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1327 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1328 if (Visited
[I
] == false)
1331 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1335 if (_error
->PendingError() == true)
1339 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1340 _error
->DumpErrors();
1347 *OutMap
= Map
.release();
1351 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1352 // ---------------------------------------------------------------------
1353 /* Size is kind of an abstract notion that is only used for the progress
1355 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1357 map_filesize_t TotalSize
= 0;
1360 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1362 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1363 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1364 if ((*j
)->HasPackages() == true)
1365 TotalSize
+= (*j
)->Size();
1369 for (; Start
< End
; ++Start
)
1371 if ((*Start
)->HasPackages() == false)
1373 TotalSize
+= (*Start
)->Size();
1378 // BuildCache - Merge the list of index files into the cache /*{{{*/
1379 static bool BuildCache(pkgCacheGenerator
&Gen
,
1380 OpProgress
* const Progress
,
1381 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1382 pkgSourceList
const * const List
,
1383 FileIterator
const Start
, FileIterator
const End
)
1385 std::vector
<pkgIndexFile
*> Files
;
1386 bool mergeFailure
= false;
1388 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1389 if (I
->HasPackages() == false || mergeFailure
)
1392 if (I
->Exists() == false)
1395 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1397 _error
->Warning("Duplicate sources.list entry %s",
1398 I
->Describe().c_str());
1402 map_filesize_t
const Size
= I
->Size();
1403 if (Progress
!= NULL
)
1404 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1405 CurrentSize
+= Size
;
1407 if (I
->Merge(Gen
,Progress
) == false)
1408 mergeFailure
= true;
1413 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1415 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1417 _error
->Warning("Duplicate sources.list entry %s",
1418 (*i
)->Describe().c_str());
1422 if ((*i
)->Merge(Gen
, Progress
) == false)
1425 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1426 if (Indexes
!= NULL
)
1427 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1435 Gen
.SelectReleaseFile("", "");
1436 std::for_each(Start
, End
, indexFileMerge
);
1443 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1444 // ---------------------------------------------------------------------
1445 /* This makes sure that the status cache (the cache that has all
1446 index files from the sources list and all local ones) is ready
1447 to be mmaped. If OutMap is not zero then a MMap object representing
1448 the cache will be stored there. This is pretty much mandetory if you
1449 are using AllowMem. AllowMem lets the function be run as non-root
1450 where it builds the cache 'fast' into a memory buffer. */
1451 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1453 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1454 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1455 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1456 Flags
|= MMap::Moveable
;
1457 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1458 Flags
|= MMap::Fallback
;
1460 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1462 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1464 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1465 std::string
const &FileName
)
1467 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1468 if (_error
->PendingError() == true)
1471 fchmod(SCacheF
.Fd(),0644);
1473 // Write out the main data
1474 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1475 return _error
->Error(_("IO Error saving source cache"));
1478 // Write out the proper header
1479 Gen
->GetCache().HeaderP
->Dirty
= false;
1480 if (SCacheF
.Seek(0) == false ||
1481 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1482 return _error
->Error(_("IO Error saving source cache"));
1483 Gen
->GetCache().HeaderP
->Dirty
= true;
1487 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1488 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1490 Map
.reset(CreateDynamicMMap(NULL
, 0));
1491 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1492 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1493 if ((alloc
== 0 && _error
->PendingError())
1494 || CacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1495 CacheF
.Size()) == false)
1497 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1500 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1501 MMap
**OutMap
, bool AllowMem
)
1502 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1503 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1504 MMap
**OutMap
,bool AllowMem
)
1506 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1508 std::vector
<pkgIndexFile
*> Files
;
1509 if (_system
->AddStatusFiles(Files
) == false)
1512 // Decide if we can write to the files..
1513 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1514 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1516 // ensure the cache directory exists
1517 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1519 string dir
= _config
->FindDir("Dir::Cache");
1520 size_t const len
= dir
.size();
1521 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1522 dir
= dir
.substr(0, len
- 5);
1523 if (CacheFile
.empty() == false)
1524 CreateDirectory(dir
, flNotFile(CacheFile
));
1525 if (SrcCacheFile
.empty() == false)
1526 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1529 if (Progress
!= NULL
)
1530 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1532 bool pkgcache_fine
= false;
1533 bool srcpkgcache_fine
= false;
1534 bool volatile_fine
= List
.GetVolatileFiles().empty();
1536 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
) == true)
1539 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1540 pkgcache_fine
= true;
1541 srcpkgcache_fine
= true;
1543 if (pkgcache_fine
== false)
1545 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1548 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1549 srcpkgcache_fine
= true;
1553 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1555 if (Progress
!= NULL
)
1556 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1560 bool Writeable
= false;
1561 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1563 if (CacheFile
.empty() == false)
1564 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1565 else if (SrcCacheFile
.empty() == false)
1566 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1569 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1571 if (Writeable
== false && AllowMem
== false)
1573 if (CacheFile
.empty() == false)
1574 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1575 else if (SrcCacheFile
.empty() == false)
1576 return _error
->Error(_("Unable to write to %s"),flNotFile(SrcCacheFile
).c_str());
1578 return _error
->Error("Unable to create caches as file usage is disabled, but memory not allowed either!");
1582 // At this point we know we need to construct something, so get storage ready
1583 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1585 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1587 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1588 map_filesize_t CurrentSize
= 0;
1589 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1590 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1591 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1594 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1595 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1597 srcpkgcache_fine
= true;
1598 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1600 else if (srcpkgcache_fine
== false)
1603 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1604 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1606 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1607 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1608 Files
.end(),Files
.end()) == false)
1611 if (Writeable
== true && SrcCacheFile
.empty() == false)
1612 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1616 if (pkgcache_fine
== false)
1619 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1620 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1621 Files
.begin(), Files
.end()) == false)
1624 if (Writeable
== true && CacheFile
.empty() == false)
1625 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1630 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1632 if (volatile_fine
== false)
1637 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1638 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1642 Files
= List
.GetVolatileFiles();
1643 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1644 Files
.begin(), Files
.end()) == false)
1648 if (OutMap
!= nullptr)
1649 *OutMap
= Map
.release();
1652 std::clog
<< "Everything is ready for shipping" << std::endl
;
1656 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1657 // ---------------------------------------------------------------------
1659 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1660 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1661 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1663 std::vector
<pkgIndexFile
*> Files
;
1664 if (_system
->AddStatusFiles(Files
) == false)
1667 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1668 map_filesize_t CurrentSize
= 0;
1669 map_filesize_t TotalSize
= 0;
1671 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1673 // Build the status cache
1674 if (Progress
!= NULL
)
1675 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1676 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1677 if (_error
->PendingError() == true)
1679 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1680 Files
.begin(), Files
.end()) == false)
1683 if (_error
->PendingError() == true)
1685 *OutMap
= Map
.release();
1690 // IsDuplicateDescription /*{{{*/
1691 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1692 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1694 // Descriptions in the same link-list have all the same md5
1695 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1697 for (; Desc
.end() == false; ++Desc
)
1698 if (Desc
.LanguageCode() == CurLang
)
1704 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1705 pkgCacheListParser::~pkgCacheListParser() {}