]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
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
),
60 memset(UniqHash
,0,sizeof(UniqHash
));
62 if (_error
->PendingError() == true)
67 // Setup the map interface..
68 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
69 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
72 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
75 *Cache
.HeaderP
= pkgCache::Header();
76 map_ptrloc
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
77 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
78 // this pointer is set in ReMap, but we need it now for WriteUniqString
79 Cache
.StringItemP
= (pkgCache::StringItem
*)Map
.Data();
80 map_ptrloc
const idxArchitecture
= WriteUniqString(_config
->Find("APT::Architecture"));
81 Cache
.HeaderP
->Architecture
= idxArchitecture
;
82 if (unlikely(idxVerSysName
== 0 || idxArchitecture
== 0))
88 // Map directly from the existing file
90 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
91 if (Cache
.VS
!= _system
->VS
)
93 _error
->Error(_("Cache has an incompatible versioning system"));
98 Cache
.HeaderP
->Dirty
= true;
99 Map
.Sync(0,sizeof(pkgCache::Header
));
102 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
103 // ---------------------------------------------------------------------
104 /* We sync the data then unset the dirty flag in two steps so as to
105 advoid a problem during a crash */
106 pkgCacheGenerator::~pkgCacheGenerator()
108 if (_error
->PendingError() == true)
110 if (Map
.Sync() == false)
113 Cache
.HeaderP
->Dirty
= false;
114 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
115 Map
.Sync(0,sizeof(pkgCache::Header
));
118 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
119 if (oldMap
== newMap
)
122 if (_config
->FindB("Debug::pkgCacheGen", false))
123 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
127 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
129 for (size_t i
= 0; i
< _count(UniqHash
); ++i
)
130 if (UniqHash
[i
] != 0)
131 UniqHash
[i
] += (pkgCache::StringItem
const * const) newMap
- (pkgCache::StringItem
const * const) oldMap
;
133 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
134 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
135 (*i
)->ReMap(oldMap
, newMap
);
136 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
137 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
138 (*i
)->ReMap(oldMap
, newMap
);
139 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
140 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
141 (*i
)->ReMap(oldMap
, newMap
);
142 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
143 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
144 (*i
)->ReMap(oldMap
, newMap
);
145 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
146 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
147 (*i
)->ReMap(oldMap
, newMap
);
148 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
149 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
150 (*i
)->ReMap(oldMap
, newMap
);
151 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
152 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
153 (*i
)->ReMap(oldMap
, newMap
);
155 // CacheGenerator::WriteStringInMap /*{{{*/
156 map_ptrloc
pkgCacheGenerator::WriteStringInMap(const char *String
,
157 const unsigned long &Len
) {
158 void const * const oldMap
= Map
.Data();
159 map_ptrloc
const index
= Map
.WriteString(String
, Len
);
161 ReMap(oldMap
, Map
.Data());
165 // CacheGenerator::WriteStringInMap /*{{{*/
166 map_ptrloc
pkgCacheGenerator::WriteStringInMap(const char *String
) {
167 void const * const oldMap
= Map
.Data();
168 map_ptrloc
const index
= Map
.WriteString(String
);
170 ReMap(oldMap
, Map
.Data());
174 map_ptrloc
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
175 void const * const oldMap
= Map
.Data();
176 map_ptrloc
const index
= Map
.Allocate(size
);
178 ReMap(oldMap
, Map
.Data());
182 // CacheGenerator::MergeList - Merge the package list /*{{{*/
183 // ---------------------------------------------------------------------
184 /* This provides the generation of the entries in the cache. Each loop
185 goes through a single package record from the underlying parse engine. */
186 bool pkgCacheGenerator::MergeList(ListParser
&List
,
187 pkgCache::VerIterator
*OutVer
)
191 unsigned int Counter
= 0;
192 while (List
.Step() == true)
194 string
const PackageName
= List
.Package();
195 if (PackageName
.empty() == true)
199 if (Counter
% 100 == 0 && Progress
!= 0)
200 Progress
->Progress(List
.Offset());
202 string Arch
= List
.Architecture();
203 string
const Version
= List
.Version();
204 if (Version
.empty() == true && Arch
.empty() == true)
206 // package descriptions
207 if (MergeListGroup(List
, PackageName
) == false)
212 if (Arch
.empty() == true)
214 // use the pseudo arch 'none' for arch-less packages
216 /* We might built a SingleArchCache here, which we don't want to blow up
217 just for these :none packages to a proper MultiArchCache, so just ensure
218 that we have always a native package structure first for SingleArch */
219 pkgCache::PkgIterator NP
;
220 Dynamic
<pkgCache::PkgIterator
> DynPkg(NP
);
221 if (NewPackage(NP
, PackageName
, _config
->Find("APT::Architecture")) == false)
222 // TRANSLATOR: The first placeholder is a package name,
223 // the other two should be copied verbatim as they include debug info
224 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
225 PackageName
.c_str(), "NewPackage", 0);
228 // Get a pointer to the package structure
229 pkgCache::PkgIterator Pkg
;
230 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
231 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
232 // TRANSLATOR: The first placeholder is a package name,
233 // the other two should be copied verbatim as they include debug info
234 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
235 PackageName
.c_str(), "NewPackage", 1);
238 if (Version
.empty() == true)
240 if (MergeListPackage(List
, Pkg
) == false)
245 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
251 FoundFileDeps
|= List
.HasFileDeps();
256 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
257 return _error
->Error(_("Wow, you exceeded the number of package "
258 "names this APT is capable of."));
259 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
260 return _error
->Error(_("Wow, you exceeded the number of versions "
261 "this APT is capable of."));
262 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
263 return _error
->Error(_("Wow, you exceeded the number of descriptions "
264 "this APT is capable of."));
265 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
266 return _error
->Error(_("Wow, you exceeded the number of dependencies "
267 "this APT is capable of."));
269 FoundFileDeps
|= List
.HasFileDeps();
272 // CacheGenerator::MergeListGroup /*{{{*/
273 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
275 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
276 // a group has no data on it's own, only packages have it but these
277 // stanzas like this come from Translation- files to add descriptions,
278 // but without a version we don't need a description for it…
279 if (Grp
.end() == true)
281 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
283 pkgCache::PkgIterator Pkg
;
284 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
285 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
286 if (MergeListPackage(List
, Pkg
) == false)
292 // CacheGenerator::MergeListPackage /*{{{*/
293 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
295 // we first process the package, then the descriptions
296 // (for deb this package processing is in fact a no-op)
297 pkgCache::VerIterator
Ver(Cache
);
298 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
299 if (List
.UsePackage(Pkg
, Ver
) == false)
300 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
301 Pkg
.Name(), "UsePackage", 1);
303 // Find the right version to write the description
304 MD5SumValue CurMd5
= List
.Description_md5();
305 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
307 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
308 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
310 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
312 // a version can only have one md5 describing it
313 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
316 map_ptrloc md5idx
= VerDesc
->md5sum
;
317 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
319 // don't add a new description if we have one for the given
321 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
324 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
327 // we can stop here as all "same" versions will share the description
334 // CacheGenerator::MergeListVersion /*{{{*/
335 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
336 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
338 pkgCache::VerIterator Ver
= Pkg
.VersionList();
339 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
340 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
341 void const * oldMap
= Map
.Data();
343 unsigned short const Hash
= List
.VersionHash();
344 if (Ver
.end() == false)
346 /* We know the list is sorted so we use that fact in the search.
347 Insertion of new versions is done with correct sorting */
349 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
351 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
352 // Version is higher as current version - insert here
355 // Versionstrings are equal - is hash also equal?
356 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
358 // proceed with the next till we have either the right
359 // or we found another version (which will be lower)
362 /* We already have a version for this item, record that we saw it */
363 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
365 if (List
.UsePackage(Pkg
,Ver
) == false)
366 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
367 Pkg
.Name(), "UsePackage", 2);
369 if (NewFileVer(Ver
,List
) == false)
370 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
371 Pkg
.Name(), "NewFileVer", 1);
373 // Read only a single record and return
385 map_ptrloc
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
386 if (verindex
== 0 && _error
->PendingError())
387 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
388 Pkg
.Name(), "NewVersion", 1);
390 if (oldMap
!= Map
.Data())
391 LastVer
+= (map_ptrloc
const * const) Map
.Data() - (map_ptrloc
const * const) oldMap
;
394 if (unlikely(List
.NewVersion(Ver
) == false))
395 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
396 Pkg
.Name(), "NewVersion", 2);
398 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
399 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
400 Pkg
.Name(), "UsePackage", 3);
402 if (unlikely(NewFileVer(Ver
,List
) == false))
403 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
404 Pkg
.Name(), "NewFileVer", 2);
406 pkgCache::GrpIterator Grp
= Pkg
.Group();
407 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
409 /* If it is the first version of this package we need to add implicit
410 Multi-Arch dependencies to all other package versions in the group now -
411 otherwise we just add them for this new version */
412 if (Pkg
.VersionList()->NextVer
== 0)
414 pkgCache::PkgIterator P
= Grp
.PackageList();
415 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
416 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
418 if (P
->ID
== Pkg
->ID
)
420 pkgCache::VerIterator V
= P
.VersionList();
421 Dynamic
<pkgCache::VerIterator
> DynV(V
);
422 for (; V
.end() != true; ++V
)
423 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
424 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
425 Pkg
.Name(), "AddImplicitDepends", 1);
427 /* :none packages are packages without an architecture. They are forbidden by
428 debian-policy, so usually they will only be in (old) dpkg status files -
429 and dpkg will complain about them - and are pretty rare. We therefore do
430 usually not create conflicts while the parent is created, but only if a :none
431 package (= the target) appears. This creates incorrect dependencies on :none
432 for architecture-specific dependencies on the package we copy from, but we
433 will ignore this bug as architecture-specific dependencies are only allowed
434 in jessie and until then the :none packages should be extinct (hopefully).
435 In other words: This should work long enough to allow graceful removal of
436 these packages, it is not supposed to allow users to keep using them … */
437 if (strcmp(Pkg
.Arch(), "none") == 0)
439 pkgCache::PkgIterator M
= Grp
.FindPreferredPkg();
440 if (M
.end() == false && Pkg
!= M
)
442 pkgCache::DepIterator D
= M
.RevDependsList();
443 Dynamic
<pkgCache::DepIterator
> DynD(D
);
444 for (; D
.end() == false; ++D
)
446 if ((D
->Type
!= pkgCache::Dep::Conflicts
&&
447 D
->Type
!= pkgCache::Dep::DpkgBreaks
&&
448 D
->Type
!= pkgCache::Dep::Replaces
) ||
449 D
.ParentPkg().Group() == Grp
)
452 map_ptrloc
*OldDepLast
= NULL
;
453 pkgCache::VerIterator ConVersion
= D
.ParentVer();
454 Dynamic
<pkgCache::VerIterator
> DynV(ConVersion
);
455 // duplicate the Conflicts/Breaks/Replaces for :none arch
456 NewDepends(Pkg
, ConVersion
, D
->Version
,
457 D
->CompareOp
, D
->Type
, OldDepLast
);
462 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
463 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
464 Pkg
.Name(), "AddImplicitDepends", 2);
466 // Read only a single record and return
473 /* Record the Description(s) based on their master md5sum */
474 MD5SumValue CurMd5
= List
.Description_md5();
475 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
478 /* Before we add a new description we first search in the group for
479 a version with a description of the same MD5 - if so we reuse this
480 description group instead of creating our own for this version */
481 for (pkgCache::PkgIterator P
= Grp
.PackageList();
482 P
.end() == false; P
= Grp
.NextPkg(P
))
484 for (pkgCache::VerIterator V
= P
.VersionList();
485 V
.end() == false; ++V
)
487 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
489 Ver
->DescriptionList
= V
->DescriptionList
;
493 // We haven't found reusable descriptions, so add the first description(s)
494 map_ptrloc md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
495 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
496 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
497 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
502 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_ptrloc
&md5idx
) /*{{{*/
504 pkgCache::DescIterator Desc
;
505 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
507 map_ptrloc
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
508 if (unlikely(descindex
== 0 && _error
->PendingError()))
509 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
510 Ver
.ParentPkg().Name(), "NewDescription", 1);
512 md5idx
= Desc
->md5sum
;
513 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
515 // we add at the end, so that the start is constant as we need
516 // that to be able to efficiently share these lists
517 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
518 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
519 map_ptrloc
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
520 *LastNextDesc
= descindex
;
522 if (NewFileDesc(Desc
,List
) == false)
523 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
524 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
530 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
531 // ---------------------------------------------------------------------
532 /* If we found any file depends while parsing the main list we need to
533 resolve them. Since it is undesired to load the entire list of files
534 into the cache as virtual packages we do a two stage effort. MergeList
535 identifies the file depends and this creates Provdies for them by
536 re-parsing all the indexs. */
537 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
541 unsigned int Counter
= 0;
542 while (List
.Step() == true)
544 string PackageName
= List
.Package();
545 if (PackageName
.empty() == true)
547 string Version
= List
.Version();
548 if (Version
.empty() == true)
551 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
552 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
553 if (Pkg
.end() == true)
554 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
555 PackageName
.c_str(), "FindPkg", 1);
557 if (Counter
% 100 == 0 && Progress
!= 0)
558 Progress
->Progress(List
.Offset());
560 unsigned short Hash
= List
.VersionHash();
561 pkgCache::VerIterator Ver
= Pkg
.VersionList();
562 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
563 for (; Ver
.end() == false; ++Ver
)
565 if (List
.SameVersion(Hash
, Ver
) == true && Version
== Ver
.VerStr())
567 if (List
.CollectFileProvides(Cache
,Ver
) == false)
568 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
569 PackageName
.c_str(), "CollectFileProvides", 1);
574 if (Ver
.end() == true)
575 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
581 // CacheGenerator::NewGroup - Add a new group /*{{{*/
582 // ---------------------------------------------------------------------
583 /* This creates a new group structure and adds it to the hash table */
584 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
586 Grp
= Cache
.FindGrp(Name
);
587 if (Grp
.end() == false)
591 map_ptrloc
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
592 if (unlikely(Group
== 0))
595 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
596 map_ptrloc
const idxName
= WriteStringInMap(Name
);
597 if (unlikely(idxName
== 0))
601 // Insert it into the hash table
602 unsigned long const Hash
= Cache
.Hash(Name
);
603 map_ptrloc
*insertAt
= &Cache
.HeaderP
->GrpHashTable
[Hash
];
604 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
605 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
606 Grp
->Next
= *insertAt
;
609 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
613 // CacheGenerator::NewPackage - Add a new package /*{{{*/
614 // ---------------------------------------------------------------------
615 /* This creates a new package structure and adds it to the hash table */
616 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
617 const string
&Arch
) {
618 pkgCache::GrpIterator Grp
;
619 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
620 if (unlikely(NewGroup(Grp
, Name
) == false))
623 Pkg
= Grp
.FindPkg(Arch
);
624 if (Pkg
.end() == false)
628 map_ptrloc
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
629 if (unlikely(Package
== 0))
631 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
633 // Insert the package into our package list
634 if (Grp
->FirstPackage
== 0) // the group is new
636 Grp
->FirstPackage
= Package
;
637 // Insert it into the hash table
638 unsigned long const Hash
= Cache
.Hash(Name
);
639 map_ptrloc
*insertAt
= &Cache
.HeaderP
->PkgHashTable
[Hash
];
640 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.PkgP
+ *insertAt
)->Name
) > 0)
641 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
642 Pkg
->NextPackage
= *insertAt
;
645 else // Group the Packages together
647 // this package is the new last package
648 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
649 Pkg
->NextPackage
= LastPkg
->NextPackage
;
650 LastPkg
->NextPackage
= Package
;
652 Grp
->LastPackage
= Package
;
654 // Set the name, arch and the ID
655 Pkg
->Name
= Grp
->Name
;
656 Pkg
->Group
= Grp
.Index();
657 // all is mapped to the native architecture
658 map_ptrloc
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: WriteUniqString(Arch
.c_str());
659 if (unlikely(idxArch
== 0))
662 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
667 // CacheGenerator::AddImplicitDepends /*{{{*/
668 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
669 pkgCache::PkgIterator
&P
,
670 pkgCache::VerIterator
&V
)
672 // copy P.Arch() into a string here as a cache remap
673 // in NewDepends() later may alter the pointer location
674 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
675 map_ptrloc
*OldDepLast
= NULL
;
676 /* MultiArch handling introduces a lot of implicit Dependencies:
677 - MultiArch: same → Co-Installable if they have the same version
678 - All others conflict with all other group members */
679 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
680 pkgCache::PkgIterator D
= G
.PackageList();
681 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
682 map_ptrloc
const VerStrIdx
= V
->VerStr
;
683 for (; D
.end() != true; D
= G
.NextPkg(D
))
685 if (Arch
== D
.Arch() || D
->VersionList
== 0)
687 /* We allow only one installed arch at the time
688 per group, therefore each group member conflicts
689 with all other group members */
690 if (coInstall
== true)
692 // Replaces: ${self}:other ( << ${binary:Version})
693 NewDepends(D
, V
, VerStrIdx
,
694 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
696 // Breaks: ${self}:other (!= ${binary:Version})
697 NewDepends(D
, V
, VerStrIdx
,
698 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
701 // Conflicts: ${self}:other
703 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
709 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
710 pkgCache::PkgIterator
&D
)
712 /* MultiArch handling introduces a lot of implicit Dependencies:
713 - MultiArch: same → Co-Installable if they have the same version
714 - All others conflict with all other group members */
715 map_ptrloc
*OldDepLast
= NULL
;
716 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
717 if (coInstall
== true)
719 map_ptrloc
const VerStrIdx
= V
->VerStr
;
720 // Replaces: ${self}:other ( << ${binary:Version})
721 NewDepends(D
, V
, VerStrIdx
,
722 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
724 // Breaks: ${self}:other (!= ${binary:Version})
725 NewDepends(D
, V
, VerStrIdx
,
726 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
729 // Conflicts: ${self}:other
731 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
738 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
739 // ---------------------------------------------------------------------
741 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
744 if (CurrentFile
== 0)
748 map_ptrloc
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
752 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
753 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
755 // Link it to the end of the list
756 map_ptrloc
*Last
= &Ver
->FileList
;
757 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
759 VF
->NextFile
= *Last
;
762 VF
->Offset
= List
.Offset();
763 VF
->Size
= List
.Size();
764 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
765 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
766 Cache
.HeaderP
->VerFileCount
++;
771 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
772 // ---------------------------------------------------------------------
773 /* This puts a version structure in the linked list */
774 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
775 const string
&VerStr
,
776 map_ptrloc
const ParentPkg
,
777 unsigned long const Hash
,
781 map_ptrloc
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
786 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
787 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
789 Ver
->ParentPkg
= ParentPkg
;
791 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
793 // try to find the version string in the group for reuse
794 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
795 pkgCache::GrpIterator Grp
= Pkg
.Group();
796 if (Pkg
.end() == false && Grp
.end() == false)
798 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
802 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
804 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
807 Ver
->VerStr
= V
->VerStr
;
815 // haven't found the version string, so create
816 map_ptrloc
const idxVerStr
= WriteStringInMap(VerStr
);
817 if (unlikely(idxVerStr
== 0))
819 Ver
->VerStr
= idxVerStr
;
823 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
824 // ---------------------------------------------------------------------
826 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
829 if (CurrentFile
== 0)
833 map_ptrloc
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
837 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
838 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
840 // Link it to the end of the list
841 map_ptrloc
*Last
= &Desc
->FileList
;
842 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
845 DF
->NextFile
= *Last
;
848 DF
->Offset
= List
.Offset();
849 DF
->Size
= List
.Size();
850 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
851 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
852 Cache
.HeaderP
->DescFileCount
++;
857 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
858 // ---------------------------------------------------------------------
859 /* This puts a description structure in the linked list */
860 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
862 const MD5SumValue
&md5sum
,
863 map_ptrloc idxmd5str
)
866 map_ptrloc
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
867 if (Description
== 0)
871 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
872 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
873 map_ptrloc
const idxlanguage_code
= WriteUniqString(Lang
);
874 if (unlikely(idxlanguage_code
== 0))
876 Desc
->language_code
= idxlanguage_code
;
879 Desc
->md5sum
= idxmd5str
;
882 map_ptrloc
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
883 if (unlikely(idxmd5sum
== 0))
885 Desc
->md5sum
= idxmd5sum
;
891 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
892 // ---------------------------------------------------------------------
893 /* This creates a dependency element in the tree. It is linked to the
894 version and to the package that it is pointing to. */
895 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
896 pkgCache::VerIterator
&Ver
,
897 string
const &Version
,
898 unsigned int const &Op
,
899 unsigned int const &Type
,
900 map_ptrloc
* &OldDepLast
)
902 map_ptrloc index
= 0;
903 if (Version
.empty() == false)
905 int const CmpOp
= Op
& 0x0F;
906 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
907 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
912 void const * const oldMap
= Map
.Data();
913 index
= WriteStringInMap(Version
);
914 if (unlikely(index
== 0))
916 if (OldDepLast
!= 0 && oldMap
!= Map
.Data())
917 OldDepLast
+= (map_ptrloc
const * const) Map
.Data() - (map_ptrloc
const * const) oldMap
;
920 return NewDepends(Pkg
, Ver
, index
, Op
, Type
, OldDepLast
);
922 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
923 pkgCache::VerIterator
&Ver
,
924 map_ptrloc
const Version
,
925 unsigned int const &Op
,
926 unsigned int const &Type
,
927 map_ptrloc
* &OldDepLast
)
929 void const * const oldMap
= Map
.Data();
931 map_ptrloc
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
932 if (unlikely(Dependency
== 0))
936 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
937 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
938 Dep
->ParentVer
= Ver
.Index();
941 Dep
->Version
= Version
;
942 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
944 // Link it to the package
945 Dep
->Package
= Pkg
.Index();
946 Dep
->NextRevDepends
= Pkg
->RevDepends
;
947 Pkg
->RevDepends
= Dep
.Index();
949 // Do we know where to link the Dependency to?
950 if (OldDepLast
== NULL
)
952 OldDepLast
= &Ver
->DependsList
;
953 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
954 OldDepLast
= &D
->NextDepends
;
955 } else if (oldMap
!= Map
.Data())
956 OldDepLast
+= (map_ptrloc
const * const) Map
.Data() - (map_ptrloc
const * const) oldMap
;
958 Dep
->NextDepends
= *OldDepLast
;
959 *OldDepLast
= Dep
.Index();
960 OldDepLast
= &Dep
->NextDepends
;
965 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
966 // ---------------------------------------------------------------------
967 /* This creates a Group and the Package to link this dependency to if
968 needed and handles also the caching of the old endpoint */
969 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator
&Ver
,
970 const string
&PackageName
,
972 const string
&Version
,
976 pkgCache::GrpIterator Grp
;
977 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
978 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
981 // Locate the target package
982 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(Arch
);
983 // we don't create 'none' packages and their dependencies if we can avoid it …
984 if (Pkg
.end() == true && Arch
== "none" && strcmp(Ver
.ParentPkg().Arch(), "none") != 0)
986 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
987 if (Pkg
.end() == true) {
988 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
992 // Is it a file dependency?
993 if (unlikely(PackageName
[0] == '/'))
994 FoundFileDeps
= true;
996 /* Caching the old end point speeds up generation substantially */
997 if (OldDepVer
!= Ver
) {
1002 return Owner
->NewDepends(Pkg
, Ver
, Version
, Op
, Type
, OldDepLast
);
1005 // ListParser::NewProvides - Create a Provides element /*{{{*/
1006 // ---------------------------------------------------------------------
1008 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1009 const string
&PkgName
,
1010 const string
&PkgArch
,
1011 const string
&Version
)
1013 pkgCache
&Cache
= Owner
->Cache
;
1015 // We do not add self referencing provides
1016 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1017 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1021 map_ptrloc
const Provides
= Owner
->AllocateInMap(sizeof(pkgCache::Provides
));
1022 if (unlikely(Provides
== 0))
1024 Cache
.HeaderP
->ProvidesCount
++;
1027 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1028 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
1029 Prv
->Version
= Ver
.Index();
1030 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1031 Ver
->ProvidesList
= Prv
.Index();
1032 if (Version
.empty() == false) {
1033 map_ptrloc
const idxProvideVersion
= WriteString(Version
);
1034 Prv
->ProvideVersion
= idxProvideVersion
;
1035 if (unlikely(idxProvideVersion
== 0))
1039 // Locate the target package
1040 pkgCache::PkgIterator Pkg
;
1041 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1042 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1045 // Link it to the package
1046 Prv
->ParentPkg
= Pkg
.Index();
1047 Prv
->NextProvides
= Pkg
->ProvidesList
;
1048 Pkg
->ProvidesList
= Prv
.Index();
1053 bool pkgCacheGenerator::ListParser::SameVersion(unsigned short const Hash
,/*{{{*/
1054 pkgCache::VerIterator
const &Ver
)
1056 return Hash
== Ver
->Hash
;
1059 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1060 // ---------------------------------------------------------------------
1061 /* This is used to select which file is to be associated with all newly
1062 added versions. The caller is responsible for setting the IMS fields. */
1063 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
1064 const pkgIndexFile
&Index
,
1065 unsigned long Flags
)
1067 // Get some space for the structure
1068 map_ptrloc
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1069 if (unlikely(idxFile
== 0))
1071 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1074 map_ptrloc
const idxFileName
= WriteStringInMap(File
);
1075 map_ptrloc
const idxSite
= WriteUniqString(Site
);
1076 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1078 CurrentFile
->FileName
= idxFileName
;
1079 CurrentFile
->Site
= idxSite
;
1080 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1081 CurrentFile
->Flags
= Flags
;
1082 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1083 map_ptrloc
const idxIndexType
= WriteUniqString(Index
.GetType()->Label
);
1084 if (unlikely(idxIndexType
== 0))
1086 CurrentFile
->IndexType
= idxIndexType
;
1088 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1089 Cache
.HeaderP
->PackageFileCount
++;
1092 Progress
->SubProgress(Index
.Size());
1096 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1097 // ---------------------------------------------------------------------
1098 /* This is used to create handles to strings. Given the same text it
1099 always returns the same number */
1100 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
1103 /* We use a very small transient hash table here, this speeds up generation
1104 by a fair amount on slower machines */
1105 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
1107 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
1108 return Bucket
->String
;
1110 // Search for an insertion point
1111 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
1113 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
1114 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
1115 I
= Cache
.StringItemP
+ I
->NextItem
)
1117 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
1130 void const * const oldMap
= Map
.Data();
1131 map_ptrloc
const Item
= AllocateInMap(sizeof(pkgCache::StringItem
));
1135 map_ptrloc
const idxString
= WriteStringInMap(S
,Size
);
1136 if (unlikely(idxString
== 0))
1138 if (oldMap
!= Map
.Data()) {
1139 Last
+= (map_ptrloc
const * const) Map
.Data() - (map_ptrloc
const * const) oldMap
;
1140 I
+= (pkgCache::StringItem
const * const) Map
.Data() - (pkgCache::StringItem
const * const) oldMap
;
1144 // Fill in the structure
1145 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
1146 ItemP
->NextItem
= I
- Cache
.StringItemP
;
1147 ItemP
->String
= idxString
;
1150 return ItemP
->String
;
1153 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1154 // ---------------------------------------------------------------------
1155 /* This just verifies that each file in the list of index files exists,
1156 has matching attributes with the cache and the cache does not have
1158 static bool CheckValidity(const string
&CacheFile
,
1159 pkgSourceList
&List
,
1164 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1165 // No file, certainly invalid
1166 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1169 std::clog
<< "CacheFile doesn't exist" << std::endl
;
1173 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1176 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1181 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1182 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
1183 pkgCache
Cache(Map
);
1184 if (_error
->PendingError() == true || Map
->Size() == 0)
1187 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
1192 /* Now we check every index file, see if it is in the cache,
1193 verify the IMS data and check that it is on the disk too.. */
1194 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
1195 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
1196 for (; Start
!= End
; ++Start
)
1199 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
1200 if ((*Start
)->HasPackages() == false)
1203 std::clog
<< "Has NO packages" << std::endl
;
1207 if ((*Start
)->Exists() == false)
1209 #if 0 // mvo: we no longer give a message here (Default Sources spec)
1210 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
1211 (*Start
)->Describe().c_str());
1214 std::clog
<< "file doesn't exist" << std::endl
;
1218 // FindInCache is also expected to do an IMS check.
1219 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
1220 if (File
.end() == true)
1223 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1227 Visited
[File
->ID
] = true;
1229 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1232 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1233 if (Visited
[I
] == false)
1236 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
1240 if (_error
->PendingError() == true)
1244 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1245 _error
->DumpErrors();
1252 *OutMap
= Map
.UnGuard();
1256 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1257 // ---------------------------------------------------------------------
1258 /* Size is kind of an abstract notion that is only used for the progress
1260 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
1262 unsigned long TotalSize
= 0;
1263 for (; Start
< End
; ++Start
)
1265 if ((*Start
)->HasPackages() == false)
1267 TotalSize
+= (*Start
)->Size();
1272 // BuildCache - Merge the list of index files into the cache /*{{{*/
1273 // ---------------------------------------------------------------------
1275 static bool BuildCache(pkgCacheGenerator
&Gen
,
1276 OpProgress
*Progress
,
1277 unsigned long &CurrentSize
,unsigned long TotalSize
,
1278 FileIterator Start
, FileIterator End
)
1281 for (I
= Start
; I
!= End
; ++I
)
1283 if ((*I
)->HasPackages() == false)
1286 if ((*I
)->Exists() == false)
1289 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
1291 _error
->Warning("Duplicate sources.list entry %s",
1292 (*I
)->Describe().c_str());
1296 unsigned long Size
= (*I
)->Size();
1297 if (Progress
!= NULL
)
1298 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
1299 CurrentSize
+= Size
;
1301 if ((*I
)->Merge(Gen
,Progress
) == false)
1305 if (Gen
.HasFileDeps() == true)
1307 if (Progress
!= NULL
)
1309 TotalSize
= ComputeSize(Start
, End
);
1311 for (I
= Start
; I
!= End
; ++I
)
1313 unsigned long Size
= (*I
)->Size();
1314 if (Progress
!= NULL
)
1315 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
1316 CurrentSize
+= Size
;
1317 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
1325 // CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
1326 DynamicMMap
* pkgCacheGenerator::CreateDynamicMMap(FileFd
*CacheF
, unsigned long Flags
) {
1327 unsigned long const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1328 unsigned long const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1329 unsigned long const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1330 Flags
|= MMap::Moveable
;
1331 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1332 Flags
|= MMap::Fallback
;
1334 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1336 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1339 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1340 // ---------------------------------------------------------------------
1341 /* This makes sure that the status cache (the cache that has all
1342 index files from the sources list and all local ones) is ready
1343 to be mmaped. If OutMap is not zero then a MMap object representing
1344 the cache will be stored there. This is pretty much mandetory if you
1345 are using AllowMem. AllowMem lets the function be run as non-root
1346 where it builds the cache 'fast' into a memory buffer. */
1347 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1348 MMap
**OutMap
, bool AllowMem
)
1349 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1350 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1351 MMap
**OutMap
,bool AllowMem
)
1353 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1355 std::vector
<pkgIndexFile
*> Files
;
1356 for (std::vector
<metaIndex
*>::const_iterator i
= List
.begin();
1360 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1361 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
1362 j
!= Indexes
->end();
1364 Files
.push_back (*j
);
1367 unsigned long const EndOfSource
= Files
.size();
1368 if (_system
->AddStatusFiles(Files
) == false)
1371 // Decide if we can write to the files..
1372 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1373 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1375 // ensure the cache directory exists
1376 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1378 string dir
= _config
->FindDir("Dir::Cache");
1379 size_t const len
= dir
.size();
1380 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1381 dir
= dir
.substr(0, len
- 5);
1382 if (CacheFile
.empty() == false)
1383 CreateDirectory(dir
, flNotFile(CacheFile
));
1384 if (SrcCacheFile
.empty() == false)
1385 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1388 // Decide if we can write to the cache
1389 bool Writeable
= false;
1390 if (CacheFile
.empty() == false)
1391 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1393 if (SrcCacheFile
.empty() == false)
1394 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1396 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1398 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
1399 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1401 if (Progress
!= NULL
)
1402 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1404 // Cache is OK, Fin.
1405 if (CheckValidity(CacheFile
, List
, Files
.begin(),Files
.end(),OutMap
) == true)
1407 if (Progress
!= NULL
)
1408 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1410 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
1413 else if (Debug
== true)
1414 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
1416 /* At this point we know we need to reconstruct the package cache,
1418 SPtr
<FileFd
> CacheF
;
1419 SPtr
<DynamicMMap
> Map
;
1420 if (Writeable
== true && CacheFile
.empty() == false)
1422 _error
->PushToStack();
1423 unlink(CacheFile
.c_str());
1424 CacheF
= new FileFd(CacheFile
,FileFd::WriteAtomic
);
1425 fchmod(CacheF
->Fd(),0644);
1426 Map
= CreateDynamicMMap(CacheF
, MMap::Public
);
1427 if (_error
->PendingError() == true)
1429 delete CacheF
.UnGuard();
1430 delete Map
.UnGuard();
1432 std::clog
<< "Open filebased MMap FAILED" << std::endl
;
1434 if (AllowMem
== false)
1436 _error
->MergeWithStack();
1439 _error
->RevertToStack();
1443 _error
->MergeWithStack();
1445 std::clog
<< "Open filebased MMap" << std::endl
;
1448 if (Writeable
== false || CacheFile
.empty() == true)
1450 // Just build it in memory..
1451 Map
= CreateDynamicMMap(NULL
);
1453 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1456 // Lets try the source cache.
1457 unsigned long CurrentSize
= 0;
1458 unsigned long TotalSize
= 0;
1459 if (CheckValidity(SrcCacheFile
, List
, Files
.begin(),
1460 Files
.begin()+EndOfSource
) == true)
1463 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
1464 // Preload the map with the source cache
1465 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
1466 unsigned long const alloc
= Map
->RawAllocate(SCacheF
.Size());
1467 if ((alloc
== 0 && _error
->PendingError())
1468 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1469 SCacheF
.Size()) == false)
1472 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1474 // Build the status cache
1475 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1476 if (_error
->PendingError() == true)
1478 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1479 Files
.begin()+EndOfSource
,Files
.end()) == false)
1485 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1486 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
1488 // Build the source cache
1489 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1490 if (_error
->PendingError() == true)
1492 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1493 Files
.begin(),Files
.begin()+EndOfSource
) == false)
1497 if (Writeable
== true && SrcCacheFile
.empty() == false)
1499 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteAtomic
);
1500 if (_error
->PendingError() == true)
1503 fchmod(SCacheF
.Fd(),0644);
1505 // Write out the main data
1506 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1507 return _error
->Error(_("IO Error saving source cache"));
1510 // Write out the proper header
1511 Gen
.GetCache().HeaderP
->Dirty
= false;
1512 if (SCacheF
.Seek(0) == false ||
1513 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1514 return _error
->Error(_("IO Error saving source cache"));
1515 Gen
.GetCache().HeaderP
->Dirty
= true;
1519 // Build the status cache
1520 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1521 Files
.begin()+EndOfSource
,Files
.end()) == false)
1525 std::clog
<< "Caches are ready for shipping" << std::endl
;
1527 if (_error
->PendingError() == true)
1533 delete Map
.UnGuard();
1534 *OutMap
= new MMap(*CacheF
,0);
1538 *OutMap
= Map
.UnGuard();
1545 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1546 // ---------------------------------------------------------------------
1548 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1549 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1550 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1552 std::vector
<pkgIndexFile
*> Files
;
1553 unsigned long EndOfSource
= Files
.size();
1554 if (_system
->AddStatusFiles(Files
) == false)
1557 SPtr
<DynamicMMap
> Map
= CreateDynamicMMap(NULL
);
1558 unsigned long CurrentSize
= 0;
1559 unsigned long TotalSize
= 0;
1561 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1563 // Build the status cache
1564 if (Progress
!= NULL
)
1565 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1566 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1567 if (_error
->PendingError() == true)
1569 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1570 Files
.begin()+EndOfSource
,Files
.end()) == false)
1573 if (_error
->PendingError() == true)
1575 *OutMap
= Map
.UnGuard();
1580 // IsDuplicateDescription /*{{{*/
1581 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1582 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1584 // Descriptions in the same link-list have all the same md5
1585 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1587 for (; Desc
.end() == false; ++Desc
)
1588 if (Desc
.LanguageCode() == CurLang
)
1593 // CacheGenerator::FinishCache /*{{{*/
1594 bool pkgCacheGenerator::FinishCache(OpProgress
* /*Progress*/)