]>
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/aptconfiguration.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/sptr.h>
24 #include <apt-pkg/pkgsystem.h>
25 #include <apt-pkg/macros.h>
26 #include <apt-pkg/tagfile.h>
27 #include <apt-pkg/metaindex.h>
28 #include <apt-pkg/fileutl.h>
38 typedef std::vector
<pkgIndexFile
*>::iterator FileIterator
;
39 template <typename Iter
> std::vector
<Iter
*> pkgCacheGenerator::Dynamic
<Iter
>::toReMap
;
41 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
42 MD5SumValue
const &CurMd5
, std::string
const &CurLang
);
46 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
47 // ---------------------------------------------------------------------
48 /* We set the dirty flag and make sure that is written to the disk */
49 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
50 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
54 memset(UniqHash
,0,sizeof(UniqHash
));
56 if (_error
->PendingError() == true)
61 // Setup the map interface..
62 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
63 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
66 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
69 *Cache
.HeaderP
= pkgCache::Header();
70 map_ptrloc
const idxVerSysName
= WriteStringInMap(_system
->VS
->Label
);
71 Cache
.HeaderP
->VerSysName
= idxVerSysName
;
72 map_ptrloc
const idxArchitecture
= WriteStringInMap(_config
->Find("APT::Architecture"));
73 Cache
.HeaderP
->Architecture
= idxArchitecture
;
74 if (unlikely(idxVerSysName
== 0 || idxArchitecture
== 0))
80 // Map directly from the existing file
82 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
83 if (Cache
.VS
!= _system
->VS
)
85 _error
->Error(_("Cache has an incompatible versioning system"));
90 Cache
.HeaderP
->Dirty
= true;
91 Map
.Sync(0,sizeof(pkgCache::Header
));
94 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
95 // ---------------------------------------------------------------------
96 /* We sync the data then unset the dirty flag in two steps so as to
97 advoid a problem during a crash */
98 pkgCacheGenerator::~pkgCacheGenerator()
100 if (_error
->PendingError() == true)
102 if (Map
.Sync() == false)
105 Cache
.HeaderP
->Dirty
= false;
106 Cache
.HeaderP
->CacheFileSize
= Map
.Size();
107 Map
.Sync(0,sizeof(pkgCache::Header
));
110 void pkgCacheGenerator::ReMap(void const * const oldMap
, void const * const newMap
) {/*{{{*/
111 if (oldMap
== newMap
)
114 if (_config
->FindB("Debug::pkgCacheGen", false))
115 std::clog
<< "Remaping from " << oldMap
<< " to " << newMap
<< std::endl
;
119 CurrentFile
+= (pkgCache::PackageFile
*) newMap
- (pkgCache::PackageFile
*) oldMap
;
121 for (size_t i
= 0; i
< _count(UniqHash
); ++i
)
122 if (UniqHash
[i
] != 0)
123 UniqHash
[i
] += (pkgCache::StringItem
*) newMap
- (pkgCache::StringItem
*) oldMap
;
125 for (std::vector
<pkgCache::GrpIterator
*>::const_iterator i
= Dynamic
<pkgCache::GrpIterator
>::toReMap
.begin();
126 i
!= Dynamic
<pkgCache::GrpIterator
>::toReMap
.end(); ++i
)
127 (*i
)->ReMap(oldMap
, newMap
);
128 for (std::vector
<pkgCache::PkgIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgIterator
>::toReMap
.begin();
129 i
!= Dynamic
<pkgCache::PkgIterator
>::toReMap
.end(); ++i
)
130 (*i
)->ReMap(oldMap
, newMap
);
131 for (std::vector
<pkgCache::VerIterator
*>::const_iterator i
= Dynamic
<pkgCache::VerIterator
>::toReMap
.begin();
132 i
!= Dynamic
<pkgCache::VerIterator
>::toReMap
.end(); ++i
)
133 (*i
)->ReMap(oldMap
, newMap
);
134 for (std::vector
<pkgCache::DepIterator
*>::const_iterator i
= Dynamic
<pkgCache::DepIterator
>::toReMap
.begin();
135 i
!= Dynamic
<pkgCache::DepIterator
>::toReMap
.end(); ++i
)
136 (*i
)->ReMap(oldMap
, newMap
);
137 for (std::vector
<pkgCache::DescIterator
*>::const_iterator i
= Dynamic
<pkgCache::DescIterator
>::toReMap
.begin();
138 i
!= Dynamic
<pkgCache::DescIterator
>::toReMap
.end(); ++i
)
139 (*i
)->ReMap(oldMap
, newMap
);
140 for (std::vector
<pkgCache::PrvIterator
*>::const_iterator i
= Dynamic
<pkgCache::PrvIterator
>::toReMap
.begin();
141 i
!= Dynamic
<pkgCache::PrvIterator
>::toReMap
.end(); ++i
)
142 (*i
)->ReMap(oldMap
, newMap
);
143 for (std::vector
<pkgCache::PkgFileIterator
*>::const_iterator i
= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.begin();
144 i
!= Dynamic
<pkgCache::PkgFileIterator
>::toReMap
.end(); ++i
)
145 (*i
)->ReMap(oldMap
, newMap
);
147 // CacheGenerator::WriteStringInMap /*{{{*/
148 map_ptrloc
pkgCacheGenerator::WriteStringInMap(const char *String
,
149 const unsigned long &Len
) {
150 void const * const oldMap
= Map
.Data();
151 map_ptrloc
const index
= Map
.WriteString(String
, Len
);
153 ReMap(oldMap
, Map
.Data());
157 // CacheGenerator::WriteStringInMap /*{{{*/
158 map_ptrloc
pkgCacheGenerator::WriteStringInMap(const char *String
) {
159 void const * const oldMap
= Map
.Data();
160 map_ptrloc
const index
= Map
.WriteString(String
);
162 ReMap(oldMap
, Map
.Data());
166 map_ptrloc
pkgCacheGenerator::AllocateInMap(const unsigned long &size
) {/*{{{*/
167 void const * const oldMap
= Map
.Data();
168 map_ptrloc
const index
= Map
.Allocate(size
);
170 ReMap(oldMap
, Map
.Data());
174 // CacheGenerator::MergeList - Merge the package list /*{{{*/
175 // ---------------------------------------------------------------------
176 /* This provides the generation of the entries in the cache. Each loop
177 goes through a single package record from the underlying parse engine. */
178 bool pkgCacheGenerator::MergeList(ListParser
&List
,
179 pkgCache::VerIterator
*OutVer
)
183 unsigned int Counter
= 0;
184 while (List
.Step() == true)
186 string
const PackageName
= List
.Package();
187 if (PackageName
.empty() == true)
191 if (Counter
% 100 == 0 && Progress
!= 0)
192 Progress
->Progress(List
.Offset());
194 string Arch
= List
.Architecture();
195 string
const Version
= List
.Version();
196 if (Version
.empty() == true && Arch
.empty() == true)
198 if (MergeListGroup(List
, PackageName
) == false)
202 if (Arch
.empty() == true)
203 Arch
= _config
->Find("APT::Architecture");
205 // Get a pointer to the package structure
206 pkgCache::PkgIterator Pkg
;
207 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
208 if (NewPackage(Pkg
, PackageName
, Arch
) == false)
209 // TRANSLATOR: The first placeholder is a package name,
210 // the other two should be copied verbatim as they include debug info
211 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
212 PackageName
.c_str(), "NewPackage", 1);
215 if (Version
.empty() == true)
217 if (MergeListPackage(List
, Pkg
) == false)
222 if (MergeListVersion(List
, Pkg
, Version
, OutVer
) == false)
228 FoundFileDeps
|= List
.HasFileDeps();
233 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
234 return _error
->Error(_("Wow, you exceeded the number of package "
235 "names this APT is capable of."));
236 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
237 return _error
->Error(_("Wow, you exceeded the number of versions "
238 "this APT is capable of."));
239 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
240 return _error
->Error(_("Wow, you exceeded the number of descriptions "
241 "this APT is capable of."));
242 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
243 return _error
->Error(_("Wow, you exceeded the number of dependencies "
244 "this APT is capable of."));
246 FoundFileDeps
|= List
.HasFileDeps();
249 // CacheGenerator::MergeListGroup /*{{{*/
250 bool pkgCacheGenerator::MergeListGroup(ListParser
&List
, std::string
const &GrpName
)
252 pkgCache::GrpIterator Grp
= Cache
.FindGrp(GrpName
);
253 // a group has no data on it's own, only packages have it but these
254 // stanzas like this come from Translation- files to add descriptions,
255 // but without a version we don't need a description for it…
256 if (Grp
.end() == true)
258 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
260 pkgCache::PkgIterator Pkg
;
261 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
262 for (Pkg
= Grp
.PackageList(); Pkg
.end() == false; Pkg
= Grp
.NextPkg(Pkg
))
263 if (MergeListPackage(List
, Pkg
) == false)
269 // CacheGenerator::MergeListPackage /*{{{*/
270 bool pkgCacheGenerator::MergeListPackage(ListParser
&List
, pkgCache::PkgIterator
&Pkg
)
272 // we first process the package, then the descriptions
273 // (for deb this package processing is in fact a no-op)
274 pkgCache::VerIterator
Ver(Cache
);
275 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
276 if (List
.UsePackage(Pkg
, Ver
) == false)
277 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
278 Pkg
.Name(), "UsePackage", 1);
280 // Find the right version to write the description
281 MD5SumValue CurMd5
= List
.Description_md5();
282 std::string CurLang
= List
.DescriptionLanguage();
284 for (Ver
= Pkg
.VersionList(); Ver
.end() == false; ++Ver
)
286 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
288 // a version can only have one md5 describing it
289 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
292 // don't add a new description if we have one for the given
294 if (IsDuplicateDescription(Desc
, CurMd5
, CurLang
) == true)
297 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
298 // we add at the end, so that the start is constant as we need
299 // that to be able to efficiently share these lists
300 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
301 for (;Desc
.end() == false && Desc
->NextDesc
!= 0; ++Desc
);
302 if (Desc
.end() == false)
303 LastDesc
= &Desc
->NextDesc
;
305 void const * const oldMap
= Map
.Data();
306 map_ptrloc
const descindex
= NewDescription(Desc
, CurLang
, CurMd5
, *LastDesc
);
307 if (unlikely(descindex
== 0 && _error
->PendingError()))
308 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
309 Pkg
.Name(), "NewDescription", 1);
310 if (oldMap
!= Map
.Data())
311 LastDesc
+= (map_ptrloc
*) Map
.Data() - (map_ptrloc
*) oldMap
;
312 *LastDesc
= descindex
;
313 Desc
->ParentPkg
= Pkg
.Index();
315 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
316 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
317 Pkg
.Name(), "NewFileDesc", 1);
319 // we can stop here as all "same" versions will share the description
326 // CacheGenerator::MergeListVersion /*{{{*/
327 bool pkgCacheGenerator::MergeListVersion(ListParser
&List
, pkgCache::PkgIterator
&Pkg
,
328 std::string
const &Version
, pkgCache::VerIterator
* &OutVer
)
330 pkgCache::VerIterator Ver
= Pkg
.VersionList();
331 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
332 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
333 void const * oldMap
= Map
.Data();
335 unsigned long const Hash
= List
.VersionHash();
336 if (Ver
.end() == false)
338 /* We know the list is sorted so we use that fact in the search.
339 Insertion of new versions is done with correct sorting */
341 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
343 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
344 // Version is higher as current version - insert here
347 // Versionstrings are equal - is hash also equal?
348 if (Res
== 0 && Ver
->Hash
== Hash
)
350 // proceed with the next till we have either the right
351 // or we found another version (which will be lower)
354 /* We already have a version for this item, record that we saw it */
355 if (Res
== 0 && Ver
.end() == false && Ver
->Hash
== Hash
)
357 if (List
.UsePackage(Pkg
,Ver
) == false)
358 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
359 Pkg
.Name(), "UsePackage", 2);
361 if (NewFileVer(Ver
,List
) == false)
362 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
363 Pkg
.Name(), "NewFileVer", 1);
365 // Read only a single record and return
377 map_ptrloc
const verindex
= NewVersion(Ver
,Version
,*LastVer
);
378 if (verindex
== 0 && _error
->PendingError())
379 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
380 Pkg
.Name(), "NewVersion", 1);
382 if (oldMap
!= Map
.Data())
383 LastVer
+= (map_ptrloc
*) Map
.Data() - (map_ptrloc
*) oldMap
;
385 Ver
->ParentPkg
= Pkg
.Index();
388 if (unlikely(List
.NewVersion(Ver
) == false))
389 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
390 Pkg
.Name(), "NewVersion", 2);
392 if (unlikely(List
.UsePackage(Pkg
,Ver
) == false))
393 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
394 Pkg
.Name(), "UsePackage", 3);
396 if (unlikely(NewFileVer(Ver
,List
) == false))
397 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
398 Pkg
.Name(), "NewFileVer", 2);
400 pkgCache::GrpIterator Grp
= Pkg
.Group();
401 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
403 /* If it is the first version of this package we need to add implicit
404 Multi-Arch dependencies to all other package versions in the group now -
405 otherwise we just add them for this new version */
406 if (Pkg
.VersionList()->NextVer
== 0)
408 pkgCache::PkgIterator P
= Grp
.PackageList();
409 Dynamic
<pkgCache::PkgIterator
> DynP(P
);
410 for (; P
.end() != true; P
= Grp
.NextPkg(P
))
412 if (P
->ID
== Pkg
->ID
)
414 pkgCache::VerIterator V
= P
.VersionList();
415 Dynamic
<pkgCache::VerIterator
> DynV(V
);
416 for (; V
.end() != true; ++V
)
417 if (unlikely(AddImplicitDepends(V
, Pkg
) == false))
418 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
419 Pkg
.Name(), "AddImplicitDepends", 1);
422 if (unlikely(AddImplicitDepends(Grp
, Pkg
, Ver
) == false))
423 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
424 Pkg
.Name(), "AddImplicitDepends", 2);
426 // Read only a single record and return
433 /* Record the Description (it is not translated) */
434 MD5SumValue CurMd5
= List
.Description_md5();
435 if (CurMd5
.Value().empty() == true)
437 std::string CurLang
= List
.DescriptionLanguage();
439 /* Before we add a new description we first search in the group for
440 a version with a description of the same MD5 - if so we reuse this
441 description group instead of creating our own for this version */
442 for (pkgCache::PkgIterator P
= Grp
.PackageList();
443 P
.end() == false; P
= Grp
.NextPkg(P
))
445 for (pkgCache::VerIterator V
= P
.VersionList();
446 V
.end() == false; ++V
)
448 if (IsDuplicateDescription(V
.DescriptionList(), CurMd5
, "") == false)
450 Ver
->DescriptionList
= V
->DescriptionList
;
455 // We haven't found reusable descriptions, so add the first description
456 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
457 Dynamic
<pkgCache::DescIterator
> DynDesc(Desc
);
458 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
461 map_ptrloc
const descindex
= NewDescription(Desc
, CurLang
, CurMd5
, *LastDesc
);
462 if (unlikely(descindex
== 0 && _error
->PendingError()))
463 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
464 Pkg
.Name(), "NewDescription", 2);
465 if (oldMap
!= Map
.Data())
466 LastDesc
+= (map_ptrloc
*) Map
.Data() - (map_ptrloc
*) oldMap
;
467 *LastDesc
= descindex
;
468 Desc
->ParentPkg
= Pkg
.Index();
470 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
471 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
472 Pkg
.Name(), "NewFileDesc", 2);
478 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
479 // ---------------------------------------------------------------------
480 /* If we found any file depends while parsing the main list we need to
481 resolve them. Since it is undesired to load the entire list of files
482 into the cache as virtual packages we do a two stage effort. MergeList
483 identifies the file depends and this creates Provdies for them by
484 re-parsing all the indexs. */
485 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
489 unsigned int Counter
= 0;
490 while (List
.Step() == true)
492 string PackageName
= List
.Package();
493 if (PackageName
.empty() == true)
495 string Version
= List
.Version();
496 if (Version
.empty() == true)
499 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
500 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
501 if (Pkg
.end() == true)
502 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
503 PackageName
.c_str(), "FindPkg", 1);
505 if (Counter
% 100 == 0 && Progress
!= 0)
506 Progress
->Progress(List
.Offset());
508 unsigned long Hash
= List
.VersionHash();
509 pkgCache::VerIterator Ver
= Pkg
.VersionList();
510 Dynamic
<pkgCache::VerIterator
> DynVer(Ver
);
511 for (; Ver
.end() == false; ++Ver
)
513 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
515 if (List
.CollectFileProvides(Cache
,Ver
) == false)
516 return _error
->Error(_("Error occurred while processing %s (%s%d)"),
517 PackageName
.c_str(), "CollectFileProvides", 1);
522 if (Ver
.end() == true)
523 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
529 // CacheGenerator::NewGroup - Add a new group /*{{{*/
530 // ---------------------------------------------------------------------
531 /* This creates a new group structure and adds it to the hash table */
532 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
)
534 Grp
= Cache
.FindGrp(Name
);
535 if (Grp
.end() == false)
539 map_ptrloc
const Group
= AllocateInMap(sizeof(pkgCache::Group
));
540 if (unlikely(Group
== 0))
543 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
544 map_ptrloc
const idxName
= WriteStringInMap(Name
);
545 if (unlikely(idxName
== 0))
549 // Insert it into the hash table
550 unsigned long const Hash
= Cache
.Hash(Name
);
551 Grp
->Next
= Cache
.HeaderP
->GrpHashTable
[Hash
];
552 Cache
.HeaderP
->GrpHashTable
[Hash
] = Group
;
554 Grp
->ID
= Cache
.HeaderP
->GroupCount
++;
558 // CacheGenerator::NewPackage - Add a new package /*{{{*/
559 // ---------------------------------------------------------------------
560 /* This creates a new package structure and adds it to the hash table */
561 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
562 const string
&Arch
) {
563 pkgCache::GrpIterator Grp
;
564 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
565 if (unlikely(NewGroup(Grp
, Name
) == false))
568 Pkg
= Grp
.FindPkg(Arch
);
569 if (Pkg
.end() == false)
573 map_ptrloc
const Package
= AllocateInMap(sizeof(pkgCache::Package
));
574 if (unlikely(Package
== 0))
576 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
578 // Insert the package into our package list
579 if (Grp
->FirstPackage
== 0) // the group is new
581 // Insert it into the hash table
582 unsigned long const Hash
= Cache
.Hash(Name
);
583 Pkg
->NextPackage
= Cache
.HeaderP
->PkgHashTable
[Hash
];
584 Cache
.HeaderP
->PkgHashTable
[Hash
] = Package
;
585 Grp
->FirstPackage
= Package
;
587 else // Group the Packages together
589 // this package is the new last package
590 pkgCache::PkgIterator
LastPkg(Cache
, Cache
.PkgP
+ Grp
->LastPackage
);
591 Pkg
->NextPackage
= LastPkg
->NextPackage
;
592 LastPkg
->NextPackage
= Package
;
594 Grp
->LastPackage
= Package
;
596 // Set the name, arch and the ID
597 Pkg
->Name
= Grp
->Name
;
598 Pkg
->Group
= Grp
.Index();
599 // all is mapped to the native architecture
600 map_ptrloc
const idxArch
= (Arch
== "all") ? Cache
.HeaderP
->Architecture
: WriteUniqString(Arch
.c_str());
601 if (unlikely(idxArch
== 0))
604 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
609 // CacheGenerator::AddImplicitDepends /*{{{*/
610 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator
&G
,
611 pkgCache::PkgIterator
&P
,
612 pkgCache::VerIterator
&V
)
614 // copy P.Arch() into a string here as a cache remap
615 // in NewDepends() later may alter the pointer location
616 string Arch
= P
.Arch() == NULL
? "" : P
.Arch();
617 map_ptrloc
*OldDepLast
= NULL
;
618 /* MultiArch handling introduces a lot of implicit Dependencies:
619 - MultiArch: same → Co-Installable if they have the same version
620 - All others conflict with all other group members */
621 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
622 pkgCache::PkgIterator D
= G
.PackageList();
623 Dynamic
<pkgCache::PkgIterator
> DynD(D
);
624 for (; D
.end() != true; D
= G
.NextPkg(D
))
626 if (Arch
== D
.Arch() || D
->VersionList
== 0)
628 /* We allow only one installed arch at the time
629 per group, therefore each group member conflicts
630 with all other group members */
631 if (coInstall
== true)
633 // Replaces: ${self}:other ( << ${binary:Version})
634 NewDepends(D
, V
, V
.VerStr(),
635 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
637 // Breaks: ${self}:other (!= ${binary:Version})
638 NewDepends(D
, V
, V
.VerStr(),
639 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
642 // Conflicts: ${self}:other
644 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
650 bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator
&V
,
651 pkgCache::PkgIterator
&D
)
653 /* MultiArch handling introduces a lot of implicit Dependencies:
654 - MultiArch: same → Co-Installable if they have the same version
655 - All others conflict with all other group members */
656 map_ptrloc
*OldDepLast
= NULL
;
657 bool const coInstall
= ((V
->MultiArch
& pkgCache::Version::Same
) == pkgCache::Version::Same
);
658 if (coInstall
== true)
660 // Replaces: ${self}:other ( << ${binary:Version})
661 NewDepends(D
, V
, V
.VerStr(),
662 pkgCache::Dep::Less
, pkgCache::Dep::Replaces
,
664 // Breaks: ${self}:other (!= ${binary:Version})
665 NewDepends(D
, V
, V
.VerStr(),
666 pkgCache::Dep::NotEquals
, pkgCache::Dep::DpkgBreaks
,
669 // Conflicts: ${self}:other
671 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
678 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
679 // ---------------------------------------------------------------------
681 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
684 if (CurrentFile
== 0)
688 map_ptrloc
const VerFile
= AllocateInMap(sizeof(pkgCache::VerFile
));
692 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
693 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
695 // Link it to the end of the list
696 map_ptrloc
*Last
= &Ver
->FileList
;
697 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; ++V
)
699 VF
->NextFile
= *Last
;
702 VF
->Offset
= List
.Offset();
703 VF
->Size
= List
.Size();
704 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
705 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
706 Cache
.HeaderP
->VerFileCount
++;
711 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
712 // ---------------------------------------------------------------------
713 /* This puts a version structure in the linked list */
714 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
715 const string
&VerStr
,
719 map_ptrloc
const Version
= AllocateInMap(sizeof(pkgCache::Version
));
724 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
726 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
727 map_ptrloc
const idxVerStr
= WriteStringInMap(VerStr
);
728 if (unlikely(idxVerStr
== 0))
730 Ver
->VerStr
= idxVerStr
;
735 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
736 // ---------------------------------------------------------------------
738 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
741 if (CurrentFile
== 0)
745 map_ptrloc
const DescFile
= AllocateInMap(sizeof(pkgCache::DescFile
));
749 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
750 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
752 // Link it to the end of the list
753 map_ptrloc
*Last
= &Desc
->FileList
;
754 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; ++D
)
757 DF
->NextFile
= *Last
;
760 DF
->Offset
= List
.Offset();
761 DF
->Size
= List
.Size();
762 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
763 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
764 Cache
.HeaderP
->DescFileCount
++;
769 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
770 // ---------------------------------------------------------------------
771 /* This puts a description structure in the linked list */
772 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
774 const MD5SumValue
&md5sum
,
778 map_ptrloc
const Description
= AllocateInMap(sizeof(pkgCache::Description
));
779 if (Description
== 0)
783 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
784 Desc
->NextDesc
= Next
;
785 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
786 map_ptrloc
const idxlanguage_code
= WriteStringInMap(Lang
);
787 map_ptrloc
const idxmd5sum
= WriteStringInMap(md5sum
.Value());
788 if (unlikely(idxlanguage_code
== 0 || idxmd5sum
== 0))
790 Desc
->language_code
= idxlanguage_code
;
791 Desc
->md5sum
= idxmd5sum
;
796 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
797 // ---------------------------------------------------------------------
798 /* This creates a dependency element in the tree. It is linked to the
799 version and to the package that it is pointing to. */
800 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
801 pkgCache::VerIterator
&Ver
,
802 string
const &Version
,
803 unsigned int const &Op
,
804 unsigned int const &Type
,
805 map_ptrloc
* &OldDepLast
)
807 void const * const oldMap
= Map
.Data();
809 map_ptrloc
const Dependency
= AllocateInMap(sizeof(pkgCache::Dependency
));
810 if (unlikely(Dependency
== 0))
814 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
815 Dynamic
<pkgCache::DepIterator
> DynDep(Dep
);
816 Dep
->ParentVer
= Ver
.Index();
819 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
821 // Probe the reverse dependency list for a version string that matches
822 if (Version
.empty() == false)
824 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
825 if (I->Version != 0 && I.TargetVer() == Version)
826 Dep->Version = I->Version;*/
827 if (Dep
->Version
== 0) {
828 map_ptrloc
const index
= WriteStringInMap(Version
);
829 if (unlikely(index
== 0))
831 Dep
->Version
= index
;
835 // Link it to the package
836 Dep
->Package
= Pkg
.Index();
837 Dep
->NextRevDepends
= Pkg
->RevDepends
;
838 Pkg
->RevDepends
= Dep
.Index();
840 // Do we know where to link the Dependency to?
841 if (OldDepLast
== NULL
)
843 OldDepLast
= &Ver
->DependsList
;
844 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; ++D
)
845 OldDepLast
= &D
->NextDepends
;
846 } else if (oldMap
!= Map
.Data())
847 OldDepLast
+= (map_ptrloc
*) Map
.Data() - (map_ptrloc
*) oldMap
;
849 Dep
->NextDepends
= *OldDepLast
;
850 *OldDepLast
= Dep
.Index();
851 OldDepLast
= &Dep
->NextDepends
;
856 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
857 // ---------------------------------------------------------------------
858 /* This creates a Group and the Package to link this dependency to if
859 needed and handles also the caching of the old endpoint */
860 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator
&Ver
,
861 const string
&PackageName
,
863 const string
&Version
,
867 pkgCache::GrpIterator Grp
;
868 Dynamic
<pkgCache::GrpIterator
> DynGrp(Grp
);
869 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
872 // Locate the target package
873 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(Arch
);
874 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
875 if (Pkg
.end() == true) {
876 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
880 // Is it a file dependency?
881 if (unlikely(PackageName
[0] == '/'))
882 FoundFileDeps
= true;
884 /* Caching the old end point speeds up generation substantially */
885 if (OldDepVer
!= Ver
) {
890 return Owner
->NewDepends(Pkg
, Ver
, Version
, Op
, Type
, OldDepLast
);
893 // ListParser::NewProvides - Create a Provides element /*{{{*/
894 // ---------------------------------------------------------------------
896 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator
&Ver
,
897 const string
&PkgName
,
898 const string
&PkgArch
,
899 const string
&Version
)
901 pkgCache
&Cache
= Owner
->Cache
;
903 // We do not add self referencing provides
904 if (Ver
.ParentPkg().Name() == PkgName
&& (PkgArch
== Ver
.ParentPkg().Arch() ||
905 (PkgArch
== "all" && strcmp((Cache
.StrP
+ Cache
.HeaderP
->Architecture
), Ver
.ParentPkg().Arch()) == 0)))
909 map_ptrloc
const Provides
= Owner
->AllocateInMap(sizeof(pkgCache::Provides
));
910 if (unlikely(Provides
== 0))
912 Cache
.HeaderP
->ProvidesCount
++;
915 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
916 Dynamic
<pkgCache::PrvIterator
> DynPrv(Prv
);
917 Prv
->Version
= Ver
.Index();
918 Prv
->NextPkgProv
= Ver
->ProvidesList
;
919 Ver
->ProvidesList
= Prv
.Index();
920 if (Version
.empty() == false && unlikely((Prv
->ProvideVersion
= WriteString(Version
)) == 0))
923 // Locate the target package
924 pkgCache::PkgIterator Pkg
;
925 Dynamic
<pkgCache::PkgIterator
> DynPkg(Pkg
);
926 if (unlikely(Owner
->NewPackage(Pkg
,PkgName
, PkgArch
) == false))
929 // Link it to the package
930 Prv
->ParentPkg
= Pkg
.Index();
931 Prv
->NextProvides
= Pkg
->ProvidesList
;
932 Pkg
->ProvidesList
= Prv
.Index();
937 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
938 // ---------------------------------------------------------------------
939 /* This is used to select which file is to be associated with all newly
940 added versions. The caller is responsible for setting the IMS fields. */
941 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
942 const pkgIndexFile
&Index
,
945 // Get some space for the structure
946 map_ptrloc
const idxFile
= AllocateInMap(sizeof(*CurrentFile
));
947 if (unlikely(idxFile
== 0))
949 CurrentFile
= Cache
.PkgFileP
+ idxFile
;
952 map_ptrloc
const idxFileName
= WriteStringInMap(File
);
953 map_ptrloc
const idxSite
= WriteUniqString(Site
);
954 if (unlikely(idxFileName
== 0 || idxSite
== 0))
956 CurrentFile
->FileName
= idxFileName
;
957 CurrentFile
->Site
= idxSite
;
958 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
959 CurrentFile
->Flags
= Flags
;
960 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
961 map_ptrloc
const idxIndexType
= WriteUniqString(Index
.GetType()->Label
);
962 if (unlikely(idxIndexType
== 0))
964 CurrentFile
->IndexType
= idxIndexType
;
966 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
967 Cache
.HeaderP
->PackageFileCount
++;
970 Progress
->SubProgress(Index
.Size());
974 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
975 // ---------------------------------------------------------------------
976 /* This is used to create handles to strings. Given the same text it
977 always returns the same number */
978 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
981 /* We use a very small transient hash table here, this speeds up generation
982 by a fair amount on slower machines */
983 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
985 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
986 return Bucket
->String
;
988 // Search for an insertion point
989 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
991 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
992 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
993 I
= Cache
.StringItemP
+ I
->NextItem
)
995 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
1008 void const * const oldMap
= Map
.Data();
1009 map_ptrloc
const Item
= AllocateInMap(sizeof(pkgCache::StringItem
));
1013 map_ptrloc
const idxString
= WriteStringInMap(S
,Size
);
1014 if (unlikely(idxString
== 0))
1016 if (oldMap
!= Map
.Data()) {
1017 Last
+= (map_ptrloc
*) Map
.Data() - (map_ptrloc
*) oldMap
;
1018 I
+= (pkgCache::StringItem
*) Map
.Data() - (pkgCache::StringItem
*) oldMap
;
1022 // Fill in the structure
1023 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
1024 ItemP
->NextItem
= I
- Cache
.StringItemP
;
1025 ItemP
->String
= idxString
;
1028 return ItemP
->String
;
1031 // CheckValidity - Check that a cache is up-to-date /*{{{*/
1032 // ---------------------------------------------------------------------
1033 /* This just verifies that each file in the list of index files exists,
1034 has matching attributes with the cache and the cache does not have
1036 static bool CheckValidity(const string
&CacheFile
,
1037 pkgSourceList
&List
,
1042 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1043 // No file, certainly invalid
1044 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
1047 std::clog
<< "CacheFile doesn't exist" << std::endl
;
1051 if (List
.GetLastModifiedTime() > GetModificationTime(CacheFile
))
1054 std::clog
<< "sources.list is newer than the cache" << std::endl
;
1059 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
1060 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
1061 pkgCache
Cache(Map
);
1062 if (_error
->PendingError() == true || Map
->Size() == 0)
1065 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
1070 /* Now we check every index file, see if it is in the cache,
1071 verify the IMS data and check that it is on the disk too.. */
1072 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
1073 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
1074 for (; Start
!= End
; ++Start
)
1077 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
1078 if ((*Start
)->HasPackages() == false)
1081 std::clog
<< "Has NO packages" << std::endl
;
1085 if ((*Start
)->Exists() == false)
1087 #if 0 // mvo: we no longer give a message here (Default Sources spec)
1088 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
1089 (*Start
)->Describe().c_str());
1092 std::clog
<< "file doesn't exist" << std::endl
;
1096 // FindInCache is also expected to do an IMS check.
1097 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
1098 if (File
.end() == true)
1101 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
1105 Visited
[File
->ID
] = true;
1107 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
1110 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
1111 if (Visited
[I
] == false)
1114 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
1118 if (_error
->PendingError() == true)
1122 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
1123 _error
->DumpErrors();
1130 *OutMap
= Map
.UnGuard();
1134 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
1135 // ---------------------------------------------------------------------
1136 /* Size is kind of an abstract notion that is only used for the progress
1138 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
1140 unsigned long TotalSize
= 0;
1141 for (; Start
!= End
; ++Start
)
1143 if ((*Start
)->HasPackages() == false)
1145 TotalSize
+= (*Start
)->Size();
1150 // BuildCache - Merge the list of index files into the cache /*{{{*/
1151 // ---------------------------------------------------------------------
1153 static bool BuildCache(pkgCacheGenerator
&Gen
,
1154 OpProgress
*Progress
,
1155 unsigned long &CurrentSize
,unsigned long TotalSize
,
1156 FileIterator Start
, FileIterator End
)
1159 for (I
= Start
; I
!= End
; ++I
)
1161 if ((*I
)->HasPackages() == false)
1164 if ((*I
)->Exists() == false)
1167 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
1169 _error
->Warning("Duplicate sources.list entry %s",
1170 (*I
)->Describe().c_str());
1174 unsigned long Size
= (*I
)->Size();
1175 if (Progress
!= NULL
)
1176 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
1177 CurrentSize
+= Size
;
1179 if ((*I
)->Merge(Gen
,Progress
) == false)
1183 if (Gen
.HasFileDeps() == true)
1185 if (Progress
!= NULL
)
1187 TotalSize
= ComputeSize(Start
, End
);
1189 for (I
= Start
; I
!= End
; ++I
)
1191 unsigned long Size
= (*I
)->Size();
1192 if (Progress
!= NULL
)
1193 Progress
->OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
1194 CurrentSize
+= Size
;
1195 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
1203 // CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
1204 DynamicMMap
* pkgCacheGenerator::CreateDynamicMMap(FileFd
*CacheF
, unsigned long Flags
) {
1205 unsigned long const MapStart
= _config
->FindI("APT::Cache-Start", 24*1024*1024);
1206 unsigned long const MapGrow
= _config
->FindI("APT::Cache-Grow", 1*1024*1024);
1207 unsigned long const MapLimit
= _config
->FindI("APT::Cache-Limit", 0);
1208 Flags
|= MMap::Moveable
;
1209 if (_config
->FindB("APT::Cache-Fallback", false) == true)
1210 Flags
|= MMap::Fallback
;
1212 return new DynamicMMap(*CacheF
, Flags
, MapStart
, MapGrow
, MapLimit
);
1214 return new DynamicMMap(Flags
, MapStart
, MapGrow
, MapLimit
);
1217 // CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1218 // ---------------------------------------------------------------------
1219 /* This makes sure that the status cache (the cache that has all
1220 index files from the sources list and all local ones) is ready
1221 to be mmaped. If OutMap is not zero then a MMap object representing
1222 the cache will be stored there. This is pretty much mandetory if you
1223 are using AllowMem. AllowMem lets the function be run as non-root
1224 where it builds the cache 'fast' into a memory buffer. */
1225 __deprecated
bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
1226 MMap
**OutMap
, bool AllowMem
)
1227 { return pkgCacheGenerator::MakeStatusCache(List
, &Progress
, OutMap
, AllowMem
); }
1228 bool pkgCacheGenerator::MakeStatusCache(pkgSourceList
&List
,OpProgress
*Progress
,
1229 MMap
**OutMap
,bool AllowMem
)
1231 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
1233 std::vector
<pkgIndexFile
*> Files
;
1234 for (std::vector
<metaIndex
*>::const_iterator i
= List
.begin();
1238 std::vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
1239 for (std::vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
1240 j
!= Indexes
->end();
1242 Files
.push_back (*j
);
1245 unsigned long const EndOfSource
= Files
.size();
1246 if (_system
->AddStatusFiles(Files
) == false)
1249 // Decide if we can write to the files..
1250 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
1251 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
1253 // ensure the cache directory exists
1254 if (CacheFile
.empty() == false || SrcCacheFile
.empty() == false)
1256 string dir
= _config
->FindDir("Dir::Cache");
1257 size_t const len
= dir
.size();
1258 if (len
> 5 && dir
.find("/apt/", len
- 6, 5) == len
- 5)
1259 dir
= dir
.substr(0, len
- 5);
1260 if (CacheFile
.empty() == false)
1261 CreateDirectory(dir
, flNotFile(CacheFile
));
1262 if (SrcCacheFile
.empty() == false)
1263 CreateDirectory(dir
, flNotFile(SrcCacheFile
));
1266 // Decide if we can write to the cache
1267 bool Writeable
= false;
1268 if (CacheFile
.empty() == false)
1269 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
1271 if (SrcCacheFile
.empty() == false)
1272 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
1274 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
1276 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
1277 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
1279 if (Progress
!= NULL
)
1280 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1282 // Cache is OK, Fin.
1283 if (CheckValidity(CacheFile
, List
, Files
.begin(),Files
.end(),OutMap
) == true)
1285 if (Progress
!= NULL
)
1286 Progress
->OverallProgress(1,1,1,_("Reading package lists"));
1288 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
1291 else if (Debug
== true)
1292 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
1294 /* At this point we know we need to reconstruct the package cache,
1296 SPtr
<FileFd
> CacheF
;
1297 SPtr
<DynamicMMap
> Map
;
1298 if (Writeable
== true && CacheFile
.empty() == false)
1300 _error
->PushToStack();
1301 unlink(CacheFile
.c_str());
1302 CacheF
= new FileFd(CacheFile
,FileFd::WriteAtomic
);
1303 fchmod(CacheF
->Fd(),0644);
1304 Map
= CreateDynamicMMap(CacheF
, MMap::Public
);
1305 if (_error
->PendingError() == true)
1307 delete CacheF
.UnGuard();
1308 delete Map
.UnGuard();
1310 std::clog
<< "Open filebased MMap FAILED" << std::endl
;
1312 if (AllowMem
== false)
1314 _error
->MergeWithStack();
1317 _error
->RevertToStack();
1319 else if (Debug
== true)
1321 _error
->MergeWithStack();
1322 std::clog
<< "Open filebased MMap" << std::endl
;
1325 if (Writeable
== false || CacheFile
.empty() == true)
1327 // Just build it in memory..
1328 Map
= CreateDynamicMMap(NULL
);
1330 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
1333 // Lets try the source cache.
1334 unsigned long CurrentSize
= 0;
1335 unsigned long TotalSize
= 0;
1336 if (CheckValidity(SrcCacheFile
, List
, Files
.begin(),
1337 Files
.begin()+EndOfSource
) == true)
1340 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
1341 // Preload the map with the source cache
1342 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
1343 unsigned long const alloc
= Map
->RawAllocate(SCacheF
.Size());
1344 if ((alloc
== 0 && _error
->PendingError())
1345 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1346 SCacheF
.Size()) == false)
1349 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1351 // Build the status cache
1352 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1353 if (_error
->PendingError() == true)
1355 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1356 Files
.begin()+EndOfSource
,Files
.end()) == false)
1362 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1363 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
1365 // Build the source cache
1366 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1367 if (_error
->PendingError() == true)
1369 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1370 Files
.begin(),Files
.begin()+EndOfSource
) == false)
1374 if (Writeable
== true && SrcCacheFile
.empty() == false)
1376 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteAtomic
);
1377 if (_error
->PendingError() == true)
1380 fchmod(SCacheF
.Fd(),0644);
1382 // Write out the main data
1383 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1384 return _error
->Error(_("IO Error saving source cache"));
1387 // Write out the proper header
1388 Gen
.GetCache().HeaderP
->Dirty
= false;
1389 if (SCacheF
.Seek(0) == false ||
1390 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1391 return _error
->Error(_("IO Error saving source cache"));
1392 Gen
.GetCache().HeaderP
->Dirty
= true;
1396 // Build the status cache
1397 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1398 Files
.begin()+EndOfSource
,Files
.end()) == false)
1402 std::clog
<< "Caches are ready for shipping" << std::endl
;
1404 if (_error
->PendingError() == true)
1410 delete Map
.UnGuard();
1411 *OutMap
= new MMap(*CacheF
,0);
1415 *OutMap
= Map
.UnGuard();
1422 // CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1423 // ---------------------------------------------------------------------
1425 __deprecated
bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1426 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress
, OutMap
); }
1427 bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress
*Progress
,DynamicMMap
**OutMap
)
1429 std::vector
<pkgIndexFile
*> Files
;
1430 unsigned long EndOfSource
= Files
.size();
1431 if (_system
->AddStatusFiles(Files
) == false)
1434 SPtr
<DynamicMMap
> Map
= CreateDynamicMMap(NULL
);
1435 unsigned long CurrentSize
= 0;
1436 unsigned long TotalSize
= 0;
1438 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1440 // Build the status cache
1441 if (Progress
!= NULL
)
1442 Progress
->OverallProgress(0,1,1,_("Reading package lists"));
1443 pkgCacheGenerator
Gen(Map
.Get(),Progress
);
1444 if (_error
->PendingError() == true)
1446 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1447 Files
.begin()+EndOfSource
,Files
.end()) == false)
1450 if (_error
->PendingError() == true)
1452 *OutMap
= Map
.UnGuard();
1457 // IsDuplicateDescription /*{{{*/
1458 static bool IsDuplicateDescription(pkgCache::DescIterator Desc
,
1459 MD5SumValue
const &CurMd5
, std::string
const &CurLang
)
1461 // Descriptions in the same link-list have all the same md5
1462 if (Desc
.end() == true || MD5SumValue(Desc
.md5()) != CurMd5
)
1464 for (; Desc
.end() == false; ++Desc
)
1465 if (Desc
.LanguageCode() == CurLang
)
1470 // CacheGenerator::FinishCache /*{{{*/
1471 bool pkgCacheGenerator::FinishCache(OpProgress
*Progress
)