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
),
57 CurrentRlsFile(NULL
), CurrentFile(NULL
), FoundFileDeps(0), d(NULL
)
59 if (_error
->PendingError() == true)
64 // Setup the map interface..
65 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
66 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
69 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
72 *Cache
.HeaderP
= pkgCache::Header();
74 // make room for the hashtables for packages and groups
75 if (Map
.RawAllocate(2 * (Cache
.HeaderP
->GetHashTableSize() * sizeof(map_pointer_t
))) == 0)
78 map_stringitem_t
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
79 if (unlikely(idxVerSysName
== 0))
81 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
82 map_stringitem_t
const idxArchitecture
= StoreString(MIXED
, _config
->Find("APT::Architecture"));
83 if (unlikely(idxArchitecture
== 0))
85 Cache
.HeaderP
->Architecture
= idxArchitecture
;
87 std::vector
<std::string
> archs
= APT::Configuration::getArchitectures();
90 std::vector
<std::string
>::const_iterator a
= archs
.begin();
91 std::string list
= *a
;
92 for (++a
; a
!= archs
.end(); ++a
)
93 list
.append(",").append(*a
);
94 map_stringitem_t
const idxArchitectures
= WriteStringInMap(list
);
95 if (unlikely(idxArchitectures
== 0))
97 Cache
.HeaderP
->SetArchitectures(idxArchitectures
);
100 Cache
.HeaderP
->SetArchitectures(idxArchitecture
);
106 // Map directly from the existing file
108 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
109 if (Cache
.VS
!= _system
->VS
)
111 _error
->Error(_("Cache has an incompatible versioning system"));
116 Cache
.HeaderP
->Dirty
= true;
117 Map
.Sync(0,sizeof(pkgCache::Header
));
120 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
121 // ---------------------------------------------------------------------
122 /* We sync the data then unset the dirty flag in two steps so as to
123 advoid a problem during a crash */
124 pkgCacheGenerator::~pkgCacheGenerator()
126 if (_error
->PendingError() == true)
128 if (Map
.Sync() == false)
131 Cache
.HeaderP
->Dirty
= false;
132 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
133 Map
.Sync(0,sizeof(pkgCache::Header
));
136 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
137 if (oldMap
== newMap
)
140 if (_config
->FindB("Debug::pkgCacheGen", false))
141 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
145 CurrentFile
+= (pkgCache::PackageFile
const * const) newMap
- (pkgCache::PackageFile
const * const) oldMap
;
146 CurrentRlsFile
+= (pkgCache::ReleaseFile
const * const) newMap
- (pkgCache::ReleaseFile
const * const) oldMap
;
148 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
149 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
150 (*i
)->ReMap(oldMap
, newMap
);
151 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
152 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
153 (*i
)->ReMap(oldMap
, newMap
);
154 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
155 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
156 (*i
)->ReMap(oldMap
, newMap
);
157 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
158 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
159 (*i
)->ReMap(oldMap
, newMap
);
160 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
161 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
162 (*i
)->ReMap(oldMap
, newMap
);
163 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
164 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
165 (*i
)->ReMap(oldMap
, newMap
);
166 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
167 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
168 (*i
)->ReMap(oldMap
, newMap
);
169 for (std::vector
<pkgCache::RlsFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.begin();
170 i
!= Dynamic
<pkgCache::RlsFileIterator
>::toReMap
.end(); ++i
)
171 (*i
)->ReMap(oldMap
, newMap
);
173 // CacheGenerator::WriteStringInMap /*{{{*/
174 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
,
175 const unsigned long &Len
) {
176 void const * const oldMap
= Map
.Data();
177 map_stringitem_t
const index
= Map
.WriteString(String
, Len
);
179 ReMap(oldMap
, Map
.Data());
183 // CacheGenerator::WriteStringInMap /*{{{*/
184 map_stringitem_t
pkgCacheGenerator::WriteStringInMap(const char *String
) {
185 void const * const oldMap
= Map
.Data();
186 map_stringitem_t
const index
= Map
.WriteString(String
);
188 ReMap(oldMap
, Map
.Data());
192 map_pointer_t
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
193 void const * const oldMap
= Map
.Data();
194 map_pointer_t
const index
= Map
.Allocate(size
);
196 ReMap(oldMap
, Map
.Data());
200 // CacheGenerator::MergeList - Merge the package list /*{{{*/
201 // ---------------------------------------------------------------------
202 /* This provides the generation of the entries in the cache. Each loop
203 goes through a single package record from the underlying parse engine. */
204 bool pkgCacheGenerator::MergeList(ListParser
&List
,
205 pkgCache::VerIterator
*OutVer
)
209 unsigned int Counter
= 0;
210 while (List
.Step() == true)
212 string
const PackageName
= List
.Package();
213 if (PackageName
.empty() == true)
217 if (Counter
% 100 == 0 && Progress
!= 0)
218 Progress
->Progress(List
.Offset());
220 string Arch
= List
.Architecture();
221 string
const Version
= List
.Version();
222 if (Version
.empty() == true && Arch
.empty() == true)
224 // package descriptions
225 if (MergeListGroup(List
, PackageName
) == false)
230 if (Arch
.empty() == true)
232 // use the pseudo arch 'none' for arch-less packages
234 /* We might built a SingleArchCache here, which we don't want to blow up
235 just for these :none packages to a proper MultiArchCache, so just ensure
236 that we have always a native package structure first for SingleArch */
237 pkgCache::PkgIterator NP
;
238 Dynamic
<pkgCache::PkgIterator
> DynPkg(NP
);
239 if (NewPackage(NP
, PackageName
, _config
->Find("APT::Architecture")) == false)
240 // TRANSLATOR: The first placeholder is a package name,
241 // the other two should be copied verbatim as they include debug info
242 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
243 PackageName
.c_str(), "NewPackage", 0);
246 // Get a pointer to the package structure
247 pkgCache::PkgIterator Pkg
;
248 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
249 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
250 // TRANSLATOR: The first placeholder is a package name,
251 // the other two should be copied verbatim as they include debug info
252 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
253 PackageName
.c_str(), "NewPackage", 1);
256 if (Version
.empty() == true)
258 if (MergeListPackage(List
, Pkg
) == false)
263 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
269 FoundFileDeps
|= List
.HasFileDeps();
274 if (Cache
.HeaderP
->PackageCount
>= std::numeric_limits
<map_id_t
>::max())
275 return _error
->Error(_("Wow, you exceeded the number of package "
276 "names this APT is capable of."));
277 if (Cache
.HeaderP
->VersionCount
>= std::numeric_limits
<map_id_t
>::max())
278 return _error
->Error(_("Wow, you exceeded the number of versions "
279 "this APT is capable of."));
280 if (Cache
.HeaderP
->DescriptionCount
>= std::numeric_limits
<map_id_t
>::max())
281 return _error
->Error(_("Wow, you exceeded the number of descriptions "
282 "this APT is capable of."));
283 if (Cache
.HeaderP
->DependsCount
>= std::numeric_limits
<map_id_t
>::max())
284 return _error
->Error(_("Wow, you exceeded the number of dependencies "
285 "this APT is capable of."));
287 FoundFileDeps
|= List
.HasFileDeps();
290 // CacheGenerator::MergeListGroup /*{{{*/
291 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
293 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
294 // a group has no data on it's own, only packages have it but these
295 // stanzas like this come from Translation- files to add descriptions,
296 // but without a version we don't need a description for it…
297 if (Grp
.end() == true)
299 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
301 pkgCache::PkgIterator Pkg
;
302 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
303 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
304 if (MergeListPackage(List
, Pkg
) == false)
310 // CacheGenerator::MergeListPackage /*{{{*/
311 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
313 // we first process the package, then the descriptions
314 // (for deb this package processing is in fact a no-op)
315 pkgCache::VerIterator
Ver(Cache
);
316 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
317 if (List
.UsePackage(Pkg
, Ver
) == false)
318 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
319 Pkg
.Name(), "UsePackage", 1);
321 // Find the right version to write the description
322 MD5SumValue CurMd5
= List
.Description_md5();
323 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
325 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
326 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
328 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList();
330 // a version can only have one md5 describing it
331 if (VerDesc
.end() == true || MD5SumValue(VerDesc
.md5()) != CurMd5
)
334 map_stringitem_t md5idx
= VerDesc
->md5sum
;
335 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
337 // don't add a new description if we have one for the given
339 if (IsDuplicateDescription(VerDesc
, CurMd5
, *CurLang
) == true)
342 AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
);
345 // we can stop here as all "same" versions will share the description
352 // CacheGenerator::MergeListVersion /*{{{*/
353 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
354 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
356 pkgCache::VerIterator Ver
= Pkg
.VersionList();
357 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
358 map_pointer_t
*LastVer
= &Pkg
->VersionList
;
359 void const * oldMap
= Map
.Data();
361 unsigned short const Hash
= List
.VersionHash();
362 if (Ver
.end() == false)
364 /* We know the list is sorted so we use that fact in the search.
365 Insertion of new versions is done with correct sorting */
367 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, ++Ver
)
369 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
370 // Version is higher as current version - insert here
373 // Versionstrings are equal - is hash also equal?
374 if (Res
== 0 && List
.SameVersion(Hash
, Ver
) == true)
376 // proceed with the next till we have either the right
377 // or we found another version (which will be lower)
380 /* We already have a version for this item, record that we saw it */
381 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
383 if (List
.UsePackage(Pkg
,Ver
) == false)
384 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
385 Pkg
.Name(), "UsePackage", 2);
387 if (NewFileVer(Ver
,List
) == false)
388 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
389 Pkg
.Name(), "NewFileVer", 1);
391 // Read only a single record and return
403 map_pointer_t
const verindex
= NewVersion(Ver
, Version
, Pkg
.Index(), Hash
, *LastVer
);
404 if (verindex
== 0 && _error
->PendingError())
405 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
406 Pkg
.Name(), "NewVersion", 1);
408 if (oldMap
!= Map
.Data())
409 LastVer
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
412 if (unlikely(List
.NewVersion(Ver
) == false))
413 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
414 Pkg
.Name(), "NewVersion", 2);
416 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
417 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
418 Pkg
.Name(), "UsePackage", 3);
420 if (unlikely(NewFileVer(Ver
,List
) == false))
421 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
422 Pkg
.Name(), "NewFileVer", 2);
424 pkgCache::GrpIterator Grp
= Pkg
.Group();
425 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
427 /* If it is the first version of this package we need to add implicit
428 Multi-Arch dependencies to all other package versions in the group now -
429 otherwise we just add them for this new version */
430 if (Pkg
.VersionList()->NextVer
== 0)
432 pkgCache::PkgIterator P
= Grp
.PackageList();
433 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
434 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
436 if (P
->ID
== Pkg
->ID
)
438 pkgCache::VerIterator V
= P
.VersionList();
439 Dynamic
<pkgCache::VerIterator
> DynV(V
);
440 for (; V
.end() != true; ++V
)
441 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
442 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
443 Pkg
.Name(), "AddImplicitDepends", 1);
445 /* :none packages are packages without an architecture. They are forbidden by
446 debian-policy, so usually they will only be in (old) dpkg status files -
447 and dpkg will complain about them - and are pretty rare. We therefore do
448 usually not create conflicts while the parent is created, but only if a :none
449 package (= the target) appears. This creates incorrect dependencies on :none
450 for architecture-specific dependencies on the package we copy from, but we
451 will ignore this bug as architecture-specific dependencies are only allowed
452 in jessie and until then the :none packages should be extinct (hopefully).
453 In other words: This should work long enough to allow graceful removal of
454 these packages, it is not supposed to allow users to keep using them … */
455 if (strcmp(Pkg
.Arch(), "none") == 0)
457 pkgCache::PkgIterator M
= Grp
.FindPreferredPkg();
458 if (M
.end() == false && Pkg
!= M
)
460 pkgCache::DepIterator D
= M
.RevDependsList();
461 Dynamic
<pkgCache::DepIterator
> DynD(D
);
462 for (; D
.end() == false; ++D
)
464 if ((D
->Type
!= pkgCache::Dep::Conflicts
&&
465 D
->Type
!= pkgCache::Dep::DpkgBreaks
&&
466 D
->Type
!= pkgCache::Dep::Replaces
) ||
467 D
.ParentPkg().Group() == Grp
)
470 map_pointer_t
*OldDepLast
= NULL
;
471 pkgCache::VerIterator ConVersion
= D
.ParentVer();
472 Dynamic
<pkgCache::VerIterator
> DynV(ConVersion
);
473 // duplicate the Conflicts/Breaks/Replaces for :none arch
474 NewDepends(Pkg
, ConVersion
, D
->Version
,
475 D
->CompareOp
, D
->Type
, OldDepLast
);
480 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
481 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
482 Pkg
.Name(), "AddImplicitDepends", 2);
484 // Read only a single record and return
491 /* Record the Description(s) based on their master md5sum */
492 MD5SumValue CurMd5
= List
.Description_md5();
493 if (CurMd5
.Value().empty() == true && List
.Description("").empty() == true)
496 /* Before we add a new description we first search in the group for
497 a version with a description of the same MD5 - if so we reuse this
498 description group instead of creating our own for this version */
499 for (pkgCache::PkgIterator P
= Grp
.PackageList();
500 P
.end() == false; P
= Grp
.NextPkg(P
))
502 for (pkgCache::VerIterator V
= P
.VersionList();
503 V
.end() == false; ++V
)
505 if (V
->DescriptionList
== 0 || MD5SumValue(V
.DescriptionList().md5()) != CurMd5
)
507 Ver
->DescriptionList
= V
->DescriptionList
;
511 // We haven't found reusable descriptions, so add the first description(s)
512 map_stringitem_t md5idx
= Ver
->DescriptionList
== 0 ? 0 : Ver
.DescriptionList()->md5sum
;
513 std::vector
<std::string
> availDesc
= List
.AvailableDescriptionLanguages();
514 for (std::vector
<std::string
>::const_iterator CurLang
= availDesc
.begin(); CurLang
!= availDesc
.end(); ++CurLang
)
515 if (AddNewDescription(List
, Ver
, *CurLang
, CurMd5
, md5idx
) == false)
520 bool pkgCacheGenerator::AddNewDescription(ListParser
&List
, pkgCache::VerIterator
&Ver
, std::string
const &lang
, MD5SumValue
const &CurMd5
, map_stringitem_t
&md5idx
) /*{{{*/
522 pkgCache::DescIterator Desc
;
523 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
525 map_pointer_t
const descindex
= NewDescription(Desc
, lang
, CurMd5
, md5idx
);
526 if (unlikely(descindex
== 0 && _error
->PendingError()))
527 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
528 Ver
.ParentPkg().Name(), "NewDescription", 1);
530 md5idx
= Desc
->md5sum
;
531 Desc
->ParentPkg
= Ver
.ParentPkg().Index();
533 // we add at the end, so that the start is constant as we need
534 // that to be able to efficiently share these lists
535 pkgCache::DescIterator VerDesc
= Ver
.DescriptionList(); // old value might be invalid after ReMap
536 for (;VerDesc
.end() == false && VerDesc
->NextDesc
!= 0; ++VerDesc
);
537 map_pointer_t
* const LastNextDesc
= (VerDesc
.end() == true) ? &Ver
->DescriptionList
: &VerDesc
->NextDesc
;
538 *LastNextDesc
= descindex
;
540 if (NewFileDesc(Desc
,List
) == false)
541 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
542 Ver
.ParentPkg().Name(), "NewFileDesc", 1);
548 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
549 // ---------------------------------------------------------------------
550 /* If we found any file depends while parsing the main list we need to
551 resolve them. Since it is undesired to load the entire list of files
552 into the cache as virtual packages we do a two stage effort. MergeList
553 identifies the file depends and this creates Provdies for them by
554 re-parsing all the indexs. */
555 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
559 unsigned int Counter
= 0;
560 while (List
.Step() == true)
562 string PackageName
= List
.Package();
563 if (PackageName
.empty() == true)
565 string Version
= List
.Version();
566 if (Version
.empty() == true)
569 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
570 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
571 if (Pkg
.end() == true)
572 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
573 PackageName
.c_str(), "FindPkg", 1);
575 if (Counter
% 100 == 0 && Progress
!= 0)
576 Progress
->Progress(List
.Offset());
578 unsigned short Hash
= List
.VersionHash();
579 pkgCache::VerIterator Ver
= Pkg
.VersionList();
580 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
581 for (; Ver
.end() == false; ++Ver
)
583 if (List
.SameVersion(Hash
, Ver
) == true && Version
== Ver
.VerStr())
585 if (List
.CollectFileProvides(Cache
,Ver
) == false)
586 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
587 PackageName
.c_str(), "CollectFileProvides", 1);
592 if (Ver
.end() == true)
593 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
599 // CacheGenerator::NewGroup - Add a new group /*{{{*/
600 // ---------------------------------------------------------------------
601 /* This creates a new group structure and adds it to the hash table */
602 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
604 Grp
= Cache
.FindGrp(Name
);
605 if (Grp
.end() == false)
609 map_pointer_t
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
610 if (unlikely(Group
== 0))
613 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
614 map_stringitem_t
const idxName
= StoreString(PKGNAME
, Name
);
615 if (unlikely(idxName
== 0))
619 // Insert it into the hash table
620 unsigned long const Hash
= Cache
.Hash(Name
);
621 map_pointer_t
*insertAt
= &Cache
.HeaderP
->GrpHashTableP()[Hash
];
622 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ *insertAt
)->Name
) > 0)
623 insertAt
= &(Cache
.GrpP
+ *insertAt
)->Next
;
624 Grp
->Next
= *insertAt
;
627 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
631 // CacheGenerator::NewPackage - Add a new package /*{{{*/
632 // ---------------------------------------------------------------------
633 /* This creates a new package structure and adds it to the hash table */
634 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
635 const string
&Arch
) {
636 pkgCache::GrpIterator Grp
;
637 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
638 if (unlikely(NewGroup(Grp
, Name
) == false))
641 Pkg
= Grp
.FindPkg(Arch
);
642 if (Pkg
.end() == false)
646 map_pointer_t
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
647 if (unlikely(Package
== 0))
649 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
651 // Insert the package into our package list
652 if (Grp
->FirstPackage
== 0) // the group is new
654 Grp
->FirstPackage
= Package
;
655 // Insert it into the hash table
656 map_id_t
const Hash
= Cache
.Hash(Name
);
657 map_pointer_t
*insertAt
= &Cache
.HeaderP
->PkgHashTableP()[Hash
];
658 while (*insertAt
!= 0 && strcasecmp(Name
.c_str(), Cache
.StrP
+ (Cache
.GrpP
+ (Cache
.PkgP
+ *insertAt
)->Group
)->Name
) > 0)
659 insertAt
= &(Cache
.PkgP
+ *insertAt
)->NextPackage
;
660 Pkg
->NextPackage
= *insertAt
;
663 else // Group the Packages together
665 // this package is the new last package
666 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
667 Pkg
->NextPackage
= LastPkg
->NextPackage
;
668 LastPkg
->NextPackage
= Package
;
670 Grp
->LastPackage
= Package
;
672 // Set the name, arch and the ID
673 APT_IGNORE_DEPRECATED(Pkg
->Name
= Grp
->Name
;)
674 Pkg
->Group
= Grp
.Index();
675 // all is mapped to the native architecture
676 map_stringitem_t
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: StoreString(MIXED
, Arch
);
677 if (unlikely(idxArch
== 0))
680 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
685 // CacheGenerator::AddImplicitDepends /*{{{*/
686 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
687 pkgCache::PkgIterator
&P
,
688 pkgCache::VerIterator
&V
)
690 // copy P.Arch() into a string here as a cache remap
691 // in NewDepends() later may alter the pointer location
692 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
693 map_pointer_t
*OldDepLast
= NULL
;
694 /* MultiArch handling introduces a lot of implicit Dependencies:
695 - MultiArch: same → Co-Installable if they have the same version
696 - All others conflict with all other group members */
697 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
698 pkgCache::PkgIterator D
= G
.PackageList();
699 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
700 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
701 for (; D
.end() != true; D
= G
.NextPkg(D
))
703 if (Arch
== D
.Arch() || D
->VersionList
== 0)
705 /* We allow only one installed arch at the time
706 per group, therefore each group member conflicts
707 with all other group members */
708 if (coInstall
== true)
710 // Replaces: ${self}:other ( << ${binary:Version})
711 NewDepends(D
, V
, VerStrIdx
,
712 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
714 // Breaks: ${self}:other (!= ${binary:Version})
715 NewDepends(D
, V
, VerStrIdx
,
716 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
719 // Conflicts: ${self}:other
721 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
727 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
728 pkgCache::PkgIterator
&D
)
730 /* MultiArch handling introduces a lot of implicit Dependencies:
731 - MultiArch: same → Co-Installable if they have the same version
732 - All others conflict with all other group members */
733 map_pointer_t
*OldDepLast
= NULL
;
734 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
735 if (coInstall
== true)
737 map_stringitem_t
const VerStrIdx
= V
->VerStr
;
738 // Replaces: ${self}:other ( << ${binary:Version})
739 NewDepends(D
, V
, VerStrIdx
,
740 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
742 // Breaks: ${self}:other (!= ${binary:Version})
743 NewDepends(D
, V
, VerStrIdx
,
744 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
747 // Conflicts: ${self}:other
749 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
756 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
757 // ---------------------------------------------------------------------
759 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
762 if (CurrentFile
== 0)
766 map_pointer_t
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
770 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
771 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
773 // Link it to the end of the list
774 map_pointer_t
*Last
= &Ver
->FileList
;
775 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
777 VF
->NextFile
= *Last
;
780 VF
->Offset
= List
.Offset();
781 VF
->Size
= List
.Size();
782 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
783 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
784 Cache
.HeaderP
->VerFileCount
++;
789 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
790 // ---------------------------------------------------------------------
791 /* This puts a version structure in the linked list */
792 map_pointer_t
pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
793 const string
&VerStr
,
794 map_pointer_t
const ParentPkg
,
795 unsigned short const Hash
,
796 map_pointer_t
const Next
)
799 map_pointer_t
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
804 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
805 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
807 Ver
->ParentPkg
= ParentPkg
;
809 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
811 // try to find the version string in the group for reuse
812 pkgCache::PkgIterator Pkg
= Ver
.ParentPkg();
813 pkgCache::GrpIterator Grp
= Pkg
.Group();
814 if (Pkg
.end() == false && Grp
.end() == false)
816 for (pkgCache::PkgIterator P
= Grp
.PackageList(); P
.end() == false; P
= Grp
.NextPkg(P
))
820 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() == false; ++V
)
822 int const cmp
= strcmp(V
.VerStr(), VerStr
.c_str());
825 Ver
->VerStr
= V
->VerStr
;
833 // haven't found the version string, so create
834 map_stringitem_t
const idxVerStr
= StoreString(VERSIONNUMBER
, VerStr
);
835 if (unlikely(idxVerStr
== 0))
837 Ver
->VerStr
= idxVerStr
;
841 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
842 // ---------------------------------------------------------------------
844 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
847 if (CurrentFile
== 0)
851 map_pointer_t
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
855 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
856 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
858 // Link it to the end of the list
859 map_pointer_t
*Last
= &Desc
->FileList
;
860 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
863 DF
->NextFile
= *Last
;
866 DF
->Offset
= List
.Offset();
867 DF
->Size
= List
.Size();
868 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
869 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
870 Cache
.HeaderP
->DescFileCount
++;
875 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
876 // ---------------------------------------------------------------------
877 /* This puts a description structure in the linked list */
878 map_pointer_t
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
880 const MD5SumValue
&md5sum
,
881 map_stringitem_t
const idxmd5str
)
884 map_pointer_t
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
885 if (Description
== 0)
889 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
890 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
891 map_stringitem_t
const idxlanguage_code
= StoreString(MIXED
, Lang
);
892 if (unlikely(idxlanguage_code
== 0))
894 Desc
->language_code
= idxlanguage_code
;
897 Desc
->md5sum
= idxmd5str
;
900 map_stringitem_t
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
901 if (unlikely(idxmd5sum
== 0))
903 Desc
->md5sum
= idxmd5sum
;
909 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
910 // ---------------------------------------------------------------------
911 /* This creates a dependency element in the tree. It is linked to the
912 version and to the package that it is pointing to. */
913 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
914 pkgCache::VerIterator
&Ver
,
915 string
const &Version
,
916 unsigned int const &Op
,
917 unsigned int const &Type
,
918 map_stringitem_t
* &OldDepLast
)
920 map_stringitem_t index
= 0;
921 if (Version
.empty() == false)
923 int const CmpOp
= Op
& 0x0F;
924 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
925 if (CmpOp
== pkgCache::Dep::Equals
&& strcmp(Version
.c_str(), Ver
.VerStr()) == 0)
930 void const * const oldMap
= Map
.Data();
931 index
= StoreString(VERSIONNUMBER
, Version
);
932 if (unlikely(index
== 0))
934 if (OldDepLast
!= 0 && oldMap
!= Map
.Data())
935 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
938 return NewDepends(Pkg
, Ver
, index
, Op
, Type
, OldDepLast
);
940 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
941 pkgCache::VerIterator
&Ver
,
942 map_pointer_t
const Version
,
943 unsigned int const &Op
,
944 unsigned int const &Type
,
945 map_pointer_t
* &OldDepLast
)
947 void const * const oldMap
= Map
.Data();
949 map_pointer_t
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
950 if (unlikely(Dependency
== 0))
953 bool isDuplicate
= false;
954 map_pointer_t DependencyData
= 0;
955 map_pointer_t PreviousData
= 0;
956 if (Pkg
->RevDepends
!= 0)
958 pkgCache::Dependency
const * const L
= Cache
.DepP
+ Pkg
->RevDepends
;
959 DependencyData
= L
->DependencyData
;
961 pkgCache::DependencyData
const * const D
= Cache
.DepDataP
+ DependencyData
;
962 if (Version
> D
->Version
)
964 if (D
->Version
== Version
&& D
->Type
== Type
&& D
->CompareOp
== Op
)
969 PreviousData
= DependencyData
;
970 DependencyData
= D
->NextData
;
971 } while (DependencyData
!= 0);
974 if (isDuplicate
== false)
976 DependencyData
= AllocateInMap(sizeof(pkgCache::DependencyData
));
977 if (unlikely(DependencyData
== 0))
981 pkgCache::Dependency
* Link
= Cache
.DepP
+ Dependency
;
982 Link
->ParentVer
= Ver
.Index();
983 Link
->DependencyData
= DependencyData
;
984 Link
->ID
= Cache
.HeaderP
->DependsCount
++;
986 pkgCache::DepIterator
Dep(Cache
, Link
);
987 if (isDuplicate
== false)
991 Dep
->Version
= Version
;
992 Dep
->Package
= Pkg
.Index();
993 ++Cache
.HeaderP
->DependsDataCount
;
994 if (PreviousData
!= 0)
996 pkgCache::DependencyData
* const D
= Cache
.DepDataP
+ PreviousData
;
997 Dep
->NextData
= D
->NextData
;
998 D
->NextData
= DependencyData
;
1000 else if (Pkg
->RevDepends
!= 0)
1002 pkgCache::Dependency
const * const D
= Cache
.DepP
+ Pkg
->RevDepends
;
1003 Dep
->NextData
= D
->DependencyData
;
1007 if (isDuplicate
== true || PreviousData
!= 0)
1009 pkgCache::Dependency
* const L
= Cache
.DepP
+ Pkg
->RevDepends
;
1010 Link
->NextRevDepends
= L
->NextRevDepends
;
1011 L
->NextRevDepends
= Dependency
;
1015 Link
->NextRevDepends
= Pkg
->RevDepends
;
1016 Pkg
->RevDepends
= Dependency
;
1020 // Do we know where to link the Dependency to?
1021 if (OldDepLast
== NULL
)
1023 OldDepLast
= &Ver
->DependsList
;
1024 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
1025 OldDepLast
= &D
->NextDepends
;
1026 } else if (oldMap
!= Map
.Data())
1027 OldDepLast
+= (map_pointer_t
const * const) Map
.Data() - (map_pointer_t
const * const) oldMap
;
1029 Dep
->NextDepends
= *OldDepLast
;
1030 *OldDepLast
= Dependency
;
1031 OldDepLast
= &Dep
->NextDepends
;
1035 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
1036 // ---------------------------------------------------------------------
1037 /* This creates a Group and the Package to link this dependency to if
1038 needed and handles also the caching of the old endpoint */
1039 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator
&Ver
,
1040 const string
&PackageName
,
1042 const string
&Version
,
1046 pkgCache::GrpIterator Grp
;
1047 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
1048 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
1051 // Locate the target package
1052 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(Arch
);
1053 // we don't create 'none' packages and their dependencies if we can avoid it …
1054 if (Pkg
.end() == true && Arch
== "none" && strcmp(Ver
.ParentPkg().Arch(), "none") != 0)
1056 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1057 if (Pkg
.end() == true) {
1058 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
1062 // Is it a file dependency?
1063 if (unlikely(PackageName
[0] == '/'))
1064 FoundFileDeps
= true;
1066 /* Caching the old end point speeds up generation substantially */
1067 if (OldDepVer
!= Ver
) {
1072 return Owner
->NewDepends(Pkg
, Ver
, Version
, Op
, Type
, OldDepLast
);
1075 // ListParser::NewProvides - Create a Provides element /*{{{*/
1076 // ---------------------------------------------------------------------
1078 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator
&Ver
,
1079 const string
&PkgName
,
1080 const string
&PkgArch
,
1081 const string
&Version
)
1083 pkgCache
&Cache
= Owner
->Cache
;
1085 // We do not add self referencing provides
1086 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
1087 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
1091 map_pointer_t
const Provides
= Owner
->AllocateInMap(sizeof(pkgCache::Provides
));
1092 if (unlikely(Provides
== 0))
1094 Cache
.HeaderP
->ProvidesCount
++;
1097 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
1098 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
1099 Prv
->Version
= Ver
.Index();
1100 Prv
->NextPkgProv
= Ver
->ProvidesList
;
1101 Ver
->ProvidesList
= Prv
.Index();
1102 if (Version
.empty() == false) {
1103 map_stringitem_t
const idxProvideVersion
= WriteString(Version
);
1104 Prv
->ProvideVersion
= idxProvideVersion
;
1105 if (unlikely(idxProvideVersion
== 0))
1109 // Locate the target package
1110 pkgCache::PkgIterator Pkg
;
1111 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
1112 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
1115 // Link it to the package
1116 Prv
->ParentPkg
= Pkg
.Index();
1117 Prv
->NextProvides
= Pkg
->ProvidesList
;
1118 Pkg
->ProvidesList
= Prv
.Index();
1123 bool pkgCacheGenerator::ListParser::SameVersion(unsigned short const Hash
,/*{{{*/
1124 pkgCache::VerIterator
const &Ver
)
1126 return Hash
== Ver
->Hash
;
1129 // CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1130 bool pkgCacheGenerator::SelectReleaseFile(const string
&File
,const string
&Site
,
1131 unsigned long Flags
)
1133 if (File
.empty() && Site
.empty())
1135 CurrentRlsFile
= NULL
;
1139 // Get some space for the structure
1140 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentRlsFile
));
1141 if (unlikely(idxFile
== 0))
1143 CurrentRlsFile
= Cache
.RlsFileP
+ idxFile
;
1146 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1147 map_stringitem_t
const idxSite
= StoreString(MIXED
, Site
);
1148 if (unlikely(idxFileName
== 0 || idxSite
== 0))
1150 CurrentRlsFile
->FileName
= idxFileName
;
1151 CurrentRlsFile
->Site
= idxSite
;
1152 CurrentRlsFile
->NextFile
= Cache
.HeaderP
->RlsFileList
;
1153 CurrentRlsFile
->Flags
= Flags
;
1154 CurrentRlsFile
->ID
= Cache
.HeaderP
->ReleaseFileCount
;
1156 Cache
.HeaderP
->RlsFileList
= CurrentRlsFile
- Cache
.RlsFileP
;
1157 Cache
.HeaderP
->ReleaseFileCount
++;
1162 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1163 // ---------------------------------------------------------------------
1164 /* This is used to select which file is to be associated with all newly
1165 added versions. The caller is responsible for setting the IMS fields. */
1166 bool pkgCacheGenerator::SelectFile(std::string
const &File
,
1167 pkgIndexFile
const &Index
,
1168 std::string
const &Architecture
,
1169 std::string
const &Component
,
1170 unsigned long const Flags
)
1172 // Get some space for the structure
1173 map_pointer_t
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
1174 if (unlikely(idxFile
== 0))
1176 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
1179 map_stringitem_t
const idxFileName
= WriteStringInMap(File
);
1180 if (unlikely(idxFileName
== 0))
1182 CurrentFile
->FileName
= idxFileName
;
1183 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
1184 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
1185 map_stringitem_t
const idxIndexType
= StoreString(MIXED
, Index
.GetType()->Label
);
1186 if (unlikely(idxIndexType
== 0))
1188 CurrentFile
->IndexType
= idxIndexType
;
1189 if (Architecture
.empty())
1190 CurrentFile
->Architecture
= 0;
1193 map_stringitem_t
const arch
= StoreString(pkgCacheGenerator::MIXED
, Architecture
);
1194 if (unlikely(arch
== 0))
1196 CurrentFile
->Architecture
= arch
;
1198 map_stringitem_t
const component
= StoreString(pkgCacheGenerator::MIXED
, Component
);
1199 if (unlikely(component
== 0))
1201 CurrentFile
->Component
= component
;
1202 CurrentFile
->Flags
= Flags
;
1203 if (CurrentRlsFile
!= NULL
)
1204 CurrentFile
->Release
= CurrentRlsFile
- Cache
.RlsFileP
;
1206 CurrentFile
->Release
= 0;
1208 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
1209 Cache
.HeaderP
->PackageFileCount
++;
1212 Progress
->SubProgress(Index
.Size());
1216 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1217 // ---------------------------------------------------------------------
1218 /* This is used to create handles to strings. Given the same text it
1219 always returns the same number */
1220 map_stringitem_t
pkgCacheGenerator::StoreString(enum StringType
const type
, const char *S
,
1223 std::string
const key(S
, Size
);
1225 std::map
<std::string
,map_stringitem_t
> * strings
;
1227 case MIXED
: strings
= &strMixed
; break;
1228 case PKGNAME
: strings
= &strPkgNames
; break;
1229 case VERSIONNUMBER
: strings
= &strVersions
; break;
1230 case SECTION
: strings
= &strSections
; break;
1231 default: _error
->Fatal("Unknown enum type used for string storage of '%s'", key
.c_str()); return 0;
1234 std::map
<std::string
,map_stringitem_t
>::const_iterator
const item
= strings
->find(key
);
1235 if (item
!= strings
->end())
1236 return item
->second
;
1238 map_stringitem_t
const idxString
= WriteStringInMap(S
,Size
);
1239 strings
->insert(std::make_pair(key
, idxString
));
1243 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1244 // ---------------------------------------------------------------------
1245 /* This just verifies that each file in the list of index files exists,
1246 has matching attributes with the cache and the cache does not have
1248 static bool CheckValidity(const string
&CacheFile
,
1249 pkgSourceList
&List
,
1254 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1255 // No file, certainly invalid
1256 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1259 std::clog
<< "CacheFile doesn't exist" << std::endl
;
1263 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1266 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1271 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1272 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
1273 pkgCache
Cache(Map
);
1274 if (_error
->PendingError() == true || Map
->Size() == 0)
1277 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
1282 SPtrArray
<bool> RlsVisited
= new bool[Cache
.HeaderP
->ReleaseFileCount
];
1283 memset(RlsVisited
,0,sizeof(*RlsVisited
)*Cache
.HeaderP
->ReleaseFileCount
);
1284 std::vector
<pkgIndexFile
*> Files
;
1285 for (pkgSourceList::const_iterator i
= List
.begin(); i
!= List
.end(); ++i
)
1288 std::clog
<< "Checking RlsFile " << (*i
)->Describe() << ": ";
1289 pkgCache::RlsFileIterator
const RlsFile
= (*i
)->FindInCache(Cache
, true);
1290 if (RlsFile
.end() == true)
1293 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1297 RlsVisited
[RlsFile
->ID
] = true;
1299 std::clog
<< "with ID " << RlsFile
->ID
<< " is valid" << std::endl
;
1301 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1302 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1303 if ((*j
)->HasPackages())
1304 Files
.push_back (*j
);
1306 for (unsigned I
= 0; I
!= Cache
.HeaderP
->ReleaseFileCount
; ++I
)
1307 if (RlsVisited
[I
] == false)
1310 std::clog
<< "RlsFile with ID" << I
<< " wasn't visited" << std::endl
;
1314 for (; Start
!= End
; ++Start
)
1315 Files
.push_back(*Start
);
1317 /* Now we check every index file, see if it is in the cache,
1318 verify the IMS data and check that it is on the disk too.. */
1319 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
1320 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
1321 for (std::vector
<pkgIndexFile
*>::const_reverse_iterator PkgFile
= Files
.rbegin(); PkgFile
!= Files
.rend(); ++PkgFile
)
1324 std::clog
<< "Checking PkgFile " << (*PkgFile
)->Describe() << ": ";
1325 if ((*PkgFile
)->Exists() == false)
1328 std::clog
<< "file doesn't exist" << std::endl
;
1332 // FindInCache is also expected to do an IMS check.
1333 pkgCache::PkgFileIterator File
= (*PkgFile
)->FindInCache(Cache
);
1334 if (File
.end() == true)
1337 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1341 Visited
[File
->ID
] = true;
1343 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1346 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1347 if (Visited
[I
] == false)
1350 std::clog
<< "PkgFile with ID" << I
<< " wasn't visited" << std::endl
;
1354 if (_error
->PendingError() == true)
1358 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1359 _error
->DumpErrors();
1366 *OutMap
= Map
.UnGuard();
1370 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1371 // ---------------------------------------------------------------------
1372 /* Size is kind of an abstract notion that is only used for the progress
1374 static map_filesize_t
ComputeSize(pkgSourceList
const * const List
, FileIterator Start
,FileIterator End
)
1376 map_filesize_t TotalSize
= 0;
1379 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1381 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1382 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin(); j
!= Indexes
->end(); ++j
)
1383 if ((*j
)->HasPackages() == true)
1384 TotalSize
+= (*j
)->Size();
1388 for (; Start
< End
; ++Start
)
1390 if ((*Start
)->HasPackages() == false)
1392 TotalSize
+= (*Start
)->Size();
1397 // BuildCache - Merge the list of index files into the cache /*{{{*/
1398 // ---------------------------------------------------------------------
1400 static bool BuildCache(pkgCacheGenerator
&Gen
,
1401 OpProgress
*Progress
,
1402 map_filesize_t
&CurrentSize
,map_filesize_t TotalSize
,
1403 pkgSourceList
const * const List
,
1404 FileIterator Start
, FileIterator End
)
1406 std::vector
<pkgIndexFile
*> Files
;
1407 bool const HasFileDeps
= Gen
.HasFileDeps();
1411 for (pkgSourceList::const_iterator i
= List
->begin(); i
!= List
->end(); ++i
)
1413 if ((*i
)->FindInCache(Gen
.GetCache(), false).end() == false)
1415 _error
->Warning("Duplicate sources.list entry %s",
1416 (*i
)->Describe().c_str());
1420 if ((*i
)->Merge(Gen
, Progress
) == false)
1423 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1424 for (std::vector
<pkgIndexFile
*>::const_iterator I
= Indexes
->begin(); I
!= Indexes
->end(); ++I
)
1427 Files
.push_back(*I
);
1429 if ((*I
)->HasPackages() == false)
1432 if ((*I
)->Exists() == false)
1435 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
1437 _error
->Warning("Duplicate sources.list entry %s",
1438 (*I
)->Describe().c_str());
1442 map_filesize_t Size
= (*I
)->Size();
1443 if (Progress
!= NULL
)
1444 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
1445 CurrentSize
+= Size
;
1447 if ((*I
)->Merge(Gen
,Progress
) == false)
1453 Gen
.SelectReleaseFile("", "");
1455 for (I
= Start
; I
!= End
; ++I
)
1458 Files
.push_back(*I
);
1460 if ((*I
)->HasPackages() == false)
1463 if ((*I
)->Exists() == false)
1466 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
1468 _error
->Warning("Duplicate sources.list entry %s",
1469 (*I
)->Describe().c_str());
1473 map_filesize_t Size
= (*I
)->Size();
1474 if (Progress
!= NULL
)
1475 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
1476 CurrentSize
+= Size
;
1478 if ((*I
)->Merge(Gen
,Progress
) == false)
1482 if (HasFileDeps
== true)
1484 if (Progress
!= NULL
)
1486 TotalSize
= ComputeSize(List
, Start
, End
);
1488 for (std::vector
<pkgIndexFile
*>::const_iterator I
= Files
.begin(); I
!= Files
.end(); ++I
)
1490 map_filesize_t Size
= (*I
)->Size();
1491 if (Progress
!= NULL
)
1492 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
1493 CurrentSize
+= Size
;
1494 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
1502 // CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
1503 DynamicMMap
* pkgCacheGenerator::CreateDynamicMMap(FileFd
*CacheF
, unsigned long Flags
) {
1504 map_filesize_t
const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1505 map_filesize_t
const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1506 map_filesize_t
const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1507 Flags
|= MMap::Moveable
;
1508 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1509 Flags
|= MMap::Fallback
;
1511 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1513 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1516 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1517 // ---------------------------------------------------------------------
1518 /* This makes sure that the status cache (the cache that has all
1519 index files from the sources list and all local ones) is ready
1520 to be mmaped. If OutMap is not zero then a MMap object representing
1521 the cache will be stored there. This is pretty much mandetory if you
1522 are using AllowMem. AllowMem lets the function be run as non-root
1523 where it builds the cache 'fast' into a memory buffer. */
1524 APT_DEPRECATED
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1525 MMap
**OutMap
, bool AllowMem
)
1526 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1527 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1528 MMap
**OutMap
,bool AllowMem
)
1530 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1532 std::vector
<pkgIndexFile
*> Files
;
1534 for (std::vector<metaIndex *>::const_iterator i = List.begin();
1538 std::vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1539 for (std::vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
1540 j != Indexes->end();
1542 Files.push_back (*j);
1545 if (_system
->AddStatusFiles(Files
) == false)
1548 // Decide if we can write to the files..
1549 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1550 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1552 // ensure the cache directory exists
1553 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1555 string dir
= _config
->FindDir("Dir::Cache");
1556 size_t const len
= dir
.size();
1557 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1558 dir
= dir
.substr(0, len
- 5);
1559 if (CacheFile
.empty() == false)
1560 CreateDirectory(dir
, flNotFile(CacheFile
));
1561 if (SrcCacheFile
.empty() == false)
1562 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1565 // Decide if we can write to the cache
1566 bool Writeable
= false;
1567 if (CacheFile
.empty() == false)
1568 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1570 if (SrcCacheFile
.empty() == false)
1571 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1573 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1575 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
1576 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1578 if (Progress
!= NULL
)
1579 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1581 // Cache is OK, Fin.
1582 if (CheckValidity(CacheFile
, List
, Files
.begin(),Files
.end(),OutMap
) == true)
1584 if (Progress
!= NULL
)
1585 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1587 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
1590 else if (Debug
== true)
1591 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
1593 /* At this point we know we need to reconstruct the package cache,
1595 SPtr
<FileFd
> CacheF
;
1596 SPtr
<DynamicMMap
> Map
;
1597 if (Writeable
== true && CacheFile
.empty() == false)
1599 _error
->PushToStack();
1600 unlink(CacheFile
.c_str());
1601 CacheF
= new FileFd(CacheFile
,FileFd::WriteAtomic
);
1602 fchmod(CacheF
->Fd(),0644);
1603 Map
= CreateDynamicMMap(CacheF
, MMap::Public
);
1604 if (_error
->PendingError() == true)
1606 delete CacheF
.UnGuard();
1607 delete Map
.UnGuard();
1609 std::clog
<< "Open filebased MMap FAILED" << std::endl
;
1611 if (AllowMem
== false)
1613 _error
->MergeWithStack();
1616 _error
->RevertToStack();
1620 _error
->MergeWithStack();
1622 std::clog
<< "Open filebased MMap" << std::endl
;
1625 if (Writeable
== false || CacheFile
.empty() == true)
1627 // Just build it in memory..
1628 Map
= CreateDynamicMMap(NULL
);
1630 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1633 // Lets try the source cache.
1634 map_filesize_t CurrentSize
= 0;
1635 map_filesize_t TotalSize
= 0;
1636 if (CheckValidity(SrcCacheFile
, List
, Files
.end(),
1637 Files
.end()) == true)
1640 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
1641 // Preload the map with the source cache
1642 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
1643 map_pointer_t
const alloc
= Map
->RawAllocate(SCacheF
.Size());
1644 if ((alloc
== 0 && _error
->PendingError())
1645 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1646 SCacheF
.Size()) == false)
1649 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1651 // Build the status cache
1652 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1653 if (_error
->PendingError() == true)
1655 if (BuildCache(Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1656 Files
.begin(),Files
.end()) == false)
1662 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1663 TotalSize
= ComputeSize(&List
, Files
.begin(),Files
.end());
1665 // Build the source cache
1666 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1667 if (_error
->PendingError() == true)
1669 if (BuildCache(Gen
, Progress
, CurrentSize
, TotalSize
, &List
,
1670 Files
.end(),Files
.end()) == false)
1674 if (Writeable
== true && SrcCacheFile
.empty() == false)
1676 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteAtomic
);
1677 if (_error
->PendingError() == true)
1680 fchmod(SCacheF
.Fd(),0644);
1682 // Write out the main data
1683 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1684 return _error
->Error(_("IO Error saving source cache"));
1687 // Write out the proper header
1688 Gen
.GetCache().HeaderP
->Dirty
= false;
1689 if (SCacheF
.Seek(0) == false ||
1690 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1691 return _error
->Error(_("IO Error saving source cache"));
1692 Gen
.GetCache().HeaderP
->Dirty
= true;
1696 // Build the status cache
1697 if (BuildCache(Gen
, Progress
, CurrentSize
, TotalSize
, NULL
,
1698 Files
.begin(), Files
.end()) == false)
1702 std::clog
<< "Caches are ready for shipping" << std::endl
;
1704 if (_error
->PendingError() == true)
1710 delete Map
.UnGuard();
1711 *OutMap
= new MMap(*CacheF
,0);
1715 *OutMap
= Map
.UnGuard();
1722 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1723 // ---------------------------------------------------------------------
1725 APT_DEPRECATED
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1726 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1727 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1729 std::vector
<pkgIndexFile
*> Files
;
1730 if (_system
->AddStatusFiles(Files
) == false)
1733 SPtr
<DynamicMMap
> Map
= CreateDynamicMMap(NULL
);
1734 map_filesize_t CurrentSize
= 0;
1735 map_filesize_t TotalSize
= 0;
1737 TotalSize
= ComputeSize(NULL
, Files
.begin(), Files
.end());
1739 // Build the status cache
1740 if (Progress
!= NULL
)
1741 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1742 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1743 if (_error
->PendingError() == true)
1745 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, NULL
,
1746 Files
.begin(), Files
.end()) == false)
1749 if (_error
->PendingError() == true)
1751 *OutMap
= Map
.UnGuard();
1756 // IsDuplicateDescription /*{{{*/
1757 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1758 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1760 // Descriptions in the same link-list have all the same md5
1761 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1763 for (; Desc
.end() == false; ++Desc
)
1764 if (Desc
.LanguageCode() == CurLang
)
1769 // CacheGenerator::FinishCache /*{{{*/
1770 bool pkgCacheGenerator::FinishCache(OpProgress
* /*Progress*/)
1776 pkgCacheGenerator::ListParser::ListParser() : Owner(NULL
), OldDepLast(NULL
), FoundFileDeps(false), d(NULL
) {}
1777 pkgCacheGenerator::ListParser::~ListParser() {}