1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
12 // Include Files /*{{{*/
15 #include <apt-pkg/pkgcachegen.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/version.h>
18 #include <apt-pkg/progress.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/sptr.h>
23 #include <apt-pkg/pkgsystem.h>
24 #include <apt-pkg/macros.h>
25 #include <apt-pkg/metaindex.h>
26 #include <apt-pkg/fileutl.h>
27 #include <apt-pkg/hashsum_template.h>
28 #include <apt-pkg/indexfile.h>
29 #include <apt-pkg/md5.h>
30 #include <apt-pkg/mmap.h>
31 #include <apt-pkg/pkgcache.h>
32 #include <apt-pkg/cacheiterators.h>
46 template<class T
> using Dynamic
= pkgCacheGenerator::Dynamic
<T
>; /*}}}*/
47 typedef std::vector
<pkgIndexFile
*>::iterator FileIterator
;
48 template <typename Iter
> std::vector
<Iter
*> pkgCacheGenerator::Dynamic
<Iter
>::toReMap
;
50 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
51 MD5SumValue
const &CurMd5
, std::string
const &CurLang
);
55 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
56 // ---------------------------------------------------------------------
57 /* We set the dirty flag and make sure that is written to the disk */
58 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
59 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
60 CurrentRlsFile(NULL
), CurrentFile(NULL
), d(NULL
)
62 if (_error
->PendingError() == true)
67 // Setup the map interface..
68 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
69 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
72 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
75 *Cache
.HeaderP
= pkgCache::Header();
77 // make room for the hashtables for packages and groups
78 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
81 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
82 if (unlikely(idxVerSysName
== 0))
84 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
85 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
86 if (unlikely(idxArchitecture
== 0))
88 Cache
.HeaderP
->Architecture
= idxArchitecture
;
90 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
93 std::vector
<std::string
>::const_iterator a
= archs
.begin();
94 std::string list
= *a
;
95 for (++a
; a
!= archs
.end(); ++a
)
96 list
.append(",").append(*a
);
97 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
98 if (unlikely(idxArchitectures
== 0))
100 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
103 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
109 // Map directly from the existing file
111 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
112 if (Cache
.VS
!= _system
->VS
)
114 _error
->Error(_("Cache has an incompatible versioning system"));
119 Cache
.HeaderP
->Dirty
= true;
120 Map
.Sync(0,sizeof(pkgCache::Header
));
123 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
124 // ---------------------------------------------------------------------
125 /* We sync the data then unset the dirty flag in two steps so as to
126 advoid a problem during a crash */
127 pkgCacheGenerator::~pkgCacheGenerator()
129 if (_error
->PendingError() == true)
131 if (Map
.Sync() == false)
134 Cache
.HeaderP
->Dirty
= false;
135 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
136 Map
.Sync(0,sizeof(pkgCache::Header
));
139 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
140 if (oldMap
== newMap
)
143 if (_config
->FindB("Debug::pkgCacheGen", false))
144 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
148 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
149 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
151 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
152 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
153 (*i
)->ReMap(oldMap
, newMap
);
154 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
155 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
156 (*i
)->ReMap(oldMap
, newMap
);
157 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
158 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
159 (*i
)->ReMap(oldMap
, newMap
);
160 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
161 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
162 (*i
)->ReMap(oldMap
, newMap
);
163 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
164 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
165 (*i
)->ReMap(oldMap
, newMap
);
166 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
167 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
168 (*i
)->ReMap(oldMap
, newMap
);
169 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
170 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
171 (*i
)->ReMap(oldMap
, newMap
);
172 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
173 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
174 (*i
)->ReMap(oldMap
, newMap
);
176 // CacheGenerator::WriteStringInMap /*{{{*/
177 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
178 const unsigned long &Len
) {
179 void const * const oldMap
= Map
.Data();
180 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
182 ReMap(oldMap
, Map
.Data());
186 // CacheGenerator::WriteStringInMap /*{{{*/
187 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
188 void const * const oldMap
= Map
.Data();
189 map_stringitem_t
const index
= Map
.WriteString(String
);
191 ReMap(oldMap
, Map
.Data());
195 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
196 void const * const oldMap
= Map
.Data();
197 map_pointer_t
const index
= Map
.Allocate(size
);
199 ReMap(oldMap
, Map
.Data());
203 // CacheGenerator::MergeList - Merge the package list /*{{{*/
204 // ---------------------------------------------------------------------
205 /* This provides the generation of the entries in the cache. Each loop
206 goes through a single package record from the underlying parse engine. */
207 bool pkgCacheGenerator::MergeList(ListParser
&List
,
208 pkgCache::VerIterator
*OutVer
)
212 unsigned int Counter
= 0;
213 while (List
.Step() == true)
215 string
const PackageName
= List
.Package();
216 if (PackageName
.empty() == true)
220 if (Counter
% 100 == 0 && Progress
!= 0)
221 Progress
->Progress(List
.Offset());
223 string Arch
= List
.Architecture();
224 string
const Version
= List
.Version();
225 if (Version
.empty() == true && Arch
.empty() == true)
227 // package descriptions
228 if (MergeListGroup(List
, PackageName
) == false)
233 // Get a pointer to the package structure
234 pkgCache::PkgIterator Pkg
;
235 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
236 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
237 // TRANSLATOR: The first placeholder is a package name,
238 // the other two should be copied verbatim as they include debug info
239 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
240 PackageName
.c_str(), "NewPackage", 1);
243 if (Version
.empty() == true)
245 if (MergeListPackage(List
, Pkg
) == false)
250 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
258 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
259 return _error
->Error(_("Wow, you exceeded the number of package "
260 "names this APT is capable of."));
261 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
262 return _error
->Error(_("Wow, you exceeded the number of versions "
263 "this APT is capable of."));
264 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
265 return _error
->Error(_("Wow, you exceeded the number of descriptions "
266 "this APT is capable of."));
267 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
268 return _error
->Error(_("Wow, you exceeded the number of dependencies "
269 "this APT is capable of."));
273 // CacheGenerator::MergeListGroup /*{{{*/
274 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
276 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
277 // a group has no data on it's own, only packages have it but these
278 // stanzas like this come from Translation- files to add descriptions,
279 // but without a version we don't need a description for it…
280 if (Grp
.end() == true)
282 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
284 pkgCache::PkgIterator Pkg
;
285 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
286 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
287 if (MergeListPackage(List
, Pkg
) == false)
293 // CacheGenerator::MergeListPackage /*{{{*/
294 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
296 // we first process the package, then the descriptions
297 // (for deb this package processing is in fact a no-op)
298 pkgCache::VerIterator
Ver(Cache
);
299 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
300 if (List
.UsePackage(Pkg
, Ver
) == false)
301 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
302 Pkg
.Name(), "UsePackage", 1);
304 // Find the right version to write the description
305 MD5SumValue CurMd5
= List
.Description_md5();
306 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
308 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
309 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
311 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
313 // a version can only have one md5 describing it
314 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
317 map_stringitem_t md5idx
= VerDesc
->md5sum
;
318 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
320 // don't add a new description if we have one for the given
322 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
325 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
328 // we can stop here as all "same" versions will share the description
335 // CacheGenerator::MergeListVersion /*{{{*/
336 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
337 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
339 pkgCache::VerIterator Ver
= Pkg
.VersionList();
340 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
341 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
342 void const * oldMap
= Map
.Data();
344 unsigned short const Hash
= List
.VersionHash();
345 if (Ver
.end() == false)
347 /* We know the list is sorted so we use that fact in the search.
348 Insertion of new versions is done with correct sorting */
350 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
352 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
353 // Version is higher as current version - insert here
356 // Versionstrings are equal - is hash also equal?
357 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
359 // proceed with the next till we have either the right
360 // or we found another version (which will be lower)
363 /* We already have a version for this item, record that we saw it */
364 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
366 if (List
.UsePackage(Pkg
,Ver
) == false)
367 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
368 Pkg
.Name(), "UsePackage", 2);
370 if (NewFileVer(Ver
,List
) == false)
371 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
372 Pkg
.Name(), "NewFileVer", 1);
374 // Read only a single record and return
386 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
387 if (verindex
== 0 && _error
->PendingError())
388 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
389 Pkg
.Name(), "NewVersion", 1);
391 if (oldMap
!= Map
.Data())
392 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
395 if (unlikely(List
.NewVersion(Ver
) == false))
396 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
397 Pkg
.Name(), "NewVersion", 2);
399 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
400 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
401 Pkg
.Name(), "UsePackage", 3);
403 if (unlikely(NewFileVer(Ver
,List
) == false))
404 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
405 Pkg
.Name(), "NewFileVer", 2);
407 pkgCache::GrpIterator Grp
= Pkg
.Group();
408 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
410 /* If it is the first version of this package we need to add implicit
411 Multi-Arch dependencies to all other package versions in the group now -
412 otherwise we just add them for this new version */
413 if (Pkg
.VersionList()->NextVer
== 0)
415 pkgCache::PkgIterator P
= Grp
.PackageList();
416 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
417 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
419 if (P
->ID
== Pkg
->ID
)
421 pkgCache::VerIterator V
= P
.VersionList();
422 Dynamic
<pkgCache::VerIterator
> DynV(V
);
423 for (; V
.end() != true; ++V
)
424 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
425 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
426 Pkg
.Name(), "AddImplicitDepends", 1);
429 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
430 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
431 Pkg
.Name(), "AddImplicitDepends", 2);
433 // Read only a single record and return
440 /* Record the Description(s) based on their master md5sum */
441 MD5SumValue CurMd5
= List
.Description_md5();
442 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
445 /* Before we add a new description we first search in the group for
446 a version with a description of the same MD5 - if so we reuse this
447 description group instead of creating our own for this version */
448 for (pkgCache::PkgIterator P
= Grp
.PackageList();
449 P
.end() == false; P
= Grp
.NextPkg(P
))
451 for (pkgCache::VerIterator V
= P
.VersionList();
452 V
.end() == false; ++V
)
454 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
456 Ver
->DescriptionList
= V
->DescriptionList
;
460 // We haven't found reusable descriptions, so add the first description(s)
461 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
462 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
463 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
464 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
469 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
471 pkgCache::DescIterator Desc
;
472 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
474 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
475 if (unlikely(descindex
== 0 && _error
->PendingError()))
476 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
477 Ver
.ParentPkg().Name(), "NewDescription", 1);
479 md5idx
= Desc
->md5sum
;
480 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
482 // we add at the end, so that the start is constant as we need
483 // that to be able to efficiently share these lists
484 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
485 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
486 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
487 *LastNextDesc
= descindex
;
489 if (NewFileDesc(Desc
,List
) == false)
490 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
491 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
497 // CacheGenerator::NewGroup - Add a new group /*{{{*/
498 // ---------------------------------------------------------------------
499 /* This creates a new group structure and adds it to the hash table */
500 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
502 Grp
= Cache
.FindGrp(Name
);
503 if (Grp
.end() == false)
507 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
508 if (unlikely(Group
== 0))
511 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
512 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
513 if (unlikely(idxName
== 0))
517 // Insert it into the hash table
518 unsigned long const Hash
= Cache
.Hash(Name
);
519 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
520 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
521 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
522 Grp
->Next
= *insertAt
;
525 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
529 // CacheGenerator::NewPackage - Add a new package /*{{{*/
530 // ---------------------------------------------------------------------
531 /* This creates a new package structure and adds it to the hash table */
532 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
533 const string
&Arch
) {
534 pkgCache::GrpIterator Grp
;
535 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
536 if (unlikely(NewGroup(Grp
, Name
) == false))
539 Pkg
= Grp
.FindPkg(Arch
);
540 if (Pkg
.end() == false)
544 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
545 if (unlikely(Package
== 0))
547 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
549 // Set the name, arch and the ID
550 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
551 Pkg
->Group
= Grp
.Index();
552 // all is mapped to the native architecture
553 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
554 if (unlikely(idxArch
== 0))
557 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
559 // Insert the package into our package list
560 if (Grp
->FirstPackage
== 0) // the group is new
562 Grp
->FirstPackage
= Package
;
563 // Insert it into the hash table
564 map_id_t
const Hash
= Cache
.Hash(Name
);
565 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
566 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
567 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
568 Pkg
->NextPackage
= *insertAt
;
571 else // Group the Packages together
573 // but first get implicit provides done
574 if (APT::Configuration::checkArchitecture(Pkg
.Arch()) == true)
576 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false); // native or any foreign pkg will do
577 if (M
.end() == false)
578 for (pkgCache::PrvIterator Prv
= M
.ProvidesList(); Prv
.end() == false; ++Prv
)
580 if ((Prv
->Flags
& pkgCache::Flag::ArchSpecific
) != 0)
582 pkgCache::VerIterator Ver
= Prv
.OwnerVer();
583 if ((Ver
->MultiArch
& pkgCache::Version::Allowed
) == pkgCache::Version::Allowed
||
584 ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
&&
585 (Prv
->Flags
& pkgCache::Flag::MultiArchImplicit
) == 0))
586 if (NewProvides(Ver
, Pkg
, Prv
->ProvideVersion
, Prv
->Flags
) == false)
590 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
591 for (pkgCache::VerIterator Ver
= P
.VersionList(); Ver
.end() == false; ++Ver
)
592 if ((Ver
->MultiArch
& pkgCache::Version::Foreign
) == pkgCache::Version::Foreign
)
593 if (NewProvides(Ver
, Pkg
, Ver
->VerStr
, pkgCache::Flag::MultiArchImplicit
) == false)
596 // and negative dependencies, don't forget negative dependencies
598 pkgCache::PkgIterator
const M
= Grp
.FindPreferredPkg(false);
599 if (M
.end() == false)
600 for (pkgCache::DepIterator Dep
= M
.RevDependsList(); Dep
.end() == false; ++Dep
)
602 if ((Dep
->CompareOp
& (pkgCache::Dep::ArchSpecific
| pkgCache::Dep::MultiArchImplicit
)) != 0)
604 if (Dep
->Type
!= pkgCache::Dep::DpkgBreaks
&& Dep
->Type
!= pkgCache::Dep::Conflicts
&&
605 Dep
->Type
!= pkgCache::Dep::Replaces
)
607 pkgCache::VerIterator Ver
= Dep
.ParentVer();
608 map_pointer_t
* unused
= NULL
;
609 if (NewDepends(Pkg
, Ver
, Dep
->Version
, Dep
->CompareOp
, Dep
->Type
, unused
) == false)
614 // this package is the new last package
615 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
616 Pkg
->NextPackage
= LastPkg
->NextPackage
;
617 LastPkg
->NextPackage
= Package
;
619 Grp
->LastPackage
= Package
;
623 // CacheGenerator::AddImplicitDepends /*{{{*/
624 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
625 pkgCache::PkgIterator
&P
,
626 pkgCache::VerIterator
&V
)
628 // copy P.Arch() into a string here as a cache remap
629 // in NewDepends() later may alter the pointer location
630 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
631 map_pointer_t
*OldDepLast
= NULL
;
632 /* MultiArch handling introduces a lot of implicit Dependencies:
633 - MultiArch: same → Co-Installable if they have the same version
634 - All others conflict with all other group members */
635 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
636 pkgCache::PkgIterator D
= G
.PackageList();
637 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
638 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
639 for (; D
.end() != true; D
= G
.NextPkg(D
))
641 if (Arch
== D
.Arch() || D
->VersionList
== 0)
643 /* We allow only one installed arch at the time
644 per group, therefore each group member conflicts
645 with all other group members */
646 if (coInstall
== true)
648 // Replaces: ${self}:other ( << ${binary:Version})
649 NewDepends(D
, V
, VerStrIdx
,
650 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
652 // Breaks: ${self}:other (!= ${binary:Version})
653 NewDepends(D
, V
, VerStrIdx
,
654 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
657 // Conflicts: ${self}:other
659 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
665 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
666 pkgCache::PkgIterator
&D
)
668 /* MultiArch handling introduces a lot of implicit Dependencies:
669 - MultiArch: same → Co-Installable if they have the same version
670 - All others conflict with all other group members */
671 map_pointer_t
*OldDepLast
= NULL
;
672 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
673 if (coInstall
== true)
675 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
676 // Replaces: ${self}:other ( << ${binary:Version})
677 NewDepends(D
, V
, VerStrIdx
,
678 pkgCache::Dep::Less
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Replaces
,
680 // Breaks: ${self}:other (!= ${binary:Version})
681 NewDepends(D
, V
, VerStrIdx
,
682 pkgCache::Dep::NotEquals
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::DpkgBreaks
,
685 // Conflicts: ${self}:other
687 pkgCache::Dep::NoOp
| pkgCache::Dep::MultiArchImplicit
, pkgCache::Dep::Conflicts
,
694 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
695 // ---------------------------------------------------------------------
697 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
700 if (CurrentFile
== 0)
704 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
708 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
709 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
711 // Link it to the end of the list
712 map_pointer_t
*Last
= &Ver
->FileList
;
713 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
715 VF
->NextFile
= *Last
;
718 VF
->Offset
= List
.Offset();
719 VF
->Size
= List
.Size();
720 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
721 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
722 Cache
.HeaderP
->VerFileCount
++;
727 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
728 // ---------------------------------------------------------------------
729 /* This puts a version structure in the linked list */
730 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
731 const string
&VerStr
,
732 map_pointer_t
const ParentPkg
,
733 unsigned short const Hash
,
734 map_pointer_t
const Next
)
737 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
742 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
743 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
745 Ver
->ParentPkg
= ParentPkg
;
747 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
749 // try to find the version string in the group for reuse
750 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
751 pkgCache::GrpIterator Grp
= Pkg
.Group();
752 if (Pkg
.end() == false && Grp
.end() == false)
754 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
758 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
760 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
763 Ver
->VerStr
= V
->VerStr
;
771 // haven't found the version string, so create
772 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
773 if (unlikely(idxVerStr
== 0))
775 Ver
->VerStr
= idxVerStr
;
779 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
780 // ---------------------------------------------------------------------
782 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
785 if (CurrentFile
== 0)
789 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
793 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
794 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
796 // Link it to the end of the list
797 map_pointer_t
*Last
= &Desc
->FileList
;
798 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
801 DF
->NextFile
= *Last
;
804 DF
->Offset
= List
.Offset();
805 DF
->Size
= List
.Size();
806 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
807 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
808 Cache
.HeaderP
->DescFileCount
++;
813 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
814 // ---------------------------------------------------------------------
815 /* This puts a description structure in the linked list */
816 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
818 const MD5SumValue
&md5sum
,
819 map_stringitem_t
const idxmd5str
)
822 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
823 if (Description
== 0)
827 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
828 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
829 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
830 if (unlikely(idxlanguage_code
== 0))
832 Desc
->language_code
= idxlanguage_code
;
835 Desc
->md5sum
= idxmd5str
;
838 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
839 if (unlikely(idxmd5sum
== 0))
841 Desc
->md5sum
= idxmd5sum
;
847 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
848 // ---------------------------------------------------------------------
849 /* This creates a dependency element in the tree. It is linked to the
850 version and to the package that it is pointing to. */
851 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
852 pkgCache::VerIterator
&Ver
,
853 map_pointer_t
const Version
,
856 map_pointer_t
* &OldDepLast
)
858 void const * const oldMap
= Map
.Data();
860 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
861 if (unlikely(Dependency
== 0))
864 bool isDuplicate
= false;
865 map_pointer_t DependencyData
= 0;
866 map_pointer_t PreviousData
= 0;
867 if (Pkg
->RevDepends
!= 0)
869 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
870 DependencyData
= L
->DependencyData
;
872 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
873 if (Version
> D
->Version
)
875 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
880 PreviousData
= DependencyData
;
881 DependencyData
= D
->NextData
;
882 } while (DependencyData
!= 0);
885 if (isDuplicate
== false)
887 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
888 if (unlikely(DependencyData
== 0))
892 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
893 Link
->ParentVer
= Ver
.Index();
894 Link
->DependencyData
= DependencyData
;
895 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
897 pkgCache::DepIterator
Dep(Cache
, Link
);
898 if (isDuplicate
== false)
902 Dep
->Version
= Version
;
903 Dep
->Package
= Pkg
.Index();
904 ++Cache
.HeaderP
->DependsDataCount
;
905 if (PreviousData
!= 0)
907 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
908 Dep
->NextData
= D
->NextData
;
909 D
->NextData
= DependencyData
;
911 else if (Pkg
->RevDepends
!= 0)
913 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
914 Dep
->NextData
= D
->DependencyData
;
918 if (isDuplicate
== true || PreviousData
!= 0)
920 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
921 Link
->NextRevDepends
= L
->NextRevDepends
;
922 L
->NextRevDepends
= Dependency
;
926 Link
->NextRevDepends
= Pkg
->RevDepends
;
927 Pkg
->RevDepends
= Dependency
;
931 // Do we know where to link the Dependency to?
932 if (OldDepLast
== NULL
)
934 OldDepLast
= &Ver
->DependsList
;
935 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
936 OldDepLast
= &D
->NextDepends
;
937 } else if (oldMap
!= Map
.Data())
938 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
940 Dep
->NextDepends
= *OldDepLast
;
941 *OldDepLast
= Dependency
;
942 OldDepLast
= &Dep
->NextDepends
;
946 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
947 // ---------------------------------------------------------------------
948 /* This creates a Group and the Package to link this dependency to if
949 needed and handles also the caching of the old endpoint */
950 bool pkgCacheListParser::NewDepends(pkgCache::VerIterator
&Ver
,
951 const string
&PackageName
,
953 const string
&Version
,
957 pkgCache::GrpIterator Grp
;
958 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
959 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
962 map_stringitem_t idxVersion
= 0;
963 if (Version
.empty() == false)
965 int const CmpOp
= Op
& 0x0F;
966 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
967 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
968 idxVersion
= Ver
->VerStr
;
972 idxVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
973 if (unlikely(idxVersion
== 0))
978 bool const isNegative
= (Type
== pkgCache::Dep::DpkgBreaks
||
979 Type
== pkgCache::Dep::Conflicts
||
980 Type
== pkgCache::Dep::Replaces
);
982 pkgCache::PkgIterator Pkg
;
983 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
984 if (isNegative
== false || (Op
& pkgCache::Dep::ArchSpecific
) == pkgCache::Dep::ArchSpecific
|| Grp
->FirstPackage
== 0)
986 // Locate the target package
987 Pkg
= Grp
.FindPkg(Arch
);
988 if (Pkg
.end() == true) {
989 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
993 /* Caching the old end point speeds up generation substantially */
994 if (OldDepVer
!= Ver
) {
999 return Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
);
1003 /* Caching the old end point speeds up generation substantially */
1004 if (OldDepVer
!= Ver
) {
1009 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1011 if (Owner
->NewDepends(Pkg
, Ver
, idxVersion
, Op
, Type
, OldDepLast
) == false)
1018 // ListParser::NewProvides - Create a Provides element /*{{{*/
1019 bool pkgCacheListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1020 const string
&PkgName
,
1021 const string
&PkgArch
,
1022 const string
&Version
,
1023 uint8_t const Flags
)
1025 pkgCache
const &Cache
= Owner
->Cache
;
1027 // We do not add self referencing provides
1028 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1029 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1032 // Locate the target package
1033 pkgCache::PkgIterator Pkg
;
1034 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1035 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1038 map_stringitem_t idxProvideVersion
= 0;
1039 if (Version
.empty() == false) {
1040 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1041 if (unlikely(idxProvideVersion
== 0))
1044 return Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
);
1046 bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator
&Ver
,
1047 pkgCache::PkgIterator
&Pkg
,
1048 map_pointer_t
const ProvideVersion
,
1049 uint8_t const Flags
)
1052 map_pointer_t
const Provides
= AllocateInMap(sizeof(pkgCache::Provides
));
1053 if (unlikely(Provides
== 0))
1055 ++Cache
.HeaderP
->ProvidesCount
;
1058 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1059 Prv
->Version
= Ver
.Index();
1060 Prv
->ProvideVersion
= ProvideVersion
;
1062 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1063 Ver
->ProvidesList
= Prv
.Index();
1065 // Link it to the package
1066 Prv
->ParentPkg
= Pkg
.Index();
1067 Prv
->NextProvides
= Pkg
->ProvidesList
;
1068 Pkg
->ProvidesList
= Prv
.Index();
1072 // ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1073 bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator
&Ver
, string
const &Package
,
1074 string
const &Version
, uint8_t const Flags
) {
1075 pkgCache
&Cache
= Owner
->Cache
;
1076 pkgCache::GrpIterator
const Grp
= Cache
.FindGrp(Package
);
1077 if (Grp
.end() == true)
1078 return NewProvides(Ver
, Package
, Cache
.NativeArch(), Version
, Flags
);
1081 map_stringitem_t idxProvideVersion
= 0;
1082 if (Version
.empty() == false) {
1083 idxProvideVersion
= StoreString(pkgCacheGenerator::VERSIONNUMBER
, Version
);
1084 if (unlikely(idxProvideVersion
== 0))
1088 bool const isImplicit
= (Flags
& pkgCache::Flag::MultiArchImplicit
) == pkgCache::Flag::MultiArchImplicit
;
1089 bool const isArchSpecific
= (Flags
& pkgCache::Flag::ArchSpecific
) == pkgCache::Flag::ArchSpecific
;
1090 pkgCache::PkgIterator
const OwnerPkg
= Ver
.ParentPkg();
1091 for (pkgCache::PkgIterator Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
1093 if (isImplicit
&& OwnerPkg
== Pkg
)
1095 if (isArchSpecific
== false && APT::Configuration::checkArchitecture(OwnerPkg
.Arch()) == false)
1097 if (Owner
->NewProvides(Ver
, Pkg
, idxProvideVersion
, Flags
) == false)
1104 bool pkgCacheListParser::SameVersion(unsigned short const Hash
, /*{{{*/
1105 pkgCache::VerIterator
const &Ver
)
1107 return Hash
== Ver
->Hash
;
1110 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1111 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1112 unsigned long Flags
)
1114 if (File
.empty() && Site
.empty())
1116 CurrentRlsFile
= NULL
;
1120 // Get some space for the structure
1121 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1122 if (unlikely(idxFile
== 0))
1124 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1127 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1128 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1129 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1131 CurrentRlsFile
->FileName
= idxFileName
;
1132 CurrentRlsFile
->Site
= idxSite
;
1133 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1134 CurrentRlsFile
->Flags
= Flags
;
1135 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1137 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1138 Cache
.HeaderP
->ReleaseFileCount
++;
1143 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1144 // ---------------------------------------------------------------------
1145 /* This is used to select which file is to be associated with all newly
1146 added versions. The caller is responsible for setting the IMS fields. */
1147 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1148 pkgIndexFile
const &Index
,
1149 std::string
const &Architecture
,
1150 std::string
const &Component
,
1151 unsigned long const Flags
)
1153 // Get some space for the structure
1154 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1155 if (unlikely(idxFile
== 0))
1157 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1160 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1161 if (unlikely(idxFileName
== 0))
1163 CurrentFile
->FileName
= idxFileName
;
1164 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1165 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1166 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1167 if (unlikely(idxIndexType
== 0))
1169 CurrentFile
->IndexType
= idxIndexType
;
1170 if (Architecture
.empty())
1171 CurrentFile
->Architecture
= 0;
1174 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1175 if (unlikely(arch
== 0))
1177 CurrentFile
->Architecture
= arch
;
1179 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1180 if (unlikely(component
== 0))
1182 CurrentFile
->Component
= component
;
1183 CurrentFile
->Flags
= Flags
;
1184 if (CurrentRlsFile
!= NULL
)
1185 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1187 CurrentFile
->Release
= 0;
1189 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1190 Cache
.HeaderP
->PackageFileCount
++;
1193 Progress
->SubProgress(Index
.Size());
1197 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1198 // ---------------------------------------------------------------------
1199 /* This is used to create handles to strings. Given the same text it
1200 always returns the same number */
1201 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1204 std::string
const key(S
, Size
);
1206 std::map
<std::string
,map_stringitem_t
> * strings
;
1208 case MIXED
: strings
= &strMixed
; break;
1209 case PKGNAME
: strings
= &strPkgNames
; break;
1210 case VERSIONNUMBER
: strings
= &strVersions
; break;
1211 case SECTION
: strings
= &strSections
; break;
1212 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1215 std::map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1216 if (item
!= strings
->end())
1217 return item
->second
;
1219 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1220 strings
->insert(std::make_pair(key
, idxString
));
1224 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1225 // ---------------------------------------------------------------------
1226 /* This just verifies that each file in the list of index files exists,
1227 has matching attributes with the cache and the cache does not have
1229 static bool CheckValidity(const string
&CacheFile
,
1230 pkgSourceList
&List
,
1231 FileIterator
const Start
,
1232 FileIterator
const End
,
1235 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1236 // No file, certainly invalid
1237 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1240 std::clog
<< "CacheFile " << CacheFile
<< " doesn't exist" << std::endl
;
1244 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1247 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1252 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1253 std::unique_ptr
<MMap
> Map(new MMap(CacheF
,0));
1254 pkgCache
Cache(Map
.get());
1255 if (_error
->PendingError() == true || Map
->Size() == 0)
1258 std::clog
<< "Errors are pending or Map is empty() for " << CacheFile
<< std::endl
;
1263 SPtrArray
<bool> RlsVisited
= new bool[Cache
.HeaderP
->ReleaseFileCount
];
1264 memset(RlsVisited
,0,sizeof(*RlsVisited
)*Cache
.HeaderP
->ReleaseFileCount
);
1265 std::vector
<pkgIndexFile
*> Files
;
1266 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1269 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1270 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1271 if (RlsFile
.end() == true)
1274 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1278 RlsVisited
[RlsFile
->ID
] = true;
1280 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1282 std::vector
<pkgIndexFile
*> const * const Indexes
= (*i
)->GetIndexFiles();
1283 std::copy_if(Indexes
->begin(), Indexes
->end(), std::back_inserter(Files
),
1284 [](pkgIndexFile
const * const I
) { return I
->HasPackages(); });
1286 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1287 if (RlsVisited
[I
] == false)
1290 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1294 std::copy(Start
, End
, std::back_inserter(Files
));
1296 /* Now we check every index file, see if it is in the cache,
1297 verify the IMS data and check that it is on the disk too.. */
1298 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
1299 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
1300 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1303 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1304 if ((*PkgFile
)->Exists() == false)
1307 std::clog
<< "file doesn't exist" << std::endl
;
1311 // FindInCache is also expected to do an IMS check.
1312 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1313 if (File
.end() == true)
1316 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1320 Visited
[File
->ID
] = true;
1322 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1325 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1326 if (Visited
[I
] == false)
1329 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1333 if (_error
->PendingError() == true)
1337 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1338 _error
->DumpErrors();
1345 *OutMap
= Map
.release();
1349 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1350 // ---------------------------------------------------------------------
1351 /* Size is kind of an abstract notion that is only used for the progress
1353 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1355 map_filesize_t TotalSize
= 0;
1358 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1360 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1361 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1362 if ((*j
)->HasPackages() == true)
1363 TotalSize
+= (*j
)->Size();
1367 for (; Start
< End
; ++Start
)
1369 if ((*Start
)->HasPackages() == false)
1371 TotalSize
+= (*Start
)->Size();
1376 // BuildCache - Merge the list of index files into the cache /*{{{*/
1377 static bool BuildCache(pkgCacheGenerator
&Gen
,
1378 OpProgress
* const Progress
,
1379 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1380 pkgSourceList
const * const List
,
1381 FileIterator
const Start
, FileIterator
const End
)
1383 std::vector
<pkgIndexFile
*> Files
;
1384 bool mergeFailure
= false;
1386 auto const indexFileMerge
= [&](pkgIndexFile
* const I
) {
1387 if (I
->HasPackages() == false || mergeFailure
)
1390 if (I
->Exists() == false)
1393 if (I
->FindInCache(Gen
.GetCache()).end() == false)
1395 _error
->Warning("Duplicate sources.list entry %s",
1396 I
->Describe().c_str());
1400 map_filesize_t
const Size
= I
->Size();
1401 if (Progress
!= NULL
)
1402 Progress
->OverallProgress(CurrentSize
, TotalSize
, Size
, _("Reading package lists"));
1403 CurrentSize
+= Size
;
1405 if (I
->Merge(Gen
,Progress
) == false)
1406 mergeFailure
= true;
1411 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1413 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1415 _error
->Warning("Duplicate sources.list entry %s",
1416 (*i
)->Describe().c_str());
1420 if ((*i
)->Merge(Gen
, Progress
) == false)
1423 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1424 if (Indexes
!= NULL
)
1425 std::for_each(Indexes
->begin(), Indexes
->end(), indexFileMerge
);
1433 Gen
.SelectReleaseFile("", "");
1434 std::for_each(Start
, End
, indexFileMerge
);
1441 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1442 // ---------------------------------------------------------------------
1443 /* This makes sure that the status cache (the cache that has all
1444 index files from the sources list and all local ones) is ready
1445 to be mmaped. If OutMap is not zero then a MMap object representing
1446 the cache will be stored there. This is pretty much mandetory if you
1447 are using AllowMem. AllowMem lets the function be run as non-root
1448 where it builds the cache 'fast' into a memory buffer. */
1449 static DynamicMMap
* CreateDynamicMMap(FileFd
* const CacheF
, unsigned long Flags
)
1451 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1452 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1453 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1454 Flags
|= MMap::Moveable
;
1455 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1456 Flags
|= MMap::Fallback
;
1458 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1460 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1462 static bool writeBackMMapToFile(pkgCacheGenerator
* const Gen
, DynamicMMap
* const Map
,
1463 std::string
const &FileName
)
1465 FileFd
SCacheF(FileName
, FileFd::WriteAtomic
);
1466 if (_error
->PendingError() == true)
1469 fchmod(SCacheF
.Fd(),0644);
1471 // Write out the main data
1472 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1473 return _error
->Error(_("IO Error saving source cache"));
1476 // Write out the proper header
1477 Gen
->GetCache().HeaderP
->Dirty
= false;
1478 if (SCacheF
.Seek(0) == false ||
1479 SCacheF
.Write(Map
->Data(),sizeof(*Gen
->GetCache().HeaderP
)) == false)
1480 return _error
->Error(_("IO Error saving source cache"));
1481 Gen
->GetCache().HeaderP
->Dirty
= true;
1485 static bool loadBackMMapFromFile(std::unique_ptr
<pkgCacheGenerator
> &Gen
,
1486 std::unique_ptr
<DynamicMMap
> &Map
, OpProgress
* const Progress
, std::string
const &FileName
)
1488 Map
.reset(CreateDynamicMMap(NULL
, 0));
1489 FileFd
CacheF(FileName
, FileFd::ReadOnly
);
1490 map_pointer_t
const alloc
= Map
->RawAllocate(CacheF
.Size());
1491 if ((alloc
== 0 && _error
->PendingError())
1492 || CacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1493 CacheF
.Size()) == false)
1495 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1498 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1499 MMap
**OutMap
, bool AllowMem
)
1500 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1501 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1502 MMap
**OutMap
,bool AllowMem
)
1504 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1506 std::vector
<pkgIndexFile
*> Files
;
1507 if (_system
->AddStatusFiles(Files
) == false)
1510 // Decide if we can write to the files..
1511 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1512 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1514 // ensure the cache directory exists
1515 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1517 string dir
= _config
->FindDir("Dir::Cache");
1518 size_t const len
= dir
.size();
1519 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1520 dir
= dir
.substr(0, len
- 5);
1521 if (CacheFile
.empty() == false)
1522 CreateDirectory(dir
, flNotFile(CacheFile
));
1523 if (SrcCacheFile
.empty() == false)
1524 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1527 if (Progress
!= NULL
)
1528 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1530 bool pkgcache_fine
= false;
1531 bool srcpkgcache_fine
= false;
1532 bool volatile_fine
= List
.GetVolatileFiles().empty();
1534 if (CheckValidity(CacheFile
, List
, Files
.begin(), Files
.end(), volatile_fine
? OutMap
: NULL
) == true)
1537 std::clog
<< "pkgcache.bin is valid - no need to build any cache" << std::endl
;
1538 pkgcache_fine
= true;
1539 srcpkgcache_fine
= true;
1541 if (pkgcache_fine
== false)
1543 if (CheckValidity(SrcCacheFile
, List
, Files
.end(), Files
.end()) == true)
1546 std::clog
<< "srcpkgcache.bin is valid - it can be reused" << std::endl
;
1547 srcpkgcache_fine
= true;
1551 if (volatile_fine
== true && srcpkgcache_fine
== true && pkgcache_fine
== true)
1553 if (Progress
!= NULL
)
1554 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1558 bool Writeable
= false;
1559 if (srcpkgcache_fine
== false || pkgcache_fine
== false)
1561 if (CacheFile
.empty() == false)
1562 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1563 else if (SrcCacheFile
.empty() == false)
1564 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1567 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1569 if (Writeable
== false && AllowMem
== false)
1571 if (CacheFile
.empty() == false)
1572 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1573 else if (SrcCacheFile
.empty() == false)
1574 return _error
->Error(_("Unable to write to %s"),flNotFile(SrcCacheFile
).c_str());
1576 return _error
->Error("Unable to create caches as file usage is disabled, but memory not allowed either!");
1580 // At this point we know we need to construct something, so get storage ready
1581 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1583 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1585 std::unique_ptr
<pkgCacheGenerator
> Gen
{nullptr};
1586 map_filesize_t CurrentSize
= 0;
1587 std::vector
<pkgIndexFile
*> VolatileFiles
= List
.GetVolatileFiles();
1588 map_filesize_t TotalSize
= ComputeSize(NULL
, VolatileFiles
.begin(), VolatileFiles
.end());
1589 if (srcpkgcache_fine
== true && pkgcache_fine
== false)
1592 std::clog
<< "srcpkgcache.bin was valid - populate MMap with it" << std::endl
;
1593 if (loadBackMMapFromFile(Gen
, Map
, Progress
, SrcCacheFile
) == false)
1595 srcpkgcache_fine
= true;
1596 TotalSize
+= ComputeSize(NULL
, Files
.begin(), Files
.end());
1598 else if (srcpkgcache_fine
== false)
1601 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1602 Gen
.reset(new pkgCacheGenerator(Map
.get(),Progress
));
1604 TotalSize
+= ComputeSize(&List
, Files
.begin(),Files
.end());
1605 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1606 Files
.end(),Files
.end()) == false)
1609 if (Writeable
== true && SrcCacheFile
.empty() == false)
1610 if (writeBackMMapToFile(Gen
.get(), Map
.get(), SrcCacheFile
) == false)
1614 if (pkgcache_fine
== false)
1617 std::clog
<< "Building status cache in pkgcache.bin now" << std::endl
;
1618 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1619 Files
.begin(), Files
.end()) == false)
1622 if (Writeable
== true && CacheFile
.empty() == false)
1623 if (writeBackMMapToFile(Gen
.get(), Map
.get(), CacheFile
) == false)
1628 std::clog
<< "Caches done. Now bring in the volatile files (if any)" << std::endl
;
1630 if (volatile_fine
== false)
1635 std::clog
<< "Populate new MMap with cachefile contents" << std::endl
;
1636 if (loadBackMMapFromFile(Gen
, Map
, Progress
, CacheFile
) == false)
1640 Files
= List
.GetVolatileFiles();
1641 if (BuildCache(*Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1642 Files
.begin(), Files
.end()) == false)
1646 if (OutMap
!= nullptr)
1647 *OutMap
= Map
.release();
1650 std::clog
<< "Everything is ready for shipping" << std::endl
;
1654 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1655 // ---------------------------------------------------------------------
1657 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1658 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1659 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1661 std::vector
<pkgIndexFile
*> Files
;
1662 if (_system
->AddStatusFiles(Files
) == false)
1665 std::unique_ptr
<DynamicMMap
> Map(CreateDynamicMMap(NULL
, 0));
1666 map_filesize_t CurrentSize
= 0;
1667 map_filesize_t TotalSize
= 0;
1669 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1671 // Build the status cache
1672 if (Progress
!= NULL
)
1673 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1674 pkgCacheGenerator
Gen(Map
.get(),Progress
);
1675 if (_error
->PendingError() == true)
1677 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1678 Files
.begin(), Files
.end()) == false)
1681 if (_error
->PendingError() == true)
1683 *OutMap
= Map
.release();
1688 // IsDuplicateDescription /*{{{*/
1689 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1690 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1692 // Descriptions in the same link-list have all the same md5
1693 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1695 for (; Desc
.end() == false; ++Desc
)
1696 if (Desc
.LanguageCode() == CurLang
)
1702 pkgCacheListParser::pkgCacheListParser() : Owner(NULL
), OldDepLast(NULL
), d(NULL
) {}
1703 pkgCacheListParser::~pkgCacheListParser() {}