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
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
80 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
81 if (unlikely(idxVerSysName
== 0))
83 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
84 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
85 if (unlikely(idxArchitecture
== 0))
87 Cache
.HeaderP
->Architecture
= idxArchitecture
;
89 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
92 std::vector
<std::string
>::const_iterator a
= archs
.begin();
93 std::string list
= *a
;
94 for (++a
; a
!= archs
.end(); ++a
)
95 list
.append(",").append(*a
);
96 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
97 if (unlikely(idxArchitectures
== 0))
99 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
102 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
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
->GrpHashTableP()[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
->PkgHashTableP()[Hash
];
656 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
657 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
658 Pkg
->NextPackage
= *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
->NextPackage
= LastPkg
->NextPackage
;
666 LastPkg
->NextPackage
= Package
;
668 Grp
->LastPackage
= Package
;
670 // Set the name, arch and the ID
671 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
672 Pkg
->Group
= Grp
.Index();
673 // all is mapped to the native architecture
674 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
675 if (unlikely(idxArch
== 0))
678 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
683 // CacheGenerator::AddImplicitDepends /*{{{*/
684 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
685 pkgCache::PkgIterator
&P
,
686 pkgCache::VerIterator
&V
)
688 // copy P.Arch() into a string here as a cache remap
689 // in NewDepends() later may alter the pointer location
690 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
691 map_pointer_t
*OldDepLast
= NULL
;
692 /* MultiArch handling introduces a lot of implicit Dependencies:
693 - MultiArch: same → Co-Installable if they have the same version
694 - All others conflict with all other group members */
695 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
696 pkgCache::PkgIterator D
= G
.PackageList();
697 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
698 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
699 for (; D
.end() != true; D
= G
.NextPkg(D
))
701 if (Arch
== D
.Arch() || D
->VersionList
== 0)
703 /* We allow only one installed arch at the time
704 per group, therefore each group member conflicts
705 with all other group members */
706 if (coInstall
== true)
708 // Replaces: ${self}:other ( << ${binary:Version})
709 NewDepends(D
, V
, VerStrIdx
,
710 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
712 // Breaks: ${self}:other (!= ${binary:Version})
713 NewDepends(D
, V
, VerStrIdx
,
714 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
717 // Conflicts: ${self}:other
719 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
725 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
726 pkgCache::PkgIterator
&D
)
728 /* MultiArch handling introduces a lot of implicit Dependencies:
729 - MultiArch: same → Co-Installable if they have the same version
730 - All others conflict with all other group members */
731 map_pointer_t
*OldDepLast
= NULL
;
732 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
733 if (coInstall
== true)
735 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
736 // Replaces: ${self}:other ( << ${binary:Version})
737 NewDepends(D
, V
, VerStrIdx
,
738 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
740 // Breaks: ${self}:other (!= ${binary:Version})
741 NewDepends(D
, V
, VerStrIdx
,
742 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
745 // Conflicts: ${self}:other
747 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
754 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
755 // ---------------------------------------------------------------------
757 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
760 if (CurrentFile
== 0)
764 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
768 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
769 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
771 // Link it to the end of the list
772 map_pointer_t
*Last
= &Ver
->FileList
;
773 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
775 VF
->NextFile
= *Last
;
778 VF
->Offset
= List
.Offset();
779 VF
->Size
= List
.Size();
780 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
781 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
782 Cache
.HeaderP
->VerFileCount
++;
787 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
788 // ---------------------------------------------------------------------
789 /* This puts a version structure in the linked list */
790 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
791 const string
&VerStr
,
792 map_pointer_t
const ParentPkg
,
793 unsigned short const Hash
,
794 map_pointer_t
const Next
)
797 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
802 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
803 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
805 Ver
->ParentPkg
= ParentPkg
;
807 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
809 // try to find the version string in the group for reuse
810 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
811 pkgCache::GrpIterator Grp
= Pkg
.Group();
812 if (Pkg
.end() == false && Grp
.end() == false)
814 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
818 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
820 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
823 Ver
->VerStr
= V
->VerStr
;
831 // haven't found the version string, so create
832 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
833 if (unlikely(idxVerStr
== 0))
835 Ver
->VerStr
= idxVerStr
;
839 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
840 // ---------------------------------------------------------------------
842 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
845 if (CurrentFile
== 0)
849 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
853 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
854 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
856 // Link it to the end of the list
857 map_pointer_t
*Last
= &Desc
->FileList
;
858 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
861 DF
->NextFile
= *Last
;
864 DF
->Offset
= List
.Offset();
865 DF
->Size
= List
.Size();
866 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
867 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
868 Cache
.HeaderP
->DescFileCount
++;
873 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
874 // ---------------------------------------------------------------------
875 /* This puts a description structure in the linked list */
876 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
878 const MD5SumValue
&md5sum
,
879 map_stringitem_t
const idxmd5str
)
882 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
883 if (Description
== 0)
887 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
888 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
889 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
890 if (unlikely(idxlanguage_code
== 0))
892 Desc
->language_code
= idxlanguage_code
;
895 Desc
->md5sum
= idxmd5str
;
898 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
899 if (unlikely(idxmd5sum
== 0))
901 Desc
->md5sum
= idxmd5sum
;
907 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
908 // ---------------------------------------------------------------------
909 /* This creates a dependency element in the tree. It is linked to the
910 version and to the package that it is pointing to. */
911 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
912 pkgCache::VerIterator
&Ver
,
913 string
const &Version
,
914 unsigned int const &Op
,
915 unsigned int const &Type
,
916 map_stringitem_t
* &OldDepLast
)
918 map_stringitem_t index
= 0;
919 if (Version
.empty() == false)
921 int const CmpOp
= Op
& 0x0F;
922 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
923 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
928 void const * const oldMap
= Map
.Data();
929 index
= StoreString(VERSIONNUMBER
, Version
);
930 if (unlikely(index
== 0))
932 if (OldDepLast
!= 0 && oldMap
!= Map
.Data())
933 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
936 return NewDepends(Pkg
, Ver
, index
, Op
, Type
, OldDepLast
);
938 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
939 pkgCache::VerIterator
&Ver
,
940 map_pointer_t
const Version
,
941 unsigned int const &Op
,
942 unsigned int const &Type
,
943 map_pointer_t
* &OldDepLast
)
945 void const * const oldMap
= Map
.Data();
947 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
948 if (unlikely(Dependency
== 0))
952 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
953 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
954 Dep
->ParentVer
= Ver
.Index();
957 Dep
->Version
= Version
;
958 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
960 // Link it to the package
961 Dep
->Package
= Pkg
.Index();
962 Dep
->NextRevDepends
= Pkg
->RevDepends
;
963 Pkg
->RevDepends
= Dep
.Index();
965 // Do we know where to link the Dependency to?
966 if (OldDepLast
== NULL
)
968 OldDepLast
= &Ver
->DependsList
;
969 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
970 OldDepLast
= &D
->NextDepends
;
971 } else if (oldMap
!= Map
.Data())
972 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
974 Dep
->NextDepends
= *OldDepLast
;
975 *OldDepLast
= Dep
.Index();
976 OldDepLast
= &Dep
->NextDepends
;
981 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
982 // ---------------------------------------------------------------------
983 /* This creates a Group and the Package to link this dependency to if
984 needed and handles also the caching of the old endpoint */
985 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator
&Ver
,
986 const string
&PackageName
,
988 const string
&Version
,
992 pkgCache::GrpIterator Grp
;
993 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
994 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
997 // Locate the target package
998 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(Arch
);
999 // we don't create 'none' packages and their dependencies if we can avoid it …
1000 if (Pkg
.end() == true && Arch
== "none" && strcmp(Ver
.ParentPkg().Arch(), "none") != 0)
1002 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1003 if (Pkg
.end() == true) {
1004 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1008 // Is it a file dependency?
1009 if (unlikely(PackageName
[0] == '/'))
1010 FoundFileDeps
= true;
1012 /* Caching the old end point speeds up generation substantially */
1013 if (OldDepVer
!= Ver
) {
1018 return Owner
->NewDepends(Pkg
, Ver
, Version
, Op
, Type
, OldDepLast
);
1021 // ListParser::NewProvides - Create a Provides element /*{{{*/
1022 // ---------------------------------------------------------------------
1024 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1025 const string
&PkgName
,
1026 const string
&PkgArch
,
1027 const string
&Version
)
1029 pkgCache
&Cache
= Owner
->Cache
;
1031 // We do not add self referencing provides
1032 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1033 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1037 map_pointer_t
const Provides
= Owner
->AllocateInMap(sizeof(pkgCache::Provides
));
1038 if (unlikely(Provides
== 0))
1040 Cache
.HeaderP
->ProvidesCount
++;
1043 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1044 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
1045 Prv
->Version
= Ver
.Index();
1046 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1047 Ver
->ProvidesList
= Prv
.Index();
1048 if (Version
.empty() == false) {
1049 map_stringitem_t
const idxProvideVersion
= WriteString(Version
);
1050 Prv
->ProvideVersion
= idxProvideVersion
;
1051 if (unlikely(idxProvideVersion
== 0))
1055 // Locate the target package
1056 pkgCache::PkgIterator Pkg
;
1057 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1058 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1061 // Link it to the package
1062 Prv
->ParentPkg
= Pkg
.Index();
1063 Prv
->NextProvides
= Pkg
->ProvidesList
;
1064 Pkg
->ProvidesList
= Prv
.Index();
1069 bool pkgCacheGenerator::ListParser::SameVersion(unsigned short const Hash
,/*{{{*/
1070 pkgCache::VerIterator
const &Ver
)
1072 return Hash
== Ver
->Hash
;
1075 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1076 // ---------------------------------------------------------------------
1077 /* This is used to select which file is to be associated with all newly
1078 added versions. The caller is responsible for setting the IMS fields. */
1079 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
1080 const pkgIndexFile
&Index
,
1081 unsigned long Flags
)
1083 // Get some space for the structure
1084 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1085 if (unlikely(idxFile
== 0))
1087 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1090 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1091 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1092 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1094 CurrentFile
->FileName
= idxFileName
;
1095 CurrentFile
->Site
= idxSite
;
1096 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1097 CurrentFile
->Flags
= Flags
;
1098 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1099 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1100 if (unlikely(idxIndexType
== 0))
1102 CurrentFile
->IndexType
= idxIndexType
;
1104 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1105 Cache
.HeaderP
->PackageFileCount
++;
1108 Progress
->SubProgress(Index
.Size());
1112 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1113 // ---------------------------------------------------------------------
1114 /* This is used to create handles to strings. Given the same text it
1115 always returns the same number */
1116 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1119 std::string
const key(S
, Size
);
1121 std::map
<std::string
,map_stringitem_t
> * strings
;
1123 case MIXED
: strings
= &strMixed
; break;
1124 case PKGNAME
: strings
= &strPkgNames
; break;
1125 case VERSIONNUMBER
: strings
= &strVersions
; break;
1126 case SECTION
: strings
= &strSections
; break;
1127 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1130 std::map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1131 if (item
!= strings
->end())
1132 return item
->second
;
1134 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1135 strings
->insert(std::make_pair(key
, idxString
));
1139 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1140 // ---------------------------------------------------------------------
1141 /* This just verifies that each file in the list of index files exists,
1142 has matching attributes with the cache and the cache does not have
1144 static bool CheckValidity(const string
&CacheFile
,
1145 pkgSourceList
&List
,
1150 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1151 // No file, certainly invalid
1152 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1155 std::clog
<< "CacheFile doesn't exist" << std::endl
;
1159 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1162 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1167 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1168 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
1169 pkgCache
Cache(Map
);
1170 if (_error
->PendingError() == true || Map
->Size() == 0)
1173 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
1178 /* Now we check every index file, see if it is in the cache,
1179 verify the IMS data and check that it is on the disk too.. */
1180 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
1181 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
1182 for (; Start
!= End
; ++Start
)
1185 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
1186 if ((*Start
)->HasPackages() == false)
1189 std::clog
<< "Has NO packages" << std::endl
;
1193 if ((*Start
)->Exists() == false)
1195 #if 0 // mvo: we no longer give a message here (Default Sources spec)
1196 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
1197 (*Start
)->Describe().c_str());
1200 std::clog
<< "file doesn't exist" << std::endl
;
1204 // FindInCache is also expected to do an IMS check.
1205 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
1206 if (File
.end() == true)
1209 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1213 Visited
[File
->ID
] = true;
1215 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1218 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1219 if (Visited
[I
] == false)
1222 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
1226 if (_error
->PendingError() == true)
1230 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1231 _error
->DumpErrors();
1238 *OutMap
= Map
.UnGuard();
1242 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1243 // ---------------------------------------------------------------------
1244 /* Size is kind of an abstract notion that is only used for the progress
1246 static map_filesize_t
ComputeSize(FileIterator Start
,FileIterator End
)
1248 map_filesize_t TotalSize
= 0;
1249 for (; Start
< End
; ++Start
)
1251 if ((*Start
)->HasPackages() == false)
1253 TotalSize
+= (*Start
)->Size();
1258 // BuildCache - Merge the list of index files into the cache /*{{{*/
1259 // ---------------------------------------------------------------------
1261 static bool BuildCache(pkgCacheGenerator
&Gen
,
1262 OpProgress
*Progress
,
1263 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1264 FileIterator Start
, FileIterator End
)
1267 for (I
= Start
; I
!= End
; ++I
)
1269 if ((*I
)->HasPackages() == false)
1272 if ((*I
)->Exists() == false)
1275 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
1277 _error
->Warning("Duplicate sources.list entry %s",
1278 (*I
)->Describe().c_str());
1282 map_filesize_t Size
= (*I
)->Size();
1283 if (Progress
!= NULL
)
1284 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
1285 CurrentSize
+= Size
;
1287 if ((*I
)->Merge(Gen
,Progress
) == false)
1291 if (Gen
.HasFileDeps() == true)
1293 if (Progress
!= NULL
)
1295 TotalSize
= ComputeSize(Start
, End
);
1297 for (I
= Start
; I
!= End
; ++I
)
1299 map_filesize_t Size
= (*I
)->Size();
1300 if (Progress
!= NULL
)
1301 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
1302 CurrentSize
+= Size
;
1303 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
1311 // CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
1312 DynamicMMap
* pkgCacheGenerator::CreateDynamicMMap(FileFd
*CacheF
, unsigned long Flags
) {
1313 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1314 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1315 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1316 Flags
|= MMap::Moveable
;
1317 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1318 Flags
|= MMap::Fallback
;
1320 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1322 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1325 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1326 // ---------------------------------------------------------------------
1327 /* This makes sure that the status cache (the cache that has all
1328 index files from the sources list and all local ones) is ready
1329 to be mmaped. If OutMap is not zero then a MMap object representing
1330 the cache will be stored there. This is pretty much mandetory if you
1331 are using AllowMem. AllowMem lets the function be run as non-root
1332 where it builds the cache 'fast' into a memory buffer. */
1333 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1334 MMap
**OutMap
, bool AllowMem
)
1335 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1336 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1337 MMap
**OutMap
,bool AllowMem
)
1339 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1341 std::vector
<pkgIndexFile
*> Files
;
1342 for (std::vector
<metaIndex
*>::const_iterator i
= List
.begin();
1346 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1347 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
1348 j
!= Indexes
->end();
1350 Files
.push_back (*j
);
1353 map_filesize_t
const EndOfSource
= Files
.size();
1354 if (_system
->AddStatusFiles(Files
) == false)
1357 // Decide if we can write to the files..
1358 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1359 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1361 // ensure the cache directory exists
1362 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1364 string dir
= _config
->FindDir("Dir::Cache");
1365 size_t const len
= dir
.size();
1366 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1367 dir
= dir
.substr(0, len
- 5);
1368 if (CacheFile
.empty() == false)
1369 CreateDirectory(dir
, flNotFile(CacheFile
));
1370 if (SrcCacheFile
.empty() == false)
1371 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1374 // Decide if we can write to the cache
1375 bool Writeable
= false;
1376 if (CacheFile
.empty() == false)
1377 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1379 if (SrcCacheFile
.empty() == false)
1380 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1382 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1384 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
1385 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1387 if (Progress
!= NULL
)
1388 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1390 // Cache is OK, Fin.
1391 if (CheckValidity(CacheFile
, List
, Files
.begin(),Files
.end(),OutMap
) == true)
1393 if (Progress
!= NULL
)
1394 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1396 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
1399 else if (Debug
== true)
1400 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
1402 /* At this point we know we need to reconstruct the package cache,
1404 SPtr
<FileFd
> CacheF
;
1405 SPtr
<DynamicMMap
> Map
;
1406 if (Writeable
== true && CacheFile
.empty() == false)
1408 _error
->PushToStack();
1409 unlink(CacheFile
.c_str());
1410 CacheF
= new FileFd(CacheFile
,FileFd::WriteAtomic
);
1411 fchmod(CacheF
->Fd(),0644);
1412 Map
= CreateDynamicMMap(CacheF
, MMap::Public
);
1413 if (_error
->PendingError() == true)
1415 delete CacheF
.UnGuard();
1416 delete Map
.UnGuard();
1418 std::clog
<< "Open filebased MMap FAILED" << std::endl
;
1420 if (AllowMem
== false)
1422 _error
->MergeWithStack();
1425 _error
->RevertToStack();
1429 _error
->MergeWithStack();
1431 std::clog
<< "Open filebased MMap" << std::endl
;
1434 if (Writeable
== false || CacheFile
.empty() == true)
1436 // Just build it in memory..
1437 Map
= CreateDynamicMMap(NULL
);
1439 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1442 // Lets try the source cache.
1443 map_filesize_t CurrentSize
= 0;
1444 map_filesize_t TotalSize
= 0;
1445 if (CheckValidity(SrcCacheFile
, List
, Files
.begin(),
1446 Files
.begin()+EndOfSource
) == true)
1449 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
1450 // Preload the map with the source cache
1451 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
1452 map_pointer_t
const alloc
= Map
->RawAllocate(SCacheF
.Size());
1453 if ((alloc
== 0 && _error
->PendingError())
1454 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1455 SCacheF
.Size()) == false)
1458 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1460 // Build the status cache
1461 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1462 if (_error
->PendingError() == true)
1464 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1465 Files
.begin()+EndOfSource
,Files
.end()) == false)
1471 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1472 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
1474 // Build the source cache
1475 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1476 if (_error
->PendingError() == true)
1478 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1479 Files
.begin(),Files
.begin()+EndOfSource
) == false)
1483 if (Writeable
== true && SrcCacheFile
.empty() == false)
1485 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteAtomic
);
1486 if (_error
->PendingError() == true)
1489 fchmod(SCacheF
.Fd(),0644);
1491 // Write out the main data
1492 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1493 return _error
->Error(_("IO Error saving source cache"));
1496 // Write out the proper header
1497 Gen
.GetCache().HeaderP
->Dirty
= false;
1498 if (SCacheF
.Seek(0) == false ||
1499 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1500 return _error
->Error(_("IO Error saving source cache"));
1501 Gen
.GetCache().HeaderP
->Dirty
= true;
1505 // Build the status cache
1506 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1507 Files
.begin()+EndOfSource
,Files
.end()) == false)
1511 std::clog
<< "Caches are ready for shipping" << std::endl
;
1513 if (_error
->PendingError() == true)
1519 delete Map
.UnGuard();
1520 *OutMap
= new MMap(*CacheF
,0);
1524 *OutMap
= Map
.UnGuard();
1531 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1532 // ---------------------------------------------------------------------
1534 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1535 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1536 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1538 std::vector
<pkgIndexFile
*> Files
;
1539 map_filesize_t EndOfSource
= Files
.size();
1540 if (_system
->AddStatusFiles(Files
) == false)
1543 SPtr
<DynamicMMap
> Map
= CreateDynamicMMap(NULL
);
1544 map_filesize_t CurrentSize
= 0;
1545 map_filesize_t TotalSize
= 0;
1547 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1549 // Build the status cache
1550 if (Progress
!= NULL
)
1551 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1552 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1553 if (_error
->PendingError() == true)
1555 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1556 Files
.begin()+EndOfSource
,Files
.end()) == false)
1559 if (_error
->PendingError() == true)
1561 *OutMap
= Map
.UnGuard();
1566 // IsDuplicateDescription /*{{{*/
1567 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1568 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1570 // Descriptions in the same link-list have all the same md5
1571 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1573 for (; Desc
.end() == false; ++Desc
)
1574 if (Desc
.LanguageCode() == CurLang
)
1579 // CacheGenerator::FinishCache /*{{{*/
1580 bool pkgCacheGenerator::FinishCache(OpProgress
* /*Progress*/)