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 for (pkgCache::DepIterator Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
600 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
602 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
603 Dep
->Type
!= pkgCache::Dep::Replaces
)
605 pkgCache::VerIterator Ver
= Dep
.ParentVer();
606 map_pointer_t
* unused
= NULL
;
607 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
612 // this package is the new last package
613 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
614 Pkg
->NextPackage
= LastPkg
->NextPackage
;
615 LastPkg
->NextPackage
= Package
;
617 Grp
->LastPackage
= Package
;
621 // CacheGenerator::AddImplicitDepends /*{{{*/
622 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
623 pkgCache::PkgIterator
&P
,
624 pkgCache::VerIterator
&V
)
626 // copy P.Arch() into a string here as a cache remap
627 // in NewDepends() later may alter the pointer location
628 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
629 map_pointer_t
*OldDepLast
= NULL
;
630 /* MultiArch handling introduces a lot of implicit Dependencies:
631 - MultiArch: same → Co-Installable if they have the same version
632 - All others conflict with all other group members */
633 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
634 pkgCache::PkgIterator D
= G
.PackageList();
635 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
636 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
637 for (; D
.end() != true; D
= G
.NextPkg(D
))
639 if (Arch
== D
.Arch() || D
->VersionList
== 0)
641 /* We allow only one installed arch at the time
642 per group, therefore each group member conflicts
643 with all other group members */
644 if (coInstall
== true)
646 // Replaces: ${self}:other ( << ${binary:Version})
647 NewDepends(D
, V
, VerStrIdx
,
648 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
650 // Breaks: ${self}:other (!= ${binary:Version})
651 NewDepends(D
, V
, VerStrIdx
,
652 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
655 // Conflicts: ${self}:other
657 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
663 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
664 pkgCache::PkgIterator
&D
)
666 /* MultiArch handling introduces a lot of implicit Dependencies:
667 - MultiArch: same → Co-Installable if they have the same version
668 - All others conflict with all other group members */
669 map_pointer_t
*OldDepLast
= NULL
;
670 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
671 if (coInstall
== true)
673 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
674 // Replaces: ${self}:other ( << ${binary:Version})
675 NewDepends(D
, V
, VerStrIdx
,
676 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
678 // Breaks: ${self}:other (!= ${binary:Version})
679 NewDepends(D
, V
, VerStrIdx
,
680 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
683 // Conflicts: ${self}:other
685 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
692 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
693 // ---------------------------------------------------------------------
695 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
698 if (CurrentFile
== 0)
702 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
706 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
707 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
709 // Link it to the end of the list
710 map_pointer_t
*Last
= &Ver
->FileList
;
711 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
713 VF
->NextFile
= *Last
;
716 VF
->Offset
= List
.Offset();
717 VF
->Size
= List
.Size();
718 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
719 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
720 Cache
.HeaderP
->VerFileCount
++;
725 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
726 // ---------------------------------------------------------------------
727 /* This puts a version structure in the linked list */
728 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
729 const string
&VerStr
,
730 map_pointer_t
const ParentPkg
,
731 unsigned short const Hash
,
732 map_pointer_t
const Next
)
735 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
740 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
741 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
743 Ver
->ParentPkg
= ParentPkg
;
745 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
747 // try to find the version string in the group for reuse
748 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
749 pkgCache::GrpIterator Grp
= Pkg
.Group();
750 if (Pkg
.end() == false && Grp
.end() == false)
752 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
756 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
758 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
761 Ver
->VerStr
= V
->VerStr
;
769 // haven't found the version string, so create
770 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
771 if (unlikely(idxVerStr
== 0))
773 Ver
->VerStr
= idxVerStr
;
777 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
778 // ---------------------------------------------------------------------
780 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
783 if (CurrentFile
== 0)
787 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
791 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
792 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
794 // Link it to the end of the list
795 map_pointer_t
*Last
= &Desc
->FileList
;
796 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
799 DF
->NextFile
= *Last
;
802 DF
->Offset
= List
.Offset();
803 DF
->Size
= List
.Size();
804 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
805 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
806 Cache
.HeaderP
->DescFileCount
++;
811 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
812 // ---------------------------------------------------------------------
813 /* This puts a description structure in the linked list */
814 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
816 const MD5SumValue
&md5sum
,
817 map_stringitem_t
const idxmd5str
)
820 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
821 if (Description
== 0)
825 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
826 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
827 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
828 if (unlikely(idxlanguage_code
== 0))
830 Desc
->language_code
= idxlanguage_code
;
833 Desc
->md5sum
= idxmd5str
;
836 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
837 if (unlikely(idxmd5sum
== 0))
839 Desc
->md5sum
= idxmd5sum
;
845 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
846 // ---------------------------------------------------------------------
847 /* This creates a dependency element in the tree. It is linked to the
848 version and to the package that it is pointing to. */
849 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
850 pkgCache::VerIterator
&Ver
,
851 map_pointer_t
const Version
,
854 map_pointer_t
* &OldDepLast
)
856 void const * const oldMap
= Map
.Data();
858 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
859 if (unlikely(Dependency
== 0))
862 bool isDuplicate
= false;
863 map_pointer_t DependencyData
= 0;
864 map_pointer_t PreviousData
= 0;
865 if (Pkg
->RevDepends
!= 0)
867 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
868 DependencyData
= L
->DependencyData
;
870 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
871 if (Version
> D
->Version
)
873 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
878 PreviousData
= DependencyData
;
879 DependencyData
= D
->NextData
;
880 } while (DependencyData
!= 0);
883 if (isDuplicate
== false)
885 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
886 if (unlikely(DependencyData
== 0))
890 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
891 Link
->ParentVer
= Ver
.Index();
892 Link
->DependencyData
= DependencyData
;
893 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
895 pkgCache::DepIterator
Dep(Cache
, Link
);
896 if (isDuplicate
== false)
900 Dep
->Version
= Version
;
901 Dep
->Package
= Pkg
.Index();
902 ++Cache
.HeaderP
->DependsDataCount
;
903 if (PreviousData
!= 0)
905 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
906 Dep
->NextData
= D
->NextData
;
907 D
->NextData
= DependencyData
;
909 else if (Pkg
->RevDepends
!= 0)
911 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
912 Dep
->NextData
= D
->DependencyData
;
916 if (isDuplicate
== true || PreviousData
!= 0)
918 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
919 Link
->NextRevDepends
= L
->NextRevDepends
;
920 L
->NextRevDepends
= Dependency
;
924 Link
->NextRevDepends
= Pkg
->RevDepends
;
925 Pkg
->RevDepends
= Dependency
;
929 // Do we know where to link the Dependency to?
930 if (OldDepLast
== NULL
)
932 OldDepLast
= &Ver
->DependsList
;
933 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
934 OldDepLast
= &D
->NextDepends
;
935 } else if (oldMap
!= Map
.Data())
936 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
938 Dep
->NextDepends
= *OldDepLast
;
939 *OldDepLast
= Dependency
;
940 OldDepLast
= &Dep
->NextDepends
;
944 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
945 // ---------------------------------------------------------------------
946 /* This creates a Group and the Package to link this dependency to if
947 needed and handles also the caching of the old endpoint */
948 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
949 const string
&PackageName
,
951 const string
&Version
,
955 pkgCache::GrpIterator Grp
;
956 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
957 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
960 map_stringitem_t idxVersion
= 0;
961 if (Version
.empty() == false)
963 int const CmpOp
= Op
& 0x0F;
964 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
965 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
966 idxVersion
= Ver
->VerStr
;
970 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
971 if (unlikely(idxVersion
== 0))
976 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
977 Type
== pkgCache::Dep::Conflicts
||
978 Type
== pkgCache::Dep::Replaces
);
980 pkgCache::PkgIterator Pkg
;
981 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
982 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
984 // Locate the target package
985 Pkg
= Grp
.FindPkg(Arch
);
986 if (Pkg
.end() == true) {
987 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
991 /* Caching the old end point speeds up generation substantially */
992 if (OldDepVer
!= Ver
) {
997 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1001 /* Caching the old end point speeds up generation substantially */
1002 if (OldDepVer
!= Ver
) {
1007 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1009 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1016 // ListParser::NewProvides - Create a Provides element /*{{{*/
1017 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1018 const string
&PkgName
,
1019 const string
&PkgArch
,
1020 const string
&Version
,
1021 uint8_t const Flags
)
1023 pkgCache
const &Cache
= Owner
->Cache
;
1025 // We do not add self referencing provides
1026 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1027 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1030 // Locate the target package
1031 pkgCache::PkgIterator Pkg
;
1032 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1033 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1036 map_stringitem_t idxProvideVersion
= 0;
1037 if (Version
.empty() == false) {
1038 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1039 if (unlikely(idxProvideVersion
== 0))
1042 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1044 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1045 pkgCache::PkgIterator
&Pkg
,
1046 map_pointer_t
const ProvideVersion
,
1047 uint8_t const Flags
)
1050 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1051 if (unlikely(Provides
== 0))
1053 ++Cache
.HeaderP
->ProvidesCount
;
1056 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1057 Prv
->Version
= Ver
.Index();
1058 Prv
->ProvideVersion
= ProvideVersion
;
1060 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1061 Ver
->ProvidesList
= Prv
.Index();
1063 // Link it to the package
1064 Prv
->ParentPkg
= Pkg
.Index();
1065 Prv
->NextProvides
= Pkg
->ProvidesList
;
1066 Pkg
->ProvidesList
= Prv
.Index();
1070 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1071 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, string
const &Package
,
1072 string
const &Version
, uint8_t const Flags
) {
1073 pkgCache
&Cache
= Owner
->Cache
;
1074 pkgCache::GrpIterator
const Grp
= Cache
.FindGrp(Package
);
1075 if (Grp
.end() == true)
1076 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1079 map_stringitem_t idxProvideVersion
= 0;
1080 if (Version
.empty() == false) {
1081 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1082 if (unlikely(idxProvideVersion
== 0))
1086 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1087 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1088 pkgCache::PkgIterator
const OwnerPkg
= Ver
.ParentPkg();
1089 for (pkgCache::PkgIterator Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1091 if (isImplicit
&& OwnerPkg
== Pkg
)
1093 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1095 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1102 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1103 pkgCache::VerIterator
const &Ver
)
1105 return Hash
== Ver
->Hash
;
1108 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1109 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1110 unsigned long Flags
)
1112 if (File
.empty() && Site
.empty())
1114 CurrentRlsFile
= NULL
;
1118 // Get some space for the structure
1119 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1120 if (unlikely(idxFile
== 0))
1122 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1125 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1126 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1127 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1129 CurrentRlsFile
->FileName
= idxFileName
;
1130 CurrentRlsFile
->Site
= idxSite
;
1131 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1132 CurrentRlsFile
->Flags
= Flags
;
1133 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1135 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1136 Cache
.HeaderP
->ReleaseFileCount
++;
1141 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1142 // ---------------------------------------------------------------------
1143 /* This is used to select which file is to be associated with all newly
1144 added versions. The caller is responsible for setting the IMS fields. */
1145 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1146 pkgIndexFile
const &Index
,
1147 std::string
const &Architecture
,
1148 std::string
const &Component
,
1149 unsigned long const Flags
)
1151 // Get some space for the structure
1152 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1153 if (unlikely(idxFile
== 0))
1155 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1158 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1159 if (unlikely(idxFileName
== 0))
1161 CurrentFile
->FileName
= idxFileName
;
1162 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1163 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1164 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1165 if (unlikely(idxIndexType
== 0))
1167 CurrentFile
->IndexType
= idxIndexType
;
1168 if (Architecture
.empty())
1169 CurrentFile
->Architecture
= 0;
1172 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1173 if (unlikely(arch
== 0))
1175 CurrentFile
->Architecture
= arch
;
1177 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1178 if (unlikely(component
== 0))
1180 CurrentFile
->Component
= component
;
1181 CurrentFile
->Flags
= Flags
;
1182 if (CurrentRlsFile
!= NULL
)
1183 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1185 CurrentFile
->Release
= 0;
1187 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1188 Cache
.HeaderP
->PackageFileCount
++;
1191 Progress
->SubProgress(Index
.Size());
1195 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1196 // ---------------------------------------------------------------------
1197 /* This is used to create handles to strings. Given the same text it
1198 always returns the same number */
1199 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1202 std::string
const key(S
, Size
);
1204 std::map
<std::string
,map_stringitem_t
> * strings
;
1206 case MIXED
: strings
= &strMixed
; break;
1207 case PKGNAME
: strings
= &strPkgNames
; break;
1208 case VERSIONNUMBER
: strings
= &strVersions
; break;
1209 case SECTION
: strings
= &strSections
; break;
1210 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1213 std::map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1214 if (item
!= strings
->end())
1215 return item
->second
;
1217 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1218 strings
->insert(std::make_pair(key
, idxString
));
1222 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1223 // ---------------------------------------------------------------------
1224 /* This just verifies that each file in the list of index files exists,
1225 has matching attributes with the cache and the cache does not have
1227 static bool CheckValidity(const string
&CacheFile
,
1228 pkgSourceList
&List
,
1229 FileIterator
const Start
,
1230 FileIterator
const End
,
1233 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1234 // No file, certainly invalid
1235 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1238 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1242 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1245 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1250 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1251 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1252 pkgCache
Cache(Map
.get());
1253 if (_error
->PendingError() == true || Map
->Size() == 0)
1256 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1261 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1262 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1263 std::vector
<pkgIndexFile
*> Files
;
1264 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1267 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1268 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1269 if (RlsFile
.end() == true)
1272 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1276 RlsVisited
[RlsFile
->ID
] = true;
1278 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1280 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1281 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1282 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1284 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1285 if (RlsVisited
[I
] == false)
1288 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1292 std::copy(Start
, End
, std::back_inserter(Files
));
1294 /* Now we check every index file, see if it is in the cache,
1295 verify the IMS data and check that it is on the disk too.. */
1296 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1297 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1298 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1301 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1302 if ((*PkgFile
)->Exists() == false)
1305 std::clog
<< "file doesn't exist" << std::endl
;
1309 // FindInCache is also expected to do an IMS check.
1310 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1311 if (File
.end() == true)
1314 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1318 Visited
[File
->ID
] = true;
1320 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1323 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1324 if (Visited
[I
] == false)
1327 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1331 if (_error
->PendingError() == true)
1335 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1336 _error
->DumpErrors();
1343 *OutMap
= Map
.release();
1347 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1348 // ---------------------------------------------------------------------
1349 /* Size is kind of an abstract notion that is only used for the progress
1351 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1353 map_filesize_t TotalSize
= 0;
1356 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1358 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1359 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1360 if ((*j
)->HasPackages() == true)
1361 TotalSize
+= (*j
)->Size();
1365 for (; Start
< End
; ++Start
)
1367 if ((*Start
)->HasPackages() == false)
1369 TotalSize
+= (*Start
)->Size();
1374 // BuildCache - Merge the list of index files into the cache /*{{{*/
1375 static bool BuildCache(pkgCacheGenerator
&Gen
,
1376 OpProgress
* const Progress
,
1377 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1378 pkgSourceList
const * const List
,
1379 FileIterator
const Start
, FileIterator
const End
)
1381 std::vector
<pkgIndexFile
*> Files
;
1382 bool mergeFailure
= false;
1384 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1385 if (I
->HasPackages() == false || mergeFailure
)
1388 if (I
->Exists() == false)
1391 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1393 _error
->Warning("Duplicate sources.list entry %s",
1394 I
->Describe().c_str());
1398 map_filesize_t
const Size
= I
->Size();
1399 if (Progress
!= NULL
)
1400 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1401 CurrentSize
+= Size
;
1403 if (I
->Merge(Gen
,Progress
) == false)
1404 mergeFailure
= true;
1409 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1411 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1413 _error
->Warning("Duplicate sources.list entry %s",
1414 (*i
)->Describe().c_str());
1418 if ((*i
)->Merge(Gen
, Progress
) == false)
1421 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1422 if (Indexes
!= NULL
)
1423 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1431 Gen
.SelectReleaseFile("", "");
1432 std::for_each(Start
, End
, indexFileMerge
);
1439 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1440 // ---------------------------------------------------------------------
1441 /* This makes sure that the status cache (the cache that has all
1442 index files from the sources list and all local ones) is ready
1443 to be mmaped. If OutMap is not zero then a MMap object representing
1444 the cache will be stored there. This is pretty much mandetory if you
1445 are using AllowMem. AllowMem lets the function be run as non-root
1446 where it builds the cache 'fast' into a memory buffer. */
1447 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1449 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1450 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1451 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1452 Flags
|= MMap::Moveable
;
1453 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1454 Flags
|= MMap::Fallback
;
1456 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1458 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1460 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1461 std::string
const &FileName
)
1463 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1464 if (_error
->PendingError() == true)
1467 fchmod(SCacheF
.Fd(),0644);
1469 // Write out the main data
1470 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1471 return _error
->Error(_("IO Error saving source cache"));
1474 // Write out the proper header
1475 Gen
->GetCache().HeaderP
->Dirty
= false;
1476 if (SCacheF
.Seek(0) == false ||
1477 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1478 return _error
->Error(_("IO Error saving source cache"));
1479 Gen
->GetCache().HeaderP
->Dirty
= true;
1483 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1484 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1486 Map
.reset(CreateDynamicMMap(NULL
, 0));
1487 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1488 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1489 if ((alloc
== 0 && _error
->PendingError())
1490 || CacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1491 CacheF
.Size()) == false)
1493 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1496 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1497 MMap
**OutMap
, bool AllowMem
)
1498 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1499 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1500 MMap
**OutMap
,bool AllowMem
)
1502 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1504 std::vector
<pkgIndexFile
*> Files
;
1505 if (_system
->AddStatusFiles(Files
) == false)
1508 // Decide if we can write to the files..
1509 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1510 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1512 // ensure the cache directory exists
1513 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1515 string dir
= _config
->FindDir("Dir::Cache");
1516 size_t const len
= dir
.size();
1517 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1518 dir
= dir
.substr(0, len
- 5);
1519 if (CacheFile
.empty() == false)
1520 CreateDirectory(dir
, flNotFile(CacheFile
));
1521 if (SrcCacheFile
.empty() == false)
1522 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1525 if (Progress
!= NULL
)
1526 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1528 bool pkgcache_fine
= false;
1529 bool srcpkgcache_fine
= false;
1530 bool volatile_fine
= List
.GetVolatileFiles().empty();
1532 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
) == true)
1535 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1536 pkgcache_fine
= true;
1537 srcpkgcache_fine
= true;
1539 if (pkgcache_fine
== false)
1541 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1544 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1545 srcpkgcache_fine
= true;
1549 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1551 if (Progress
!= NULL
)
1552 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1556 bool Writeable
= false;
1557 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1559 if (CacheFile
.empty() == false)
1560 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1561 else if (SrcCacheFile
.empty() == false)
1562 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1565 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1567 if (Writeable
== false && AllowMem
== false)
1569 if (CacheFile
.empty() == false)
1570 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1571 else if (SrcCacheFile
.empty() == false)
1572 return _error
->Error(_("Unable to write to %s"),flNotFile(SrcCacheFile
).c_str());
1574 return _error
->Error("Unable to create caches as file usage is disabled, but memory not allowed either!");
1578 // At this point we know we need to construct something, so get storage ready
1579 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1581 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1583 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1584 map_filesize_t CurrentSize
= 0;
1585 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1586 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1587 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1590 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1591 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1593 srcpkgcache_fine
= true;
1594 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1596 else if (srcpkgcache_fine
== false)
1599 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1600 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1602 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1603 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1604 Files
.end(),Files
.end()) == false)
1607 if (Writeable
== true && SrcCacheFile
.empty() == false)
1608 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1612 if (pkgcache_fine
== false)
1615 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1616 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1617 Files
.begin(), Files
.end()) == false)
1620 if (Writeable
== true && CacheFile
.empty() == false)
1621 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1626 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1628 if (volatile_fine
== false)
1633 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1634 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1638 Files
= List
.GetVolatileFiles();
1639 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1640 Files
.begin(), Files
.end()) == false)
1644 if (OutMap
!= nullptr)
1645 *OutMap
= Map
.release();
1648 std::clog
<< "Everything is ready for shipping" << std::endl
;
1652 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1653 // ---------------------------------------------------------------------
1655 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1656 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1657 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1659 std::vector
<pkgIndexFile
*> Files
;
1660 if (_system
->AddStatusFiles(Files
) == false)
1663 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1664 map_filesize_t CurrentSize
= 0;
1665 map_filesize_t TotalSize
= 0;
1667 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1669 // Build the status cache
1670 if (Progress
!= NULL
)
1671 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1672 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1673 if (_error
->PendingError() == true)
1675 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1676 Files
.begin(), Files
.end()) == false)
1679 if (_error
->PendingError() == true)
1681 *OutMap
= Map
.release();
1686 // IsDuplicateDescription /*{{{*/
1687 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1688 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1690 // Descriptions in the same link-list have all the same md5
1691 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1693 for (; Desc
.end() == false; ++Desc
)
1694 if (Desc
.LanguageCode() == CurLang
)
1700 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1701 pkgCacheListParser::~pkgCacheListParser() {}