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
)
62 // Setup the map interface..
63 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
64 _error
->PushToStack();
65 Map
.RawAllocate(sizeof(pkgCache::Header
));
66 bool const newError
= _error
->PendingError();
67 _error
->MergeWithStack();
71 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
74 *Cache
.HeaderP
= pkgCache::Header();
76 // make room for the hashtables for packages and groups
77 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
80 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
81 if (unlikely(idxVerSysName
== 0))
83 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
84 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
85 if (unlikely(idxArchitecture
== 0))
87 Cache
.HeaderP
->Architecture
= idxArchitecture
;
89 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
92 std::vector
<std::string
>::const_iterator a
= archs
.begin();
93 std::string list
= *a
;
94 for (++a
; a
!= archs
.end(); ++a
)
95 list
.append(",").append(*a
);
96 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
97 if (unlikely(idxArchitectures
== 0))
99 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
102 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
104 // Calculate the hash for the empty map, so ReMap does not fail
105 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
110 // Map directly from the existing file
112 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
113 if (Cache
.VS
!= _system
->VS
)
115 _error
->Error(_("Cache has an incompatible versioning system"));
120 Cache
.HeaderP
->Dirty
= true;
121 Map
.Sync(0,sizeof(pkgCache::Header
));
124 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
125 // ---------------------------------------------------------------------
126 /* We sync the data then unset the dirty flag in two steps so as to
127 advoid a problem during a crash */
128 pkgCacheGenerator::~pkgCacheGenerator()
130 if (_error
->PendingError() == true || Map
.validData() == false)
132 if (Map
.Sync() == false)
135 Cache
.HeaderP
->Dirty
= false;
136 Cache
.HeaderP
->CacheFileSize
= Cache
.CacheHash();
138 if (_config
->FindB("Debug::pkgCacheGen", false))
139 std::clog
<< "Produced cache with hash " << Cache
.HeaderP
->CacheFileSize
<< std::endl
;
140 Map
.Sync(0,sizeof(pkgCache::Header
));
143 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
144 if (oldMap
== newMap
)
147 if (_config
->FindB("Debug::pkgCacheGen", false))
148 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
152 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
153 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
155 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
156 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
157 (*i
)->ReMap(oldMap
, newMap
);
158 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
159 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
160 (*i
)->ReMap(oldMap
, newMap
);
161 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
162 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
163 (*i
)->ReMap(oldMap
, newMap
);
164 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
165 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
166 (*i
)->ReMap(oldMap
, newMap
);
167 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
168 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
169 (*i
)->ReMap(oldMap
, newMap
);
170 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
171 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
172 (*i
)->ReMap(oldMap
, newMap
);
173 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
174 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
175 (*i
)->ReMap(oldMap
, newMap
);
176 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
177 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
178 (*i
)->ReMap(oldMap
, newMap
);
180 // CacheGenerator::WriteStringInMap /*{{{*/
181 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
182 const unsigned long &Len
) {
183 void const * const oldMap
= Map
.Data();
184 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
186 ReMap(oldMap
, Map
.Data());
190 // CacheGenerator::WriteStringInMap /*{{{*/
191 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
192 void const * const oldMap
= Map
.Data();
193 map_stringitem_t
const index
= Map
.WriteString(String
);
195 ReMap(oldMap
, Map
.Data());
199 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
200 void const * const oldMap
= Map
.Data();
201 map_pointer_t
const index
= Map
.Allocate(size
);
203 ReMap(oldMap
, Map
.Data());
207 // CacheGenerator::MergeList - Merge the package list /*{{{*/
208 // ---------------------------------------------------------------------
209 /* This provides the generation of the entries in the cache. Each loop
210 goes through a single package record from the underlying parse engine. */
211 bool pkgCacheGenerator::MergeList(ListParser
&List
,
212 pkgCache::VerIterator
*OutVer
)
216 unsigned int Counter
= 0;
217 while (List
.Step() == true)
219 string
const PackageName
= List
.Package();
220 if (PackageName
.empty() == true)
224 if (Counter
% 100 == 0 && Progress
!= 0)
225 Progress
->Progress(List
.Offset());
227 string Arch
= List
.Architecture();
228 string
const Version
= List
.Version();
229 if (Version
.empty() == true && Arch
.empty() == true)
231 // package descriptions
232 if (MergeListGroup(List
, PackageName
) == false)
237 // Get a pointer to the package structure
238 pkgCache::PkgIterator Pkg
;
239 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
240 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
241 // TRANSLATOR: The first placeholder is a package name,
242 // the other two should be copied verbatim as they include debug info
243 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
244 PackageName
.c_str(), "NewPackage", 1);
247 if (Version
.empty() == true)
249 if (MergeListPackage(List
, Pkg
) == false)
254 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
262 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
263 return _error
->Error(_("Wow, you exceeded the number of package "
264 "names this APT is capable of."));
265 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
266 return _error
->Error(_("Wow, you exceeded the number of versions "
267 "this APT is capable of."));
268 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
269 return _error
->Error(_("Wow, you exceeded the number of descriptions "
270 "this APT is capable of."));
271 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
272 return _error
->Error(_("Wow, you exceeded the number of dependencies "
273 "this APT is capable of."));
277 // CacheGenerator::MergeListGroup /*{{{*/
278 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
280 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
281 // a group has no data on it's own, only packages have it but these
282 // stanzas like this come from Translation- files to add descriptions,
283 // but without a version we don't need a description for it…
284 if (Grp
.end() == true)
286 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
288 pkgCache::PkgIterator Pkg
;
289 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
290 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
291 if (MergeListPackage(List
, Pkg
) == false)
297 // CacheGenerator::MergeListPackage /*{{{*/
298 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
300 // we first process the package, then the descriptions
301 // (for deb this package processing is in fact a no-op)
302 pkgCache::VerIterator
Ver(Cache
);
303 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
304 if (List
.UsePackage(Pkg
, Ver
) == false)
305 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
306 Pkg
.Name(), "UsePackage", 1);
308 // Find the right version to write the description
309 MD5SumValue CurMd5
= List
.Description_md5();
310 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
312 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
313 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
315 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
317 // a version can only have one md5 describing it
318 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
321 map_stringitem_t md5idx
= VerDesc
->md5sum
;
322 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
324 // don't add a new description if we have one for the given
326 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
329 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
332 // we can stop here as all "same" versions will share the description
339 // CacheGenerator::MergeListVersion /*{{{*/
340 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
341 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
343 pkgCache::VerIterator Ver
= Pkg
.VersionList();
344 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
345 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
346 void const * oldMap
= Map
.Data();
348 unsigned short const Hash
= List
.VersionHash();
349 if (Ver
.end() == false)
351 /* We know the list is sorted so we use that fact in the search.
352 Insertion of new versions is done with correct sorting */
354 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
356 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
357 // Version is higher as current version - insert here
360 // Versionstrings are equal - is hash also equal?
361 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
363 // proceed with the next till we have either the right
364 // or we found another version (which will be lower)
367 /* We already have a version for this item, record that we saw it */
368 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
370 if (List
.UsePackage(Pkg
,Ver
) == false)
371 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
372 Pkg
.Name(), "UsePackage", 2);
374 if (NewFileVer(Ver
,List
) == false)
375 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
376 Pkg
.Name(), "NewFileVer", 1);
378 // Read only a single record and return
390 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
391 if (unlikely(verindex
== 0))
392 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
393 Pkg
.Name(), "NewVersion", 1);
395 if (oldMap
!= Map
.Data())
396 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
399 if (unlikely(List
.NewVersion(Ver
) == false))
400 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
401 Pkg
.Name(), "NewVersion", 2);
403 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
404 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
405 Pkg
.Name(), "UsePackage", 3);
407 if (unlikely(NewFileVer(Ver
,List
) == false))
408 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
409 Pkg
.Name(), "NewFileVer", 2);
411 pkgCache::GrpIterator Grp
= Pkg
.Group();
412 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
414 /* If it is the first version of this package we need to add implicit
415 Multi-Arch dependencies to all other package versions in the group now -
416 otherwise we just add them for this new version */
417 if (Pkg
.VersionList()->NextVer
== 0)
419 pkgCache::PkgIterator P
= Grp
.PackageList();
420 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
421 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
423 if (P
->ID
== Pkg
->ID
)
425 pkgCache::VerIterator V
= P
.VersionList();
426 Dynamic
<pkgCache::VerIterator
> DynV(V
);
427 for (; V
.end() != true; ++V
)
428 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
429 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
430 Pkg
.Name(), "AddImplicitDepends", 1);
433 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
434 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
435 Pkg
.Name(), "AddImplicitDepends", 2);
437 // Read only a single record and return
444 /* Record the Description(s) based on their master md5sum */
445 MD5SumValue CurMd5
= List
.Description_md5();
446 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
449 /* Before we add a new description we first search in the group for
450 a version with a description of the same MD5 - if so we reuse this
451 description group instead of creating our own for this version */
452 for (pkgCache::PkgIterator P
= Grp
.PackageList();
453 P
.end() == false; P
= Grp
.NextPkg(P
))
455 for (pkgCache::VerIterator V
= P
.VersionList();
456 V
.end() == false; ++V
)
458 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
460 Ver
->DescriptionList
= V
->DescriptionList
;
464 // We haven't found reusable descriptions, so add the first description(s)
465 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
466 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
467 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
468 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
473 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
475 pkgCache::DescIterator Desc
;
476 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
478 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
479 if (unlikely(descindex
== 0))
480 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
481 Ver
.ParentPkg().Name(), "NewDescription", 1);
483 md5idx
= Desc
->md5sum
;
484 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
486 // we add at the end, so that the start is constant as we need
487 // that to be able to efficiently share these lists
488 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
489 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
490 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
491 *LastNextDesc
= descindex
;
493 if (NewFileDesc(Desc
,List
) == false)
494 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
495 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
501 // CacheGenerator::NewGroup - Add a new group /*{{{*/
502 // ---------------------------------------------------------------------
503 /* This creates a new group structure and adds it to the hash table */
504 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
506 Grp
= Cache
.FindGrp(Name
);
507 if (Grp
.end() == false)
511 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
512 if (unlikely(Group
== 0))
515 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
516 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
517 if (unlikely(idxName
== 0))
521 // Insert it into the hash table
522 unsigned long const Hash
= Cache
.Hash(Name
);
523 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
524 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
525 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
526 Grp
->Next
= *insertAt
;
529 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
533 // CacheGenerator::NewPackage - Add a new package /*{{{*/
534 // ---------------------------------------------------------------------
535 /* This creates a new package structure and adds it to the hash table */
536 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
537 const string
&Arch
) {
538 pkgCache::GrpIterator Grp
;
539 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
540 if (unlikely(NewGroup(Grp
, Name
) == false))
543 Pkg
= Grp
.FindPkg(Arch
);
544 if (Pkg
.end() == false)
548 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
549 if (unlikely(Package
== 0))
551 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
553 // Set the name, arch and the ID
554 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
555 Pkg
->Group
= Grp
.Index();
556 // all is mapped to the native architecture
557 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
558 if (unlikely(idxArch
== 0))
561 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
563 // Insert the package into our package list
564 if (Grp
->FirstPackage
== 0) // the group is new
566 Grp
->FirstPackage
= Package
;
567 // Insert it into the hash table
568 map_id_t
const Hash
= Cache
.Hash(Name
);
569 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
570 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
571 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
572 Pkg
->NextPackage
= *insertAt
;
575 else // Group the Packages together
577 // but first get implicit provides done
578 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
580 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
581 if (M
.end() == false) {
582 pkgCache::PrvIterator Prv
;
583 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
584 for (Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
586 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
588 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
589 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
590 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
591 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
592 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
593 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
599 pkgCache::PkgIterator P
;
600 pkgCache::VerIterator Ver
;
601 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
602 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
604 for (P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
605 for (Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
606 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
607 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
610 // and negative dependencies, don't forget negative dependencies
612 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
613 if (M
.end() == false) {
614 pkgCache::DepIterator Dep
;
615 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
616 for (Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
618 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
620 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
621 Dep
->Type
!= pkgCache::Dep::Replaces
)
623 pkgCache::VerIterator Ver
= Dep
.ParentVer();
624 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
625 map_pointer_t
* unused
= NULL
;
626 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
632 // this package is the new last package
633 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
634 Pkg
->NextPackage
= LastPkg
->NextPackage
;
635 LastPkg
->NextPackage
= Package
;
637 Grp
->LastPackage
= Package
;
639 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
642 size_t const found
= Name
.find(':');
643 std::string
const NameA
= Name
.substr(0, found
);
644 std::string
const ArchA
= Name
.substr(found
+ 1);
645 pkgCache::PkgIterator PkgA
= Cache
.FindPkg(NameA
, ArchA
);
646 if (PkgA
.end() == false)
648 Dynamic
<pkgCache::PkgIterator
> DynPkgA(PkgA
);
649 pkgCache::PrvIterator Prv
= PkgA
.ProvidesList();
650 for (; Prv
.end() == false; ++Prv
)
652 if (Prv
.IsMultiArchImplicit())
654 pkgCache::VerIterator V
= Prv
.OwnerVer();
655 if (ArchA
!= V
.ParentPkg().Arch())
657 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
660 pkgCache::VerIterator V
= PkgA
.VersionList();
661 Dynamic
<pkgCache::VerIterator
> DynV(V
);
662 for (; V
.end() == false; ++V
)
664 if (NewProvides(V
, Pkg
, V
->VerStr
, pkgCache::Flag::MultiArchImplicit
| pkgCache::Flag::ArchSpecific
) == false)
672 // CacheGenerator::AddImplicitDepends /*{{{*/
673 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
674 pkgCache::PkgIterator
&P
,
675 pkgCache::VerIterator
&V
)
677 // copy P.Arch() into a string here as a cache remap
678 // in NewDepends() later may alter the pointer location
679 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
680 map_pointer_t
*OldDepLast
= NULL
;
681 /* MultiArch handling introduces a lot of implicit Dependencies:
682 - MultiArch: same → Co-Installable if they have the same version
683 - All others conflict with all other group members */
684 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
685 pkgCache::PkgIterator D
= G
.PackageList();
686 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
687 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
688 for (; D
.end() != true; D
= G
.NextPkg(D
))
690 if (Arch
== D
.Arch() || D
->VersionList
== 0)
692 /* We allow only one installed arch at the time
693 per group, therefore each group member conflicts
694 with all other group members */
695 if (coInstall
== true)
697 // Replaces: ${self}:other ( << ${binary:Version})
698 NewDepends(D
, V
, VerStrIdx
,
699 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
701 // Breaks: ${self}:other (!= ${binary:Version})
702 NewDepends(D
, V
, VerStrIdx
,
703 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
706 // Conflicts: ${self}:other
708 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
714 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
715 pkgCache::PkgIterator
&D
)
717 /* MultiArch handling introduces a lot of implicit Dependencies:
718 - MultiArch: same → Co-Installable if they have the same version
719 - All others conflict with all other group members */
720 map_pointer_t
*OldDepLast
= NULL
;
721 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
722 if (coInstall
== true)
724 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
725 // Replaces: ${self}:other ( << ${binary:Version})
726 NewDepends(D
, V
, VerStrIdx
,
727 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
729 // Breaks: ${self}:other (!= ${binary:Version})
730 NewDepends(D
, V
, VerStrIdx
,
731 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
734 // Conflicts: ${self}:other
736 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
743 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
744 // ---------------------------------------------------------------------
746 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
749 if (CurrentFile
== 0)
753 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
757 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
758 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
760 // Link it to the end of the list
761 map_pointer_t
*Last
= &Ver
->FileList
;
762 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
764 VF
->NextFile
= *Last
;
767 VF
->Offset
= List
.Offset();
768 VF
->Size
= List
.Size();
769 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
770 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
771 Cache
.HeaderP
->VerFileCount
++;
776 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
777 // ---------------------------------------------------------------------
778 /* This puts a version structure in the linked list */
779 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
780 const string
&VerStr
,
781 map_pointer_t
const ParentPkg
,
782 unsigned short const Hash
,
783 map_pointer_t
const Next
)
786 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
791 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
792 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
794 Ver
->ParentPkg
= ParentPkg
;
796 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
798 // try to find the version string in the group for reuse
799 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
800 pkgCache::GrpIterator Grp
= Pkg
.Group();
801 if (Pkg
.end() == false && Grp
.end() == false)
803 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
807 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
809 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
812 Ver
->VerStr
= V
->VerStr
;
820 // haven't found the version string, so create
821 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
822 if (unlikely(idxVerStr
== 0))
824 Ver
->VerStr
= idxVerStr
;
828 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
829 // ---------------------------------------------------------------------
831 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
834 if (CurrentFile
== 0)
838 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
842 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
843 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
845 // Link it to the end of the list
846 map_pointer_t
*Last
= &Desc
->FileList
;
847 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
850 DF
->NextFile
= *Last
;
853 DF
->Offset
= List
.Offset();
854 DF
->Size
= List
.Size();
855 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
856 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
857 Cache
.HeaderP
->DescFileCount
++;
862 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
863 // ---------------------------------------------------------------------
864 /* This puts a description structure in the linked list */
865 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
867 const MD5SumValue
&md5sum
,
868 map_stringitem_t
const idxmd5str
)
871 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
872 if (Description
== 0)
876 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
877 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
878 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
879 if (unlikely(idxlanguage_code
== 0))
881 Desc
->language_code
= idxlanguage_code
;
884 Desc
->md5sum
= idxmd5str
;
887 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
888 if (unlikely(idxmd5sum
== 0))
890 Desc
->md5sum
= idxmd5sum
;
896 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
897 // ---------------------------------------------------------------------
898 /* This creates a dependency element in the tree. It is linked to the
899 version and to the package that it is pointing to. */
900 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
901 pkgCache::VerIterator
&Ver
,
902 map_pointer_t
const Version
,
905 map_pointer_t
* &OldDepLast
)
907 void const * const oldMap
= Map
.Data();
909 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
910 if (unlikely(Dependency
== 0))
913 bool isDuplicate
= false;
914 map_pointer_t DependencyData
= 0;
915 map_pointer_t PreviousData
= 0;
916 if (Pkg
->RevDepends
!= 0)
918 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
919 DependencyData
= L
->DependencyData
;
921 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
922 if (Version
> D
->Version
)
924 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
929 PreviousData
= DependencyData
;
930 DependencyData
= D
->NextData
;
931 } while (DependencyData
!= 0);
934 if (isDuplicate
== false)
936 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
937 if (unlikely(DependencyData
== 0))
941 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
942 Link
->ParentVer
= Ver
.Index();
943 Link
->DependencyData
= DependencyData
;
944 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
946 pkgCache::DepIterator
Dep(Cache
, Link
);
947 if (isDuplicate
== false)
951 Dep
->Version
= Version
;
952 Dep
->Package
= Pkg
.Index();
953 ++Cache
.HeaderP
->DependsDataCount
;
954 if (PreviousData
!= 0)
956 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
957 Dep
->NextData
= D
->NextData
;
958 D
->NextData
= DependencyData
;
960 else if (Pkg
->RevDepends
!= 0)
962 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
963 Dep
->NextData
= D
->DependencyData
;
967 if (isDuplicate
== true || PreviousData
!= 0)
969 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
970 Link
->NextRevDepends
= L
->NextRevDepends
;
971 L
->NextRevDepends
= Dependency
;
975 Link
->NextRevDepends
= Pkg
->RevDepends
;
976 Pkg
->RevDepends
= Dependency
;
980 // Do we know where to link the Dependency to?
981 if (OldDepLast
== NULL
)
983 OldDepLast
= &Ver
->DependsList
;
984 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
985 OldDepLast
= &D
->NextDepends
;
986 } else if (oldMap
!= Map
.Data())
987 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
989 Dep
->NextDepends
= *OldDepLast
;
990 *OldDepLast
= Dependency
;
991 OldDepLast
= &Dep
->NextDepends
;
995 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
996 // ---------------------------------------------------------------------
997 /* This creates a Group and the Package to link this dependency to if
998 needed and handles also the caching of the old endpoint */
999 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1000 const string
&PackageName
,
1002 const string
&Version
,
1006 pkgCache::GrpIterator Grp
;
1007 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1008 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1011 map_stringitem_t idxVersion
= 0;
1012 if (Version
.empty() == false)
1014 int const CmpOp
= Op
& 0x0F;
1015 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1016 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
1017 idxVersion
= Ver
->VerStr
;
1019 if (idxVersion
== 0)
1021 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1022 if (unlikely(idxVersion
== 0))
1027 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
1028 Type
== pkgCache::Dep::Conflicts
||
1029 Type
== pkgCache::Dep::Replaces
);
1031 pkgCache::PkgIterator Pkg
;
1032 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1033 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
1035 // Locate the target package
1036 Pkg
= Grp
.FindPkg(Arch
);
1037 if (Pkg
.end() == true) {
1038 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1042 /* Caching the old end point speeds up generation substantially */
1043 if (OldDepVer
!= Ver
) {
1048 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1052 /* Caching the old end point speeds up generation substantially */
1053 if (OldDepVer
!= Ver
) {
1058 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1060 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1067 // ListParser::NewProvides - Create a Provides element /*{{{*/
1068 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1069 const string
&PkgName
,
1070 const string
&PkgArch
,
1071 const string
&Version
,
1072 uint8_t const Flags
)
1074 pkgCache
const &Cache
= Owner
->Cache
;
1076 // We do not add self referencing provides
1077 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1078 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)) &&
1079 (Version
.empty() || Version
== Ver
.VerStr()))
1082 // Locate the target package
1083 pkgCache::PkgIterator Pkg
;
1084 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1085 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1088 map_stringitem_t idxProvideVersion
= 0;
1089 if (Version
.empty() == false) {
1090 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1091 if (unlikely(idxProvideVersion
== 0))
1094 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1096 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1097 pkgCache::PkgIterator
&Pkg
,
1098 map_pointer_t
const ProvideVersion
,
1099 uint8_t const Flags
)
1102 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1103 if (unlikely(Provides
== 0))
1105 ++Cache
.HeaderP
->ProvidesCount
;
1108 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1109 Prv
->Version
= Ver
.Index();
1110 Prv
->ProvideVersion
= ProvideVersion
;
1112 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1113 Ver
->ProvidesList
= Prv
.Index();
1115 // Link it to the package
1116 Prv
->ParentPkg
= Pkg
.Index();
1117 Prv
->NextProvides
= Pkg
->ProvidesList
;
1118 Pkg
->ProvidesList
= Prv
.Index();
1122 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1123 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, string
const &Package
,
1124 string
const &Version
, uint8_t const Flags
) {
1125 pkgCache
&Cache
= Owner
->Cache
;
1126 pkgCache::GrpIterator Grp
= Cache
.FindGrp(Package
);
1127 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1129 if (Grp
.end() == true)
1130 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1133 map_stringitem_t idxProvideVersion
= 0;
1134 if (Version
.empty() == false) {
1135 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1136 if (unlikely(idxProvideVersion
== 0))
1140 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1141 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1142 pkgCache::PkgIterator OwnerPkg
= Ver
.ParentPkg();
1143 Dynamic
<pkgCache::PkgIterator
> DynOwnerPkg(OwnerPkg
);
1144 pkgCache::PkgIterator Pkg
;
1145 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1146 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1148 if (isImplicit
&& OwnerPkg
== Pkg
)
1150 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1152 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1159 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1160 pkgCache::VerIterator
const &Ver
)
1162 return Hash
== Ver
->Hash
;
1165 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1166 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1167 unsigned long Flags
)
1169 if (File
.empty() && Site
.empty())
1171 CurrentRlsFile
= NULL
;
1175 // Get some space for the structure
1176 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1177 if (unlikely(idxFile
== 0))
1179 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1182 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1183 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1184 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1186 CurrentRlsFile
->FileName
= idxFileName
;
1187 CurrentRlsFile
->Site
= idxSite
;
1188 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1189 CurrentRlsFile
->Flags
= Flags
;
1190 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1192 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1193 Cache
.HeaderP
->ReleaseFileCount
++;
1198 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1199 // ---------------------------------------------------------------------
1200 /* This is used to select which file is to be associated with all newly
1201 added versions. The caller is responsible for setting the IMS fields. */
1202 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1203 pkgIndexFile
const &Index
,
1204 std::string
const &Architecture
,
1205 std::string
const &Component
,
1206 unsigned long const Flags
)
1208 // Get some space for the structure
1209 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1210 if (unlikely(idxFile
== 0))
1212 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1215 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1216 if (unlikely(idxFileName
== 0))
1218 CurrentFile
->FileName
= idxFileName
;
1219 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1220 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1221 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1222 if (unlikely(idxIndexType
== 0))
1224 CurrentFile
->IndexType
= idxIndexType
;
1225 if (Architecture
.empty())
1226 CurrentFile
->Architecture
= 0;
1229 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1230 if (unlikely(arch
== 0))
1232 CurrentFile
->Architecture
= arch
;
1234 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1235 if (unlikely(component
== 0))
1237 CurrentFile
->Component
= component
;
1238 CurrentFile
->Flags
= Flags
;
1239 if (CurrentRlsFile
!= NULL
)
1240 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1242 CurrentFile
->Release
= 0;
1244 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1245 Cache
.HeaderP
->PackageFileCount
++;
1248 Progress
->SubProgress(Index
.Size());
1252 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1253 // ---------------------------------------------------------------------
1254 /* This is used to create handles to strings. Given the same text it
1255 always returns the same number */
1256 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1259 std::string
const key(S
, Size
);
1261 std::unordered_map
<std::string
,map_stringitem_t
> * strings
;
1263 case MIXED
: strings
= &strMixed
; break;
1264 case PKGNAME
: strings
= &strPkgNames
; break;
1265 case VERSIONNUMBER
: strings
= &strVersions
; break;
1266 case SECTION
: strings
= &strSections
; break;
1267 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1270 std::unordered_map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1271 if (item
!= strings
->end())
1272 return item
->second
;
1274 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1275 strings
->insert(std::make_pair(key
, idxString
));
1279 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1280 // ---------------------------------------------------------------------
1281 /* This just verifies that each file in the list of index files exists,
1282 has matching attributes with the cache and the cache does not have
1284 class APT_HIDDEN ScopedErrorRevert
{
1286 ScopedErrorRevert() { _error
->PushToStack(); }
1287 ~ScopedErrorRevert() { _error
->RevertToStack(); }
1289 static bool CheckValidity(const string
&CacheFile
,
1290 pkgSourceList
&List
,
1291 FileIterator
const Start
,
1292 FileIterator
const End
,
1294 pkgCache
**OutCache
= 0)
1296 ScopedErrorRevert ser
;
1297 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1298 // No file, certainly invalid
1299 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1302 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1306 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1309 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1314 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1315 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1316 if (unlikely(Map
->validData()) == false)
1318 std::unique_ptr
<pkgCache
> CacheP(new pkgCache(Map
.get()));
1319 pkgCache
&Cache
= *CacheP
.get();
1320 if (_error
->PendingError() || Map
->Size() == 0)
1323 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1327 std::unique_ptr
<bool[]> RlsVisited(new bool[Cache
.HeaderP
->ReleaseFileCount
]);
1328 memset(RlsVisited
.get(),0,sizeof(RlsVisited
[0])*Cache
.HeaderP
->ReleaseFileCount
);
1329 std::vector
<pkgIndexFile
*> Files
;
1330 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1333 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1334 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1335 if (RlsFile
.end() == true)
1338 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1342 RlsVisited
[RlsFile
->ID
] = true;
1344 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1346 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1347 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1348 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1350 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1351 if (RlsVisited
[I
] == false)
1354 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1358 std::copy(Start
, End
, std::back_inserter(Files
));
1360 /* Now we check every index file, see if it is in the cache,
1361 verify the IMS data and check that it is on the disk too.. */
1362 std::unique_ptr
<bool[]> Visited(new bool[Cache
.HeaderP
->PackageFileCount
]);
1363 memset(Visited
.get(),0,sizeof(Visited
[0])*Cache
.HeaderP
->PackageFileCount
);
1364 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1367 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1368 if ((*PkgFile
)->Exists() == false)
1371 std::clog
<< "file doesn't exist" << std::endl
;
1375 // FindInCache is also expected to do an IMS check.
1376 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1377 if (File
.end() == true)
1380 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1384 Visited
[File
->ID
] = true;
1386 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1389 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1390 if (Visited
[I
] == false)
1393 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1397 if (_error
->PendingError() == true)
1401 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1402 _error
->DumpErrors(std::clog
, GlobalError::DEBUG
, false);
1408 *OutMap
= Map
.release();
1410 *OutCache
= CacheP
.release();
1414 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1415 // ---------------------------------------------------------------------
1416 /* Size is kind of an abstract notion that is only used for the progress
1418 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1420 map_filesize_t TotalSize
= 0;
1423 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1425 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1426 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1427 if ((*j
)->HasPackages() == true)
1428 TotalSize
+= (*j
)->Size();
1432 for (; Start
< End
; ++Start
)
1434 if ((*Start
)->HasPackages() == false)
1436 TotalSize
+= (*Start
)->Size();
1441 // BuildCache - Merge the list of index files into the cache /*{{{*/
1442 static bool BuildCache(pkgCacheGenerator
&Gen
,
1443 OpProgress
* const Progress
,
1444 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1445 pkgSourceList
const * const List
,
1446 FileIterator
const Start
, FileIterator
const End
)
1448 bool mergeFailure
= false;
1450 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1451 if (I
->HasPackages() == false || mergeFailure
)
1454 if (I
->Exists() == false)
1457 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1459 _error
->Warning("Duplicate sources.list entry %s",
1460 I
->Describe().c_str());
1464 map_filesize_t
const Size
= I
->Size();
1465 if (Progress
!= NULL
)
1466 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1467 CurrentSize
+= Size
;
1469 if (I
->Merge(Gen
,Progress
) == false)
1470 mergeFailure
= true;
1475 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1477 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1479 _error
->Warning("Duplicate sources.list entry %s",
1480 (*i
)->Describe().c_str());
1484 if ((*i
)->Merge(Gen
, Progress
) == false)
1487 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1488 if (Indexes
!= NULL
)
1489 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1497 Gen
.SelectReleaseFile("", "");
1498 std::for_each(Start
, End
, indexFileMerge
);
1505 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1506 // ---------------------------------------------------------------------
1507 /* This makes sure that the status cache (the cache that has all
1508 index files from the sources list and all local ones) is ready
1509 to be mmaped. If OutMap is not zero then a MMap object representing
1510 the cache will be stored there. This is pretty much mandetory if you
1511 are using AllowMem. AllowMem lets the function be run as non-root
1512 where it builds the cache 'fast' into a memory buffer. */
1513 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1515 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1516 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1517 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1518 Flags
|= MMap::Moveable
;
1519 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1520 Flags
|= MMap::Fallback
;
1522 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1524 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1526 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1527 std::string
const &FileName
)
1529 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1530 if (SCacheF
.IsOpen() == false || SCacheF
.Failed())
1533 fchmod(SCacheF
.Fd(),0644);
1535 // Write out the main data
1536 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1537 return _error
->Error(_("IO Error saving source cache"));
1539 // Write out the proper header
1540 Gen
->GetCache().HeaderP
->Dirty
= false;
1541 Gen
->GetCache().HeaderP
->CacheFileSize
= Gen
->GetCache().CacheHash();
1542 if (SCacheF
.Seek(0) == false ||
1543 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1544 return _error
->Error(_("IO Error saving source cache"));
1545 Gen
->GetCache().HeaderP
->Dirty
= true;
1548 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1549 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1551 Map
.reset(CreateDynamicMMap(NULL
, 0));
1552 if (unlikely(Map
->validData()) == false)
1554 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1555 if (CacheF
.IsOpen() == false || CacheF
.Failed())
1557 _error
->PushToStack();
1558 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1559 bool const newError
= _error
->PendingError();
1560 _error
->MergeWithStack();
1561 if (alloc
== 0 && newError
)
1563 if (CacheF
.Read((unsigned char *)Map
->Data() + alloc
, CacheF
.Size()) == false)
1565 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1568 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1569 MMap
**OutMap
, bool AllowMem
)
1570 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1571 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1574 return pkgCacheGenerator::MakeStatusCache(List
, Progress
, OutMap
, nullptr, true);
1576 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1577 MMap
**OutMap
,pkgCache
**OutCache
, bool)
1579 // FIXME: deprecate the ignored AllowMem parameter
1580 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1582 std::vector
<pkgIndexFile
*> Files
;
1583 if (_system
->AddStatusFiles(Files
) == false)
1586 // Decide if we can write to the files..
1587 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1588 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1590 // ensure the cache directory exists
1591 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1593 string dir
= _config
->FindDir("Dir::Cache");
1594 size_t const len
= dir
.size();
1595 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1596 dir
= dir
.substr(0, len
- 5);
1597 if (CacheFile
.empty() == false)
1598 CreateDirectory(dir
, flNotFile(CacheFile
));
1599 if (SrcCacheFile
.empty() == false)
1600 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1603 if (Progress
!= NULL
)
1604 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1606 bool pkgcache_fine
= false;
1607 bool srcpkgcache_fine
= false;
1608 bool volatile_fine
= List
.GetVolatileFiles().empty();
1610 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
,
1611 volatile_fine
? OutCache
: NULL
) == true)
1614 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1615 pkgcache_fine
= true;
1616 srcpkgcache_fine
= true;
1618 if (pkgcache_fine
== false)
1620 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1623 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1624 srcpkgcache_fine
= true;
1628 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1630 if (Progress
!= NULL
)
1631 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1635 bool Writeable
= false;
1636 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1638 if (CacheFile
.empty() == false)
1639 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1640 else if (SrcCacheFile
.empty() == false)
1641 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1644 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1647 // At this point we know we need to construct something, so get storage ready
1648 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1649 if (unlikely(Map
->validData()) == false)
1652 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1654 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1655 map_filesize_t CurrentSize
= 0;
1656 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1657 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1658 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1661 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1662 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1664 srcpkgcache_fine
= true;
1665 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1667 else if (srcpkgcache_fine
== false)
1670 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1671 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1673 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1674 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1675 Files
.end(),Files
.end()) == false)
1678 if (Writeable
== true && SrcCacheFile
.empty() == false)
1679 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1683 if (pkgcache_fine
== false)
1686 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1687 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1688 Files
.begin(), Files
.end()) == false)
1691 if (Writeable
== true && CacheFile
.empty() == false)
1692 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1697 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1699 if (volatile_fine
== false)
1704 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1705 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1709 Files
= List
.GetVolatileFiles();
1710 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1711 Files
.begin(), Files
.end()) == false)
1715 if (OutMap
!= nullptr)
1716 *OutMap
= Map
.release();
1719 std::clog
<< "Everything is ready for shipping" << std::endl
;
1723 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1724 class APT_HIDDEN ScopedErrorMerge
{
1726 ScopedErrorMerge() { _error
->PushToStack(); }
1727 ~ScopedErrorMerge() { _error
->MergeWithStack(); }
1729 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1730 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1731 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1733 std::vector
<pkgIndexFile
*> Files
;
1734 if (_system
->AddStatusFiles(Files
) == false)
1737 ScopedErrorMerge sem
;
1738 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1739 if (unlikely(Map
->validData()) == false)
1741 map_filesize_t CurrentSize
= 0;
1742 map_filesize_t TotalSize
= 0;
1743 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1745 // Build the status cache
1746 if (Progress
!= NULL
)
1747 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1748 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1749 if (_error
->PendingError() == true)
1751 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1752 Files
.begin(), Files
.end()) == false)
1755 if (_error
->PendingError() == true)
1757 *OutMap
= Map
.release();
1762 // IsDuplicateDescription /*{{{*/
1763 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1764 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1766 // Descriptions in the same link-list have all the same md5
1767 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1769 for (; Desc
.end() == false; ++Desc
)
1770 if (Desc
.LanguageCode() == CurLang
)
1776 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1777 pkgCacheListParser::~pkgCacheListParser() {}