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>
44 typedef std::vector
<pkgIndexFile
*>::iterator FileIterator
;
45 template <typename Iter
> std::vector
<Iter
*> pkgCacheGenerator::Dynamic
<Iter
>::toReMap
;
47 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
48 MD5SumValue
const &CurMd5
, std::string
const &CurLang
);
52 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
53 // ---------------------------------------------------------------------
54 /* We set the dirty flag and make sure that is written to the disk */
55 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
56 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
61 if (_error
->PendingError() == true)
66 // Setup the map interface..
67 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
68 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
71 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
74 *Cache
.HeaderP
= pkgCache::Header();
76 // make room for the hashtables for packages and groups
77 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->HashTableSize
* 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
->Architectures
= idxArchitectures
;
102 Cache
.HeaderP
->Architectures
= idxArchitecture
;
108 // Map directly from the existing file
110 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
111 if (Cache
.VS
!= _system
->VS
)
113 _error
->Error(_("Cache has an incompatible versioning system"));
118 Cache
.HeaderP
->Dirty
= true;
119 Map
.Sync(0,sizeof(pkgCache::Header
));
122 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
123 // ---------------------------------------------------------------------
124 /* We sync the data then unset the dirty flag in two steps so as to
125 advoid a problem during a crash */
126 pkgCacheGenerator::~pkgCacheGenerator()
128 if (_error
->PendingError() == true)
130 if (Map
.Sync() == false)
133 Cache
.HeaderP
->Dirty
= false;
134 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
135 Map
.Sync(0,sizeof(pkgCache::Header
));
138 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
139 if (oldMap
== newMap
)
142 if (_config
->FindB("Debug::pkgCacheGen", false))
143 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
147 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
149 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
150 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
151 (*i
)->ReMap(oldMap
, newMap
);
152 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
153 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
154 (*i
)->ReMap(oldMap
, newMap
);
155 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
156 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
157 (*i
)->ReMap(oldMap
, newMap
);
158 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
159 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
160 (*i
)->ReMap(oldMap
, newMap
);
161 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
162 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
163 (*i
)->ReMap(oldMap
, newMap
);
164 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
165 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
166 (*i
)->ReMap(oldMap
, newMap
);
167 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
168 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
169 (*i
)->ReMap(oldMap
, newMap
);
171 // CacheGenerator::WriteStringInMap /*{{{*/
172 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
173 const unsigned long &Len
) {
174 void const * const oldMap
= Map
.Data();
175 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
177 ReMap(oldMap
, Map
.Data());
181 // CacheGenerator::WriteStringInMap /*{{{*/
182 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
183 void const * const oldMap
= Map
.Data();
184 map_stringitem_t
const index
= Map
.WriteString(String
);
186 ReMap(oldMap
, Map
.Data());
190 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
191 void const * const oldMap
= Map
.Data();
192 map_pointer_t
const index
= Map
.Allocate(size
);
194 ReMap(oldMap
, Map
.Data());
198 // CacheGenerator::MergeList - Merge the package list /*{{{*/
199 // ---------------------------------------------------------------------
200 /* This provides the generation of the entries in the cache. Each loop
201 goes through a single package record from the underlying parse engine. */
202 bool pkgCacheGenerator::MergeList(ListParser
&List
,
203 pkgCache::VerIterator
*OutVer
)
207 unsigned int Counter
= 0;
208 while (List
.Step() == true)
210 string
const PackageName
= List
.Package();
211 if (PackageName
.empty() == true)
215 if (Counter
% 100 == 0 && Progress
!= 0)
216 Progress
->Progress(List
.Offset());
218 string Arch
= List
.Architecture();
219 string
const Version
= List
.Version();
220 if (Version
.empty() == true && Arch
.empty() == true)
222 // package descriptions
223 if (MergeListGroup(List
, PackageName
) == false)
228 if (Arch
.empty() == true)
230 // use the pseudo arch 'none' for arch-less packages
232 /* We might built a SingleArchCache here, which we don't want to blow up
233 just for these :none packages to a proper MultiArchCache, so just ensure
234 that we have always a native package structure first for SingleArch */
235 pkgCache::PkgIterator NP
;
236 Dynamic
<pkgCache::PkgIterator
> DynPkg(NP
);
237 if (NewPackage(NP
, PackageName
, _config
->Find("APT::Architecture")) == false)
238 // TRANSLATOR: The first placeholder is a package name,
239 // the other two should be copied verbatim as they include debug info
240 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
241 PackageName
.c_str(), "NewPackage", 0);
244 // Get a pointer to the package structure
245 pkgCache::PkgIterator Pkg
;
246 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
247 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
248 // TRANSLATOR: The first placeholder is a package name,
249 // the other two should be copied verbatim as they include debug info
250 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
251 PackageName
.c_str(), "NewPackage", 1);
254 if (Version
.empty() == true)
256 if (MergeListPackage(List
, Pkg
) == false)
261 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
267 FoundFileDeps
|= List
.HasFileDeps();
272 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
273 return _error
->Error(_("Wow, you exceeded the number of package "
274 "names this APT is capable of."));
275 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
276 return _error
->Error(_("Wow, you exceeded the number of versions "
277 "this APT is capable of."));
278 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
279 return _error
->Error(_("Wow, you exceeded the number of descriptions "
280 "this APT is capable of."));
281 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
282 return _error
->Error(_("Wow, you exceeded the number of dependencies "
283 "this APT is capable of."));
285 FoundFileDeps
|= List
.HasFileDeps();
288 // CacheGenerator::MergeListGroup /*{{{*/
289 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
291 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
292 // a group has no data on it's own, only packages have it but these
293 // stanzas like this come from Translation- files to add descriptions,
294 // but without a version we don't need a description for it…
295 if (Grp
.end() == true)
297 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
299 pkgCache::PkgIterator Pkg
;
300 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
301 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
302 if (MergeListPackage(List
, Pkg
) == false)
308 // CacheGenerator::MergeListPackage /*{{{*/
309 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
311 // we first process the package, then the descriptions
312 // (for deb this package processing is in fact a no-op)
313 pkgCache::VerIterator
Ver(Cache
);
314 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
315 if (List
.UsePackage(Pkg
, Ver
) == false)
316 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
317 Pkg
.Name(), "UsePackage", 1);
319 // Find the right version to write the description
320 MD5SumValue CurMd5
= List
.Description_md5();
321 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
323 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
324 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
326 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
328 // a version can only have one md5 describing it
329 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
332 map_stringitem_t md5idx
= VerDesc
->md5sum
;
333 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
335 // don't add a new description if we have one for the given
337 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
340 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
343 // we can stop here as all "same" versions will share the description
350 // CacheGenerator::MergeListVersion /*{{{*/
351 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
352 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
354 pkgCache::VerIterator Ver
= Pkg
.VersionList();
355 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
356 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
357 void const * oldMap
= Map
.Data();
359 unsigned short const Hash
= List
.VersionHash();
360 if (Ver
.end() == false)
362 /* We know the list is sorted so we use that fact in the search.
363 Insertion of new versions is done with correct sorting */
365 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
367 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
368 // Version is higher as current version - insert here
371 // Versionstrings are equal - is hash also equal?
372 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
374 // proceed with the next till we have either the right
375 // or we found another version (which will be lower)
378 /* We already have a version for this item, record that we saw it */
379 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
381 if (List
.UsePackage(Pkg
,Ver
) == false)
382 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
383 Pkg
.Name(), "UsePackage", 2);
385 if (NewFileVer(Ver
,List
) == false)
386 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
387 Pkg
.Name(), "NewFileVer", 1);
389 // Read only a single record and return
401 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
402 if (verindex
== 0 && _error
->PendingError())
403 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
404 Pkg
.Name(), "NewVersion", 1);
406 if (oldMap
!= Map
.Data())
407 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
410 if (unlikely(List
.NewVersion(Ver
) == false))
411 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
412 Pkg
.Name(), "NewVersion", 2);
414 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
415 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
416 Pkg
.Name(), "UsePackage", 3);
418 if (unlikely(NewFileVer(Ver
,List
) == false))
419 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
420 Pkg
.Name(), "NewFileVer", 2);
422 pkgCache::GrpIterator Grp
= Pkg
.Group();
423 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
425 /* If it is the first version of this package we need to add implicit
426 Multi-Arch dependencies to all other package versions in the group now -
427 otherwise we just add them for this new version */
428 if (Pkg
.VersionList()->NextVer
== 0)
430 pkgCache::PkgIterator P
= Grp
.PackageList();
431 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
432 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
434 if (P
->ID
== Pkg
->ID
)
436 pkgCache::VerIterator V
= P
.VersionList();
437 Dynamic
<pkgCache::VerIterator
> DynV(V
);
438 for (; V
.end() != true; ++V
)
439 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
440 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
441 Pkg
.Name(), "AddImplicitDepends", 1);
443 /* :none packages are packages without an architecture. They are forbidden by
444 debian-policy, so usually they will only be in (old) dpkg status files -
445 and dpkg will complain about them - and are pretty rare. We therefore do
446 usually not create conflicts while the parent is created, but only if a :none
447 package (= the target) appears. This creates incorrect dependencies on :none
448 for architecture-specific dependencies on the package we copy from, but we
449 will ignore this bug as architecture-specific dependencies are only allowed
450 in jessie and until then the :none packages should be extinct (hopefully).
451 In other words: This should work long enough to allow graceful removal of
452 these packages, it is not supposed to allow users to keep using them … */
453 if (strcmp(Pkg
.Arch(), "none") == 0)
455 pkgCache::PkgIterator M
= Grp
.FindPreferredPkg();
456 if (M
.end() == false && Pkg
!= M
)
458 pkgCache::DepIterator D
= M
.RevDependsList();
459 Dynamic
<pkgCache::DepIterator
> DynD(D
);
460 for (; D
.end() == false; ++D
)
462 if ((D
->Type
!= pkgCache::Dep::Conflicts
&&
463 D
->Type
!= pkgCache::Dep::DpkgBreaks
&&
464 D
->Type
!= pkgCache::Dep::Replaces
) ||
465 D
.ParentPkg().Group() == Grp
)
468 map_pointer_t
*OldDepLast
= NULL
;
469 pkgCache::VerIterator ConVersion
= D
.ParentVer();
470 Dynamic
<pkgCache::VerIterator
> DynV(ConVersion
);
471 // duplicate the Conflicts/Breaks/Replaces for :none arch
472 NewDepends(Pkg
, ConVersion
, D
->Version
,
473 D
->CompareOp
, D
->Type
, OldDepLast
);
478 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
479 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
480 Pkg
.Name(), "AddImplicitDepends", 2);
482 // Read only a single record and return
489 /* Record the Description(s) based on their master md5sum */
490 MD5SumValue CurMd5
= List
.Description_md5();
491 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
494 /* Before we add a new description we first search in the group for
495 a version with a description of the same MD5 - if so we reuse this
496 description group instead of creating our own for this version */
497 for (pkgCache::PkgIterator P
= Grp
.PackageList();
498 P
.end() == false; P
= Grp
.NextPkg(P
))
500 for (pkgCache::VerIterator V
= P
.VersionList();
501 V
.end() == false; ++V
)
503 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
505 Ver
->DescriptionList
= V
->DescriptionList
;
509 // We haven't found reusable descriptions, so add the first description(s)
510 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
511 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
512 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
513 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
518 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
520 pkgCache::DescIterator Desc
;
521 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
523 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
524 if (unlikely(descindex
== 0 && _error
->PendingError()))
525 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
526 Ver
.ParentPkg().Name(), "NewDescription", 1);
528 md5idx
= Desc
->md5sum
;
529 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
531 // we add at the end, so that the start is constant as we need
532 // that to be able to efficiently share these lists
533 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
534 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
535 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
536 *LastNextDesc
= descindex
;
538 if (NewFileDesc(Desc
,List
) == false)
539 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
540 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
546 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
547 // ---------------------------------------------------------------------
548 /* If we found any file depends while parsing the main list we need to
549 resolve them. Since it is undesired to load the entire list of files
550 into the cache as virtual packages we do a two stage effort. MergeList
551 identifies the file depends and this creates Provdies for them by
552 re-parsing all the indexs. */
553 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
557 unsigned int Counter
= 0;
558 while (List
.Step() == true)
560 string PackageName
= List
.Package();
561 if (PackageName
.empty() == true)
563 string Version
= List
.Version();
564 if (Version
.empty() == true)
567 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
568 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
569 if (Pkg
.end() == true)
570 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
571 PackageName
.c_str(), "FindPkg", 1);
573 if (Counter
% 100 == 0 && Progress
!= 0)
574 Progress
->Progress(List
.Offset());
576 unsigned short Hash
= List
.VersionHash();
577 pkgCache::VerIterator Ver
= Pkg
.VersionList();
578 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
579 for (; Ver
.end() == false; ++Ver
)
581 if (List
.SameVersion(Hash
, Ver
) == true && Version
== Ver
.VerStr())
583 if (List
.CollectFileProvides(Cache
,Ver
) == false)
584 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
585 PackageName
.c_str(), "CollectFileProvides", 1);
590 if (Ver
.end() == true)
591 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
597 // CacheGenerator::NewGroup - Add a new group /*{{{*/
598 // ---------------------------------------------------------------------
599 /* This creates a new group structure and adds it to the hash table */
600 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
602 Grp
= Cache
.FindGrp(Name
);
603 if (Grp
.end() == false)
607 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
608 if (unlikely(Group
== 0))
611 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
612 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
613 if (unlikely(idxName
== 0))
617 // Insert it into the hash table
618 unsigned long const Hash
= Cache
.Hash(Name
);
619 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTable()[Hash
];
620 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
621 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
622 Grp
->Next
= *insertAt
;
625 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
629 // CacheGenerator::NewPackage - Add a new package /*{{{*/
630 // ---------------------------------------------------------------------
631 /* This creates a new package structure and adds it to the hash table */
632 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
633 const string
&Arch
) {
634 pkgCache::GrpIterator Grp
;
635 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
636 if (unlikely(NewGroup(Grp
, Name
) == false))
639 Pkg
= Grp
.FindPkg(Arch
);
640 if (Pkg
.end() == false)
644 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
645 if (unlikely(Package
== 0))
647 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
649 // Insert the package into our package list
650 if (Grp
->FirstPackage
== 0) // the group is new
652 Grp
->FirstPackage
= Package
;
653 // Insert it into the hash table
654 map_id_t
const Hash
= Cache
.Hash(Name
);
655 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTable()[Hash
];
656 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
657 insertAt
= &(Cache
.PkgP
+ *insertAt
)->Next
;
658 Pkg
->Next
= *insertAt
;
661 else // Group the Packages together
663 // this package is the new last package
664 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
665 Pkg
->Next
= LastPkg
->Next
;
666 LastPkg
->Next
= Package
;
668 Grp
->LastPackage
= Package
;
670 // Set the name, arch and the ID
672 #pragma GCC diagnostic push
673 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
675 Pkg
->Name
= Grp
->Name
;
677 #pragma GCC diagnostic pop
679 Pkg
->Group
= Grp
.Index();
680 // all is mapped to the native architecture
681 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
682 if (unlikely(idxArch
== 0))
685 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
690 // CacheGenerator::AddImplicitDepends /*{{{*/
691 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
692 pkgCache::PkgIterator
&P
,
693 pkgCache::VerIterator
&V
)
695 // copy P.Arch() into a string here as a cache remap
696 // in NewDepends() later may alter the pointer location
697 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
698 map_pointer_t
*OldDepLast
= NULL
;
699 /* MultiArch handling introduces a lot of implicit Dependencies:
700 - MultiArch: same → Co-Installable if they have the same version
701 - All others conflict with all other group members */
702 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
703 pkgCache::PkgIterator D
= G
.PackageList();
704 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
705 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
706 for (; D
.end() != true; D
= G
.NextPkg(D
))
708 if (Arch
== D
.Arch() || D
->VersionList
== 0)
710 /* We allow only one installed arch at the time
711 per group, therefore each group member conflicts
712 with all other group members */
713 if (coInstall
== true)
715 // Replaces: ${self}:other ( << ${binary:Version})
716 NewDepends(D
, V
, VerStrIdx
,
717 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
719 // Breaks: ${self}:other (!= ${binary:Version})
720 NewDepends(D
, V
, VerStrIdx
,
721 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
724 // Conflicts: ${self}:other
726 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
732 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
733 pkgCache::PkgIterator
&D
)
735 /* MultiArch handling introduces a lot of implicit Dependencies:
736 - MultiArch: same → Co-Installable if they have the same version
737 - All others conflict with all other group members */
738 map_pointer_t
*OldDepLast
= NULL
;
739 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
740 if (coInstall
== true)
742 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
743 // Replaces: ${self}:other ( << ${binary:Version})
744 NewDepends(D
, V
, VerStrIdx
,
745 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
747 // Breaks: ${self}:other (!= ${binary:Version})
748 NewDepends(D
, V
, VerStrIdx
,
749 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
752 // Conflicts: ${self}:other
754 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
761 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
762 // ---------------------------------------------------------------------
764 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
767 if (CurrentFile
== 0)
771 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
775 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
776 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
778 // Link it to the end of the list
779 map_pointer_t
*Last
= &Ver
->FileList
;
780 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
782 VF
->NextFile
= *Last
;
785 VF
->Offset
= List
.Offset();
786 VF
->Size
= List
.Size();
787 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
788 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
789 Cache
.HeaderP
->VerFileCount
++;
794 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
795 // ---------------------------------------------------------------------
796 /* This puts a version structure in the linked list */
797 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
798 const string
&VerStr
,
799 map_pointer_t
const ParentPkg
,
800 unsigned short const Hash
,
801 map_pointer_t
const Next
)
804 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
809 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
810 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
812 Ver
->ParentPkg
= ParentPkg
;
814 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
816 // try to find the version string in the group for reuse
817 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
818 pkgCache::GrpIterator Grp
= Pkg
.Group();
819 if (Pkg
.end() == false && Grp
.end() == false)
821 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
825 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
827 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
830 Ver
->VerStr
= V
->VerStr
;
838 // haven't found the version string, so create
839 map_stringitem_t
const idxVerStr
= StoreString(VERSION
, VerStr
);
840 if (unlikely(idxVerStr
== 0))
842 Ver
->VerStr
= idxVerStr
;
846 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
847 // ---------------------------------------------------------------------
849 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
852 if (CurrentFile
== 0)
856 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
860 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
861 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
863 // Link it to the end of the list
864 map_pointer_t
*Last
= &Desc
->FileList
;
865 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
868 DF
->NextFile
= *Last
;
871 DF
->Offset
= List
.Offset();
872 DF
->Size
= List
.Size();
873 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
874 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
875 Cache
.HeaderP
->DescFileCount
++;
880 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
881 // ---------------------------------------------------------------------
882 /* This puts a description structure in the linked list */
883 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
885 const MD5SumValue
&md5sum
,
886 map_stringitem_t
const idxmd5str
)
889 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
890 if (Description
== 0)
894 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
895 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
896 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
897 if (unlikely(idxlanguage_code
== 0))
899 Desc
->language_code
= idxlanguage_code
;
902 Desc
->md5sum
= idxmd5str
;
905 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
906 if (unlikely(idxmd5sum
== 0))
908 Desc
->md5sum
= idxmd5sum
;
914 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
915 // ---------------------------------------------------------------------
916 /* This creates a dependency element in the tree. It is linked to the
917 version and to the package that it is pointing to. */
918 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
919 pkgCache::VerIterator
&Ver
,
920 string
const &Version
,
921 unsigned int const &Op
,
922 unsigned int const &Type
,
923 map_stringitem_t
* &OldDepLast
)
925 map_stringitem_t index
= 0;
926 if (Version
.empty() == false)
928 int const CmpOp
= Op
& 0x0F;
929 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
930 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
935 void const * const oldMap
= Map
.Data();
936 index
= StoreString(VERSION
, Version
);
937 if (unlikely(index
== 0))
939 if (OldDepLast
!= 0 && oldMap
!= Map
.Data())
940 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
943 return NewDepends(Pkg
, Ver
, index
, Op
, Type
, OldDepLast
);
945 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
946 pkgCache::VerIterator
&Ver
,
947 map_pointer_t
const Version
,
948 unsigned int const &Op
,
949 unsigned int const &Type
,
950 map_pointer_t
* &OldDepLast
)
952 void const * const oldMap
= Map
.Data();
954 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
955 if (unlikely(Dependency
== 0))
959 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
960 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
961 Dep
->ParentVer
= Ver
.Index();
964 Dep
->Version
= Version
;
965 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
967 // Link it to the package
968 Dep
->Package
= Pkg
.Index();
969 Dep
->NextRevDepends
= Pkg
->RevDepends
;
970 Pkg
->RevDepends
= Dep
.Index();
972 // Do we know where to link the Dependency to?
973 if (OldDepLast
== NULL
)
975 OldDepLast
= &Ver
->DependsList
;
976 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
977 OldDepLast
= &D
->NextDepends
;
978 } else if (oldMap
!= Map
.Data())
979 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
981 Dep
->NextDepends
= *OldDepLast
;
982 *OldDepLast
= Dep
.Index();
983 OldDepLast
= &Dep
->NextDepends
;
988 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
989 // ---------------------------------------------------------------------
990 /* This creates a Group and the Package to link this dependency to if
991 needed and handles also the caching of the old endpoint */
992 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator
&Ver
,
993 const string
&PackageName
,
995 const string
&Version
,
999 pkgCache::GrpIterator Grp
;
1000 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1001 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1004 // Locate the target package
1005 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(Arch
);
1006 // we don't create 'none' packages and their dependencies if we can avoid it …
1007 if (Pkg
.end() == true && Arch
== "none" && strcmp(Ver
.ParentPkg().Arch(), "none") != 0)
1009 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1010 if (Pkg
.end() == true) {
1011 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1015 // Is it a file dependency?
1016 if (unlikely(PackageName
[0] == '/'))
1017 FoundFileDeps
= true;
1019 /* Caching the old end point speeds up generation substantially */
1020 if (OldDepVer
!= Ver
) {
1025 return Owner
->NewDepends(Pkg
, Ver
, Version
, Op
, Type
, OldDepLast
);
1028 // ListParser::NewProvides - Create a Provides element /*{{{*/
1029 // ---------------------------------------------------------------------
1031 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1032 const string
&PkgName
,
1033 const string
&PkgArch
,
1034 const string
&Version
)
1036 pkgCache
&Cache
= Owner
->Cache
;
1038 // We do not add self referencing provides
1039 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1040 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1044 map_pointer_t
const Provides
= Owner
->AllocateInMap(sizeof(pkgCache::Provides
));
1045 if (unlikely(Provides
== 0))
1047 Cache
.HeaderP
->ProvidesCount
++;
1050 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1051 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
1052 Prv
->Version
= Ver
.Index();
1053 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1054 Ver
->ProvidesList
= Prv
.Index();
1055 if (Version
.empty() == false) {
1056 map_stringitem_t
const idxProvideVersion
= WriteString(Version
);
1057 Prv
->ProvideVersion
= idxProvideVersion
;
1058 if (unlikely(idxProvideVersion
== 0))
1062 // Locate the target package
1063 pkgCache::PkgIterator Pkg
;
1064 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1065 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1068 // Link it to the package
1069 Prv
->ParentPkg
= Pkg
.Index();
1070 Prv
->NextProvides
= Pkg
->ProvidesList
;
1071 Pkg
->ProvidesList
= Prv
.Index();
1076 bool pkgCacheGenerator::ListParser::SameVersion(unsigned short const Hash
,/*{{{*/
1077 pkgCache::VerIterator
const &Ver
)
1079 return Hash
== Ver
->Hash
;
1082 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1083 // ---------------------------------------------------------------------
1084 /* This is used to select which file is to be associated with all newly
1085 added versions. The caller is responsible for setting the IMS fields. */
1086 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
1087 const pkgIndexFile
&Index
,
1088 unsigned long Flags
)
1090 // Get some space for the structure
1091 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1092 if (unlikely(idxFile
== 0))
1094 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1097 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1098 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1099 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1101 CurrentFile
->FileName
= idxFileName
;
1102 CurrentFile
->Site
= idxSite
;
1103 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1104 CurrentFile
->Flags
= Flags
;
1105 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1106 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1107 if (unlikely(idxIndexType
== 0))
1109 CurrentFile
->IndexType
= idxIndexType
;
1111 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1112 Cache
.HeaderP
->PackageFileCount
++;
1115 Progress
->SubProgress(Index
.Size());
1119 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1120 // ---------------------------------------------------------------------
1121 /* This is used to create handles to strings. Given the same text it
1122 always returns the same number */
1123 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1126 std::string
const key(S
, Size
);
1128 std::map
<std::string
,map_stringitem_t
> * strings
;
1130 case MIXED
: strings
= &strMixed
; break;
1131 case PKGNAME
: strings
= &strPkgNames
; break;
1132 case VERSION
: strings
= &strVersions
; break;
1133 case SECTION
: strings
= &strSections
; break;
1134 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1137 std::map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1138 if (item
!= strings
->end())
1139 return item
->second
;
1141 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1142 strings
->insert(std::make_pair(key
, idxString
));
1146 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1147 // ---------------------------------------------------------------------
1148 /* This just verifies that each file in the list of index files exists,
1149 has matching attributes with the cache and the cache does not have
1151 static bool CheckValidity(const string
&CacheFile
,
1152 pkgSourceList
&List
,
1157 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1158 // No file, certainly invalid
1159 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1162 std::clog
<< "CacheFile doesn't exist" << std::endl
;
1166 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1169 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1174 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1175 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
1176 pkgCache
Cache(Map
);
1177 if (_error
->PendingError() == true || Map
->Size() == 0)
1180 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
1185 /* Now we check every index file, see if it is in the cache,
1186 verify the IMS data and check that it is on the disk too.. */
1187 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
1188 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
1189 for (; Start
!= End
; ++Start
)
1192 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
1193 if ((*Start
)->HasPackages() == false)
1196 std::clog
<< "Has NO packages" << std::endl
;
1200 if ((*Start
)->Exists() == false)
1202 #if 0 // mvo: we no longer give a message here (Default Sources spec)
1203 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
1204 (*Start
)->Describe().c_str());
1207 std::clog
<< "file doesn't exist" << std::endl
;
1211 // FindInCache is also expected to do an IMS check.
1212 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
1213 if (File
.end() == true)
1216 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1220 Visited
[File
->ID
] = true;
1222 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1225 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1226 if (Visited
[I
] == false)
1229 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
1233 if (_error
->PendingError() == true)
1237 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1238 _error
->DumpErrors();
1245 *OutMap
= Map
.UnGuard();
1249 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1250 // ---------------------------------------------------------------------
1251 /* Size is kind of an abstract notion that is only used for the progress
1253 static map_filesize_t
ComputeSize(FileIterator Start
,FileIterator End
)
1255 map_filesize_t TotalSize
= 0;
1256 for (; Start
< End
; ++Start
)
1258 if ((*Start
)->HasPackages() == false)
1260 TotalSize
+= (*Start
)->Size();
1265 // BuildCache - Merge the list of index files into the cache /*{{{*/
1266 // ---------------------------------------------------------------------
1268 static bool BuildCache(pkgCacheGenerator
&Gen
,
1269 OpProgress
*Progress
,
1270 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1271 FileIterator Start
, FileIterator End
)
1274 for (I
= Start
; I
!= End
; ++I
)
1276 if ((*I
)->HasPackages() == false)
1279 if ((*I
)->Exists() == false)
1282 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
1284 _error
->Warning("Duplicate sources.list entry %s",
1285 (*I
)->Describe().c_str());
1289 map_filesize_t Size
= (*I
)->Size();
1290 if (Progress
!= NULL
)
1291 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
1292 CurrentSize
+= Size
;
1294 if ((*I
)->Merge(Gen
,Progress
) == false)
1298 if (Gen
.HasFileDeps() == true)
1300 if (Progress
!= NULL
)
1302 TotalSize
= ComputeSize(Start
, End
);
1304 for (I
= Start
; I
!= End
; ++I
)
1306 map_filesize_t Size
= (*I
)->Size();
1307 if (Progress
!= NULL
)
1308 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
1309 CurrentSize
+= Size
;
1310 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
1318 // CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
1319 DynamicMMap
* pkgCacheGenerator::CreateDynamicMMap(FileFd
*CacheF
, unsigned long Flags
) {
1320 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1321 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1322 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1323 Flags
|= MMap::Moveable
;
1324 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1325 Flags
|= MMap::Fallback
;
1327 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1329 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1332 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1333 // ---------------------------------------------------------------------
1334 /* This makes sure that the status cache (the cache that has all
1335 index files from the sources list and all local ones) is ready
1336 to be mmaped. If OutMap is not zero then a MMap object representing
1337 the cache will be stored there. This is pretty much mandetory if you
1338 are using AllowMem. AllowMem lets the function be run as non-root
1339 where it builds the cache 'fast' into a memory buffer. */
1340 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1341 MMap
**OutMap
, bool AllowMem
)
1342 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1343 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1344 MMap
**OutMap
,bool AllowMem
)
1346 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1348 std::vector
<pkgIndexFile
*> Files
;
1349 for (std::vector
<metaIndex
*>::const_iterator i
= List
.begin();
1353 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1354 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
1355 j
!= Indexes
->end();
1357 Files
.push_back (*j
);
1360 map_filesize_t
const EndOfSource
= Files
.size();
1361 if (_system
->AddStatusFiles(Files
) == false)
1364 // Decide if we can write to the files..
1365 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1366 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1368 // ensure the cache directory exists
1369 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1371 string dir
= _config
->FindDir("Dir::Cache");
1372 size_t const len
= dir
.size();
1373 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1374 dir
= dir
.substr(0, len
- 5);
1375 if (CacheFile
.empty() == false)
1376 CreateDirectory(dir
, flNotFile(CacheFile
));
1377 if (SrcCacheFile
.empty() == false)
1378 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1381 // Decide if we can write to the cache
1382 bool Writeable
= false;
1383 if (CacheFile
.empty() == false)
1384 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1386 if (SrcCacheFile
.empty() == false)
1387 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1389 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1391 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
1392 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1394 if (Progress
!= NULL
)
1395 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1397 // Cache is OK, Fin.
1398 if (CheckValidity(CacheFile
, List
, Files
.begin(),Files
.end(),OutMap
) == true)
1400 if (Progress
!= NULL
)
1401 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1403 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
1406 else if (Debug
== true)
1407 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
1409 /* At this point we know we need to reconstruct the package cache,
1411 SPtr
<FileFd
> CacheF
;
1412 SPtr
<DynamicMMap
> Map
;
1413 if (Writeable
== true && CacheFile
.empty() == false)
1415 _error
->PushToStack();
1416 unlink(CacheFile
.c_str());
1417 CacheF
= new FileFd(CacheFile
,FileFd::WriteAtomic
);
1418 fchmod(CacheF
->Fd(),0644);
1419 Map
= CreateDynamicMMap(CacheF
, MMap::Public
);
1420 if (_error
->PendingError() == true)
1422 delete CacheF
.UnGuard();
1423 delete Map
.UnGuard();
1425 std::clog
<< "Open filebased MMap FAILED" << std::endl
;
1427 if (AllowMem
== false)
1429 _error
->MergeWithStack();
1432 _error
->RevertToStack();
1436 _error
->MergeWithStack();
1438 std::clog
<< "Open filebased MMap" << std::endl
;
1441 if (Writeable
== false || CacheFile
.empty() == true)
1443 // Just build it in memory..
1444 Map
= CreateDynamicMMap(NULL
);
1446 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1449 // Lets try the source cache.
1450 map_filesize_t CurrentSize
= 0;
1451 map_filesize_t TotalSize
= 0;
1452 if (CheckValidity(SrcCacheFile
, List
, Files
.begin(),
1453 Files
.begin()+EndOfSource
) == true)
1456 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
1457 // Preload the map with the source cache
1458 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
1459 map_pointer_t
const alloc
= Map
->RawAllocate(SCacheF
.Size());
1460 if ((alloc
== 0 && _error
->PendingError())
1461 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1462 SCacheF
.Size()) == false)
1465 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1467 // Build the status cache
1468 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1469 if (_error
->PendingError() == true)
1471 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1472 Files
.begin()+EndOfSource
,Files
.end()) == false)
1478 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1479 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
1481 // Build the source cache
1482 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1483 if (_error
->PendingError() == true)
1485 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1486 Files
.begin(),Files
.begin()+EndOfSource
) == false)
1490 if (Writeable
== true && SrcCacheFile
.empty() == false)
1492 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteAtomic
);
1493 if (_error
->PendingError() == true)
1496 fchmod(SCacheF
.Fd(),0644);
1498 // Write out the main data
1499 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1500 return _error
->Error(_("IO Error saving source cache"));
1503 // Write out the proper header
1504 Gen
.GetCache().HeaderP
->Dirty
= false;
1505 if (SCacheF
.Seek(0) == false ||
1506 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1507 return _error
->Error(_("IO Error saving source cache"));
1508 Gen
.GetCache().HeaderP
->Dirty
= true;
1512 // Build the status cache
1513 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1514 Files
.begin()+EndOfSource
,Files
.end()) == false)
1518 std::clog
<< "Caches are ready for shipping" << std::endl
;
1520 if (_error
->PendingError() == true)
1526 delete Map
.UnGuard();
1527 *OutMap
= new MMap(*CacheF
,0);
1531 *OutMap
= Map
.UnGuard();
1538 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1539 // ---------------------------------------------------------------------
1541 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1542 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1543 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1545 std::vector
<pkgIndexFile
*> Files
;
1546 map_filesize_t EndOfSource
= Files
.size();
1547 if (_system
->AddStatusFiles(Files
) == false)
1550 SPtr
<DynamicMMap
> Map
= CreateDynamicMMap(NULL
);
1551 map_filesize_t CurrentSize
= 0;
1552 map_filesize_t TotalSize
= 0;
1554 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1556 // Build the status cache
1557 if (Progress
!= NULL
)
1558 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1559 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1560 if (_error
->PendingError() == true)
1562 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1563 Files
.begin()+EndOfSource
,Files
.end()) == false)
1566 if (_error
->PendingError() == true)
1568 *OutMap
= Map
.UnGuard();
1573 // IsDuplicateDescription /*{{{*/
1574 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1575 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1577 // Descriptions in the same link-list have all the same md5
1578 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1580 for (; Desc
.end() == false; ++Desc
)
1581 if (Desc
.LanguageCode() == CurLang
)
1586 // CacheGenerator::FinishCache /*{{{*/
1587 bool pkgCacheGenerator::FinishCache(OpProgress
* /*Progress*/)