]> git.saurik.com Git - apt.git/blame_incremental - apt-pkg/pkgcachegen.cc
implement autobit and pinning in EDSP solver 'apt'
[apt.git] / apt-pkg / pkgcachegen.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz Exp $
4/* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12// Include Files /*{{{*/
13#include <config.h>
14
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/pkgsystem.h>
22#include <apt-pkg/macros.h>
23#include <apt-pkg/metaindex.h>
24#include <apt-pkg/fileutl.h>
25#include <apt-pkg/hashsum_template.h>
26#include <apt-pkg/indexfile.h>
27#include <apt-pkg/md5.h>
28#include <apt-pkg/mmap.h>
29#include <apt-pkg/pkgcache.h>
30#include <apt-pkg/cacheiterators.h>
31
32#include <stddef.h>
33#include <string.h>
34#include <iostream>
35#include <string>
36#include <vector>
37#include <memory>
38#include <algorithm>
39#include <sys/stat.h>
40#include <unistd.h>
41
42#include <apti18n.h>
43
44template<class T> using Dynamic = pkgCacheGenerator::Dynamic<T>; /*}}}*/
45typedef std::vector<pkgIndexFile *>::iterator FileIterator;
46template <typename Iter> std::vector<Iter*> pkgCacheGenerator::Dynamic<Iter>::toReMap;
47
48static bool IsDuplicateDescription(pkgCache::DescIterator Desc,
49 MD5SumValue const &CurMd5, std::string const &CurLang);
50
51using std::string;
52
53// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
54// ---------------------------------------------------------------------
55/* We set the dirty flag and make sure that is written to the disk */
56pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
57 Map(*pMap), Cache(pMap,false), Progress(Prog),
58 CurrentRlsFile(NULL), CurrentFile(NULL), d(NULL)
59{
60 if (_error->PendingError() == true)
61 return;
62
63 if (Map.Size() == 0)
64 {
65 // Setup the map interface..
66 Cache.HeaderP = (pkgCache::Header *)Map.Data();
67 if (Map.RawAllocate(sizeof(pkgCache::Header)) == 0 && _error->PendingError() == true)
68 return;
69
70 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
71
72 // Starting header
73 *Cache.HeaderP = pkgCache::Header();
74
75 // make room for the hashtables for packages and groups
76 if (Map.RawAllocate(2 * (Cache.HeaderP->GetHashTableSize() * sizeof(map_pointer_t))) == 0)
77 return;
78
79 map_stringitem_t const idxVerSysName = WriteStringInMap(_system->VS->Label);
80 if (unlikely(idxVerSysName == 0))
81 return;
82 Cache.HeaderP->VerSysName = idxVerSysName;
83 map_stringitem_t const idxArchitecture = StoreString(MIXED, _config->Find("APT::Architecture"));
84 if (unlikely(idxArchitecture == 0))
85 return;
86 Cache.HeaderP->Architecture = idxArchitecture;
87
88 std::vector<std::string> archs = APT::Configuration::getArchitectures();
89 if (archs.size() > 1)
90 {
91 std::vector<std::string>::const_iterator a = archs.begin();
92 std::string list = *a;
93 for (++a; a != archs.end(); ++a)
94 list.append(",").append(*a);
95 map_stringitem_t const idxArchitectures = WriteStringInMap(list);
96 if (unlikely(idxArchitectures == 0))
97 return;
98 Cache.HeaderP->SetArchitectures(idxArchitectures);
99 }
100 else
101 Cache.HeaderP->SetArchitectures(idxArchitecture);
102
103 Cache.ReMap();
104 }
105 else
106 {
107 // Map directly from the existing file
108 Cache.ReMap();
109 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
110 if (Cache.VS != _system->VS)
111 {
112 _error->Error(_("Cache has an incompatible versioning system"));
113 return;
114 }
115 }
116
117 Cache.HeaderP->Dirty = true;
118 Map.Sync(0,sizeof(pkgCache::Header));
119}
120 /*}}}*/
121// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
122// ---------------------------------------------------------------------
123/* We sync the data then unset the dirty flag in two steps so as to
124 advoid a problem during a crash */
125pkgCacheGenerator::~pkgCacheGenerator()
126{
127 if (_error->PendingError() == true)
128 return;
129 if (Map.Sync() == false)
130 return;
131
132 Cache.HeaderP->Dirty = false;
133 Cache.HeaderP->CacheFileSize = Map.Size();
134 Map.Sync(0,sizeof(pkgCache::Header));
135}
136 /*}}}*/
137void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newMap) {/*{{{*/
138 if (oldMap == newMap)
139 return;
140
141 if (_config->FindB("Debug::pkgCacheGen", false))
142 std::clog << "Remaping from " << oldMap << " to " << newMap << std::endl;
143
144 Cache.ReMap(false);
145
146 CurrentFile += (pkgCache::PackageFile const * const) newMap - (pkgCache::PackageFile const * const) oldMap;
147 CurrentRlsFile += (pkgCache::ReleaseFile const * const) newMap - (pkgCache::ReleaseFile const * const) oldMap;
148
149 for (std::vector<pkgCache::GrpIterator*>::const_iterator i = Dynamic<pkgCache::GrpIterator>::toReMap.begin();
150 i != Dynamic<pkgCache::GrpIterator>::toReMap.end(); ++i)
151 (*i)->ReMap(oldMap, newMap);
152 for (std::vector<pkgCache::PkgIterator*>::const_iterator i = Dynamic<pkgCache::PkgIterator>::toReMap.begin();
153 i != Dynamic<pkgCache::PkgIterator>::toReMap.end(); ++i)
154 (*i)->ReMap(oldMap, newMap);
155 for (std::vector<pkgCache::VerIterator*>::const_iterator i = Dynamic<pkgCache::VerIterator>::toReMap.begin();
156 i != Dynamic<pkgCache::VerIterator>::toReMap.end(); ++i)
157 (*i)->ReMap(oldMap, newMap);
158 for (std::vector<pkgCache::DepIterator*>::const_iterator i = Dynamic<pkgCache::DepIterator>::toReMap.begin();
159 i != Dynamic<pkgCache::DepIterator>::toReMap.end(); ++i)
160 (*i)->ReMap(oldMap, newMap);
161 for (std::vector<pkgCache::DescIterator*>::const_iterator i = Dynamic<pkgCache::DescIterator>::toReMap.begin();
162 i != Dynamic<pkgCache::DescIterator>::toReMap.end(); ++i)
163 (*i)->ReMap(oldMap, newMap);
164 for (std::vector<pkgCache::PrvIterator*>::const_iterator i = Dynamic<pkgCache::PrvIterator>::toReMap.begin();
165 i != Dynamic<pkgCache::PrvIterator>::toReMap.end(); ++i)
166 (*i)->ReMap(oldMap, newMap);
167 for (std::vector<pkgCache::PkgFileIterator*>::const_iterator i = Dynamic<pkgCache::PkgFileIterator>::toReMap.begin();
168 i != Dynamic<pkgCache::PkgFileIterator>::toReMap.end(); ++i)
169 (*i)->ReMap(oldMap, newMap);
170 for (std::vector<pkgCache::RlsFileIterator*>::const_iterator i = Dynamic<pkgCache::RlsFileIterator>::toReMap.begin();
171 i != Dynamic<pkgCache::RlsFileIterator>::toReMap.end(); ++i)
172 (*i)->ReMap(oldMap, newMap);
173} /*}}}*/
174// CacheGenerator::WriteStringInMap /*{{{*/
175map_stringitem_t pkgCacheGenerator::WriteStringInMap(const char *String,
176 const unsigned long &Len) {
177 void const * const oldMap = Map.Data();
178 map_stringitem_t const index = Map.WriteString(String, Len);
179 if (index != 0)
180 ReMap(oldMap, Map.Data());
181 return index;
182}
183 /*}}}*/
184// CacheGenerator::WriteStringInMap /*{{{*/
185map_stringitem_t pkgCacheGenerator::WriteStringInMap(const char *String) {
186 void const * const oldMap = Map.Data();
187 map_stringitem_t const index = Map.WriteString(String);
188 if (index != 0)
189 ReMap(oldMap, Map.Data());
190 return index;
191}
192 /*}}}*/
193map_pointer_t pkgCacheGenerator::AllocateInMap(const unsigned long &size) {/*{{{*/
194 void const * const oldMap = Map.Data();
195 map_pointer_t const index = Map.Allocate(size);
196 if (index != 0)
197 ReMap(oldMap, Map.Data());
198 return index;
199}
200 /*}}}*/
201// CacheGenerator::MergeList - Merge the package list /*{{{*/
202// ---------------------------------------------------------------------
203/* This provides the generation of the entries in the cache. Each loop
204 goes through a single package record from the underlying parse engine. */
205bool pkgCacheGenerator::MergeList(ListParser &List,
206 pkgCache::VerIterator *OutVer)
207{
208 List.Owner = this;
209
210 unsigned int Counter = 0;
211 while (List.Step() == true)
212 {
213 string const PackageName = List.Package();
214 if (PackageName.empty() == true)
215 return false;
216
217 Counter++;
218 if (Counter % 100 == 0 && Progress != 0)
219 Progress->Progress(List.Offset());
220
221 string Arch = List.Architecture();
222 string const Version = List.Version();
223 if (Version.empty() == true && Arch.empty() == true)
224 {
225 // package descriptions
226 if (MergeListGroup(List, PackageName) == false)
227 return false;
228 continue;
229 }
230
231 // Get a pointer to the package structure
232 pkgCache::PkgIterator Pkg;
233 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
234 if (NewPackage(Pkg, PackageName, Arch) == false)
235 // TRANSLATOR: The first placeholder is a package name,
236 // the other two should be copied verbatim as they include debug info
237 return _error->Error(_("Error occurred while processing %s (%s%d)"),
238 PackageName.c_str(), "NewPackage", 1);
239
240
241 if (Version.empty() == true)
242 {
243 if (MergeListPackage(List, Pkg) == false)
244 return false;
245 }
246 else
247 {
248 if (MergeListVersion(List, Pkg, Version, OutVer) == false)
249 return false;
250 }
251
252 if (OutVer != 0)
253 return true;
254 }
255
256 if (Cache.HeaderP->PackageCount >= std::numeric_limits<map_id_t>::max())
257 return _error->Error(_("Wow, you exceeded the number of package "
258 "names this APT is capable of."));
259 if (Cache.HeaderP->VersionCount >= std::numeric_limits<map_id_t>::max())
260 return _error->Error(_("Wow, you exceeded the number of versions "
261 "this APT is capable of."));
262 if (Cache.HeaderP->DescriptionCount >= std::numeric_limits<map_id_t>::max())
263 return _error->Error(_("Wow, you exceeded the number of descriptions "
264 "this APT is capable of."));
265 if (Cache.HeaderP->DependsCount >= std::numeric_limits<map_id_t>::max())
266 return _error->Error(_("Wow, you exceeded the number of dependencies "
267 "this APT is capable of."));
268
269 return true;
270}
271// CacheGenerator::MergeListGroup /*{{{*/
272bool pkgCacheGenerator::MergeListGroup(ListParser &List, std::string const &GrpName)
273{
274 pkgCache::GrpIterator Grp = Cache.FindGrp(GrpName);
275 // a group has no data on it's own, only packages have it but these
276 // stanzas like this come from Translation- files to add descriptions,
277 // but without a version we don't need a description for it…
278 if (Grp.end() == true)
279 return true;
280 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
281
282 pkgCache::PkgIterator Pkg;
283 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
284 for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
285 if (MergeListPackage(List, Pkg) == false)
286 return false;
287
288 return true;
289}
290 /*}}}*/
291// CacheGenerator::MergeListPackage /*{{{*/
292bool pkgCacheGenerator::MergeListPackage(ListParser &List, pkgCache::PkgIterator &Pkg)
293{
294 // we first process the package, then the descriptions
295 // (for deb this package processing is in fact a no-op)
296 pkgCache::VerIterator Ver(Cache);
297 Dynamic<pkgCache::VerIterator> DynVer(Ver);
298 if (List.UsePackage(Pkg, Ver) == false)
299 return _error->Error(_("Error occurred while processing %s (%s%d)"),
300 Pkg.Name(), "UsePackage", 1);
301
302 // Find the right version to write the description
303 MD5SumValue CurMd5 = List.Description_md5();
304 if (CurMd5.Value().empty() == true && List.Description("").empty() == true)
305 return true;
306 std::vector<std::string> availDesc = List.AvailableDescriptionLanguages();
307 for (Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
308 {
309 pkgCache::DescIterator VerDesc = Ver.DescriptionList();
310
311 // a version can only have one md5 describing it
312 if (VerDesc.end() == true || MD5SumValue(VerDesc.md5()) != CurMd5)
313 continue;
314
315 map_stringitem_t md5idx = VerDesc->md5sum;
316 for (std::vector<std::string>::const_iterator CurLang = availDesc.begin(); CurLang != availDesc.end(); ++CurLang)
317 {
318 // don't add a new description if we have one for the given
319 // md5 && language
320 if (IsDuplicateDescription(VerDesc, CurMd5, *CurLang) == true)
321 continue;
322
323 AddNewDescription(List, Ver, *CurLang, CurMd5, md5idx);
324 }
325
326 // we can stop here as all "same" versions will share the description
327 break;
328 }
329
330 return true;
331}
332 /*}}}*/
333// CacheGenerator::MergeListVersion /*{{{*/
334bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator &Pkg,
335 std::string const &Version, pkgCache::VerIterator* &OutVer)
336{
337 pkgCache::VerIterator Ver = Pkg.VersionList();
338 Dynamic<pkgCache::VerIterator> DynVer(Ver);
339 map_pointer_t *LastVer = &Pkg->VersionList;
340 void const * oldMap = Map.Data();
341
342 unsigned short const Hash = List.VersionHash();
343 if (Ver.end() == false)
344 {
345 /* We know the list is sorted so we use that fact in the search.
346 Insertion of new versions is done with correct sorting */
347 int Res = 1;
348 for (; Ver.end() == false; LastVer = &Ver->NextVer, ++Ver)
349 {
350 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
351 // Version is higher as current version - insert here
352 if (Res > 0)
353 break;
354 // Versionstrings are equal - is hash also equal?
355 if (Res == 0 && List.SameVersion(Hash, Ver) == true)
356 break;
357 // proceed with the next till we have either the right
358 // or we found another version (which will be lower)
359 }
360
361 /* We already have a version for this item, record that we saw it */
362 if (Res == 0 && Ver.end() == false && Ver->Hash == Hash)
363 {
364 if (List.UsePackage(Pkg,Ver) == false)
365 return _error->Error(_("Error occurred while processing %s (%s%d)"),
366 Pkg.Name(), "UsePackage", 2);
367
368 if (NewFileVer(Ver,List) == false)
369 return _error->Error(_("Error occurred while processing %s (%s%d)"),
370 Pkg.Name(), "NewFileVer", 1);
371
372 // Read only a single record and return
373 if (OutVer != 0)
374 {
375 *OutVer = Ver;
376 return true;
377 }
378
379 return true;
380 }
381 }
382
383 // Add a new version
384 map_pointer_t const verindex = NewVersion(Ver, Version, Pkg.Index(), Hash, *LastVer);
385 if (verindex == 0 && _error->PendingError())
386 return _error->Error(_("Error occurred while processing %s (%s%d)"),
387 Pkg.Name(), "NewVersion", 1);
388
389 if (oldMap != Map.Data())
390 LastVer += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
391 *LastVer = verindex;
392
393 if (unlikely(List.NewVersion(Ver) == false))
394 return _error->Error(_("Error occurred while processing %s (%s%d)"),
395 Pkg.Name(), "NewVersion", 2);
396
397 if (unlikely(List.UsePackage(Pkg,Ver) == false))
398 return _error->Error(_("Error occurred while processing %s (%s%d)"),
399 Pkg.Name(), "UsePackage", 3);
400
401 if (unlikely(NewFileVer(Ver,List) == false))
402 return _error->Error(_("Error occurred while processing %s (%s%d)"),
403 Pkg.Name(), "NewFileVer", 2);
404
405 pkgCache::GrpIterator Grp = Pkg.Group();
406 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
407
408 /* If it is the first version of this package we need to add implicit
409 Multi-Arch dependencies to all other package versions in the group now -
410 otherwise we just add them for this new version */
411 if (Pkg.VersionList()->NextVer == 0)
412 {
413 pkgCache::PkgIterator P = Grp.PackageList();
414 Dynamic<pkgCache::PkgIterator> DynP(P);
415 for (; P.end() != true; P = Grp.NextPkg(P))
416 {
417 if (P->ID == Pkg->ID)
418 continue;
419 pkgCache::VerIterator V = P.VersionList();
420 Dynamic<pkgCache::VerIterator> DynV(V);
421 for (; V.end() != true; ++V)
422 if (unlikely(AddImplicitDepends(V, Pkg) == false))
423 return _error->Error(_("Error occurred while processing %s (%s%d)"),
424 Pkg.Name(), "AddImplicitDepends", 1);
425 }
426 }
427 if (unlikely(AddImplicitDepends(Grp, Pkg, Ver) == false))
428 return _error->Error(_("Error occurred while processing %s (%s%d)"),
429 Pkg.Name(), "AddImplicitDepends", 2);
430
431 // Read only a single record and return
432 if (OutVer != 0)
433 {
434 *OutVer = Ver;
435 return true;
436 }
437
438 /* Record the Description(s) based on their master md5sum */
439 MD5SumValue CurMd5 = List.Description_md5();
440 if (CurMd5.Value().empty() == true && List.Description("").empty() == true)
441 return true;
442
443 /* Before we add a new description we first search in the group for
444 a version with a description of the same MD5 - if so we reuse this
445 description group instead of creating our own for this version */
446 for (pkgCache::PkgIterator P = Grp.PackageList();
447 P.end() == false; P = Grp.NextPkg(P))
448 {
449 for (pkgCache::VerIterator V = P.VersionList();
450 V.end() == false; ++V)
451 {
452 if (V->DescriptionList == 0 || MD5SumValue(V.DescriptionList().md5()) != CurMd5)
453 continue;
454 Ver->DescriptionList = V->DescriptionList;
455 }
456 }
457
458 // We haven't found reusable descriptions, so add the first description(s)
459 map_stringitem_t md5idx = Ver->DescriptionList == 0 ? 0 : Ver.DescriptionList()->md5sum;
460 std::vector<std::string> availDesc = List.AvailableDescriptionLanguages();
461 for (std::vector<std::string>::const_iterator CurLang = availDesc.begin(); CurLang != availDesc.end(); ++CurLang)
462 if (AddNewDescription(List, Ver, *CurLang, CurMd5, md5idx) == false)
463 return false;
464 return true;
465}
466 /*}}}*/
467bool pkgCacheGenerator::AddNewDescription(ListParser &List, pkgCache::VerIterator &Ver, std::string const &lang, MD5SumValue const &CurMd5, map_stringitem_t &md5idx) /*{{{*/
468{
469 pkgCache::DescIterator Desc;
470 Dynamic<pkgCache::DescIterator> DynDesc(Desc);
471
472 map_pointer_t const descindex = NewDescription(Desc, lang, CurMd5, md5idx);
473 if (unlikely(descindex == 0 && _error->PendingError()))
474 return _error->Error(_("Error occurred while processing %s (%s%d)"),
475 Ver.ParentPkg().Name(), "NewDescription", 1);
476
477 md5idx = Desc->md5sum;
478 Desc->ParentPkg = Ver.ParentPkg().Index();
479
480 // we add at the end, so that the start is constant as we need
481 // that to be able to efficiently share these lists
482 pkgCache::DescIterator VerDesc = Ver.DescriptionList(); // old value might be invalid after ReMap
483 for (;VerDesc.end() == false && VerDesc->NextDesc != 0; ++VerDesc);
484 map_pointer_t * const LastNextDesc = (VerDesc.end() == true) ? &Ver->DescriptionList : &VerDesc->NextDesc;
485 *LastNextDesc = descindex;
486
487 if (NewFileDesc(Desc,List) == false)
488 return _error->Error(_("Error occurred while processing %s (%s%d)"),
489 Ver.ParentPkg().Name(), "NewFileDesc", 1);
490
491 return true;
492}
493 /*}}}*/
494 /*}}}*/
495// CacheGenerator::NewGroup - Add a new group /*{{{*/
496// ---------------------------------------------------------------------
497/* This creates a new group structure and adds it to the hash table */
498bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name)
499{
500 Grp = Cache.FindGrp(Name);
501 if (Grp.end() == false)
502 return true;
503
504 // Get a structure
505 map_pointer_t const Group = AllocateInMap(sizeof(pkgCache::Group));
506 if (unlikely(Group == 0))
507 return false;
508
509 Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
510 map_stringitem_t const idxName = StoreString(PKGNAME, Name);
511 if (unlikely(idxName == 0))
512 return false;
513 Grp->Name = idxName;
514
515 // Insert it into the hash table
516 unsigned long const Hash = Cache.Hash(Name);
517 map_pointer_t *insertAt = &Cache.HeaderP->GrpHashTableP()[Hash];
518 while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + *insertAt)->Name) > 0)
519 insertAt = &(Cache.GrpP + *insertAt)->Next;
520 Grp->Next = *insertAt;
521 *insertAt = Group;
522
523 Grp->ID = Cache.HeaderP->GroupCount++;
524 return true;
525}
526 /*}}}*/
527// CacheGenerator::NewPackage - Add a new package /*{{{*/
528// ---------------------------------------------------------------------
529/* This creates a new package structure and adds it to the hash table */
530bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name,
531 const string &Arch) {
532 pkgCache::GrpIterator Grp;
533 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
534 if (unlikely(NewGroup(Grp, Name) == false))
535 return false;
536
537 Pkg = Grp.FindPkg(Arch);
538 if (Pkg.end() == false)
539 return true;
540
541 // Get a structure
542 map_pointer_t const Package = AllocateInMap(sizeof(pkgCache::Package));
543 if (unlikely(Package == 0))
544 return false;
545 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
546
547 // Set the name, arch and the ID
548 APT_IGNORE_DEPRECATED(Pkg->Name = Grp->Name;)
549 Pkg->Group = Grp.Index();
550 // all is mapped to the native architecture
551 map_stringitem_t const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : StoreString(MIXED, Arch);
552 if (unlikely(idxArch == 0))
553 return false;
554 Pkg->Arch = idxArch;
555 Pkg->ID = Cache.HeaderP->PackageCount++;
556
557 // Insert the package into our package list
558 if (Grp->FirstPackage == 0) // the group is new
559 {
560 Grp->FirstPackage = Package;
561 // Insert it into the hash table
562 map_id_t const Hash = Cache.Hash(Name);
563 map_pointer_t *insertAt = &Cache.HeaderP->PkgHashTableP()[Hash];
564 while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + (Cache.PkgP + *insertAt)->Group)->Name) > 0)
565 insertAt = &(Cache.PkgP + *insertAt)->NextPackage;
566 Pkg->NextPackage = *insertAt;
567 *insertAt = Package;
568 }
569 else // Group the Packages together
570 {
571 // but first get implicit provides done
572 if (APT::Configuration::checkArchitecture(Pkg.Arch()) == true)
573 {
574 pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false); // native or any foreign pkg will do
575 if (M.end() == false) {
576 pkgCache::PrvIterator Prv;
577 Dynamic<pkgCache::PrvIterator> DynPrv(Prv);
578 for (Prv = M.ProvidesList(); Prv.end() == false; ++Prv)
579 {
580 if ((Prv->Flags & pkgCache::Flag::ArchSpecific) != 0)
581 continue;
582 pkgCache::VerIterator Ver = Prv.OwnerVer();
583 Dynamic<pkgCache::VerIterator> DynVer(Ver);
584 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed ||
585 ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign &&
586 (Prv->Flags & pkgCache::Flag::MultiArchImplicit) == 0))
587 if (NewProvides(Ver, Pkg, Prv->ProvideVersion, Prv->Flags) == false)
588 return false;
589 }
590 }
591
592
593 pkgCache::PkgIterator P;
594 pkgCache::VerIterator Ver;
595 Dynamic<pkgCache::PkgIterator> DynP(P);
596 Dynamic<pkgCache::VerIterator> DynVer(Ver);
597
598 for (P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
599 for (Ver = P.VersionList(); Ver.end() == false; ++Ver)
600 if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
601 if (NewProvides(Ver, Pkg, Ver->VerStr, pkgCache::Flag::MultiArchImplicit) == false)
602 return false;
603 }
604 // and negative dependencies, don't forget negative dependencies
605 {
606 pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false);
607 if (M.end() == false) {
608 pkgCache::DepIterator Dep;
609 Dynamic<pkgCache::DepIterator> DynDep(Dep);
610 for (Dep = M.RevDependsList(); Dep.end() == false; ++Dep)
611 {
612 if ((Dep->CompareOp & (pkgCache::Dep::ArchSpecific | pkgCache::Dep::MultiArchImplicit)) != 0)
613 continue;
614 if (Dep->Type != pkgCache::Dep::DpkgBreaks && Dep->Type != pkgCache::Dep::Conflicts &&
615 Dep->Type != pkgCache::Dep::Replaces)
616 continue;
617 pkgCache::VerIterator Ver = Dep.ParentVer();
618 Dynamic<pkgCache::VerIterator> DynVer(Ver);
619 map_pointer_t * unused = NULL;
620 if (NewDepends(Pkg, Ver, Dep->Version, Dep->CompareOp, Dep->Type, unused) == false)
621 return false;
622 }
623 }
624 }
625
626 // this package is the new last package
627 pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
628 Pkg->NextPackage = LastPkg->NextPackage;
629 LastPkg->NextPackage = Package;
630 }
631 Grp->LastPackage = Package;
632
633 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
634 if (Arch == "any")
635 {
636 size_t const found = Name.find(':');
637 std::string const NameA = Name.substr(0, found);
638 std::string const ArchA = Name.substr(found + 1);
639 pkgCache::PkgIterator PkgA = Cache.FindPkg(NameA, ArchA);
640 if (PkgA.end() == false)
641 {
642 Dynamic<pkgCache::PkgIterator> DynPkgA(PkgA);
643 pkgCache::PrvIterator Prv = PkgA.ProvidesList();
644 for (; Prv.end() == false; ++Prv)
645 {
646 if (Prv.IsMultiArchImplicit())
647 continue;
648 pkgCache::VerIterator V = Prv.OwnerVer();
649 if (ArchA != V.ParentPkg().Arch())
650 continue;
651 if (NewProvides(V, Pkg, V->VerStr, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
652 return false;
653 }
654 pkgCache::VerIterator V = PkgA.VersionList();
655 Dynamic<pkgCache::VerIterator> DynV(V);
656 for (; V.end() == false; ++V)
657 {
658 if (NewProvides(V, Pkg, V->VerStr, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
659 return false;
660 }
661 }
662 }
663 return true;
664}
665 /*}}}*/
666// CacheGenerator::AddImplicitDepends /*{{{*/
667bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator &G,
668 pkgCache::PkgIterator &P,
669 pkgCache::VerIterator &V)
670{
671 // copy P.Arch() into a string here as a cache remap
672 // in NewDepends() later may alter the pointer location
673 string Arch = P.Arch() == NULL ? "" : P.Arch();
674 map_pointer_t *OldDepLast = NULL;
675 /* MultiArch handling introduces a lot of implicit Dependencies:
676 - MultiArch: same → Co-Installable if they have the same version
677 - All others conflict with all other group members */
678 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
679 pkgCache::PkgIterator D = G.PackageList();
680 Dynamic<pkgCache::PkgIterator> DynD(D);
681 map_stringitem_t const VerStrIdx = V->VerStr;
682 for (; D.end() != true; D = G.NextPkg(D))
683 {
684 if (Arch == D.Arch() || D->VersionList == 0)
685 continue;
686 /* We allow only one installed arch at the time
687 per group, therefore each group member conflicts
688 with all other group members */
689 if (coInstall == true)
690 {
691 // Replaces: ${self}:other ( << ${binary:Version})
692 NewDepends(D, V, VerStrIdx,
693 pkgCache::Dep::Less | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Replaces,
694 OldDepLast);
695 // Breaks: ${self}:other (!= ${binary:Version})
696 NewDepends(D, V, VerStrIdx,
697 pkgCache::Dep::NotEquals | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::DpkgBreaks,
698 OldDepLast);
699 } else {
700 // Conflicts: ${self}:other
701 NewDepends(D, V, 0,
702 pkgCache::Dep::NoOp | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Conflicts,
703 OldDepLast);
704 }
705 }
706 return true;
707}
708bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator &V,
709 pkgCache::PkgIterator &D)
710{
711 /* MultiArch handling introduces a lot of implicit Dependencies:
712 - MultiArch: same → Co-Installable if they have the same version
713 - All others conflict with all other group members */
714 map_pointer_t *OldDepLast = NULL;
715 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
716 if (coInstall == true)
717 {
718 map_stringitem_t const VerStrIdx = V->VerStr;
719 // Replaces: ${self}:other ( << ${binary:Version})
720 NewDepends(D, V, VerStrIdx,
721 pkgCache::Dep::Less | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Replaces,
722 OldDepLast);
723 // Breaks: ${self}:other (!= ${binary:Version})
724 NewDepends(D, V, VerStrIdx,
725 pkgCache::Dep::NotEquals | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::DpkgBreaks,
726 OldDepLast);
727 } else {
728 // Conflicts: ${self}:other
729 NewDepends(D, V, 0,
730 pkgCache::Dep::NoOp | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Conflicts,
731 OldDepLast);
732 }
733 return true;
734}
735
736 /*}}}*/
737// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
738// ---------------------------------------------------------------------
739/* */
740bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
741 ListParser &List)
742{
743 if (CurrentFile == 0)
744 return true;
745
746 // Get a structure
747 map_pointer_t const VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
748 if (VerFile == 0)
749 return false;
750
751 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
752 VF->File = CurrentFile - Cache.PkgFileP;
753
754 // Link it to the end of the list
755 map_pointer_t *Last = &Ver->FileList;
756 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; ++V)
757 Last = &V->NextFile;
758 VF->NextFile = *Last;
759 *Last = VF.Index();
760
761 VF->Offset = List.Offset();
762 VF->Size = List.Size();
763 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
764 Cache.HeaderP->MaxVerFileSize = VF->Size;
765 Cache.HeaderP->VerFileCount++;
766
767 return true;
768}
769 /*}}}*/
770// CacheGenerator::NewVersion - Create a new Version /*{{{*/
771// ---------------------------------------------------------------------
772/* This puts a version structure in the linked list */
773map_pointer_t pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
774 const string &VerStr,
775 map_pointer_t const ParentPkg,
776 unsigned short const Hash,
777 map_pointer_t const Next)
778{
779 // Get a structure
780 map_pointer_t const Version = AllocateInMap(sizeof(pkgCache::Version));
781 if (Version == 0)
782 return 0;
783
784 // Fill it in
785 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
786 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
787 Ver->NextVer = Next;
788 Ver->ParentPkg = ParentPkg;
789 Ver->Hash = Hash;
790 Ver->ID = Cache.HeaderP->VersionCount++;
791
792 // try to find the version string in the group for reuse
793 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
794 pkgCache::GrpIterator Grp = Pkg.Group();
795 if (Pkg.end() == false && Grp.end() == false)
796 {
797 for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
798 {
799 if (Pkg == P)
800 continue;
801 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
802 {
803 int const cmp = strcmp(V.VerStr(), VerStr.c_str());
804 if (cmp == 0)
805 {
806 Ver->VerStr = V->VerStr;
807 return Version;
808 }
809 else if (cmp < 0)
810 break;
811 }
812 }
813 }
814 // haven't found the version string, so create
815 map_stringitem_t const idxVerStr = StoreString(VERSIONNUMBER, VerStr);
816 if (unlikely(idxVerStr == 0))
817 return 0;
818 Ver->VerStr = idxVerStr;
819 return Version;
820}
821 /*}}}*/
822// CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
823// ---------------------------------------------------------------------
824/* */
825bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
826 ListParser &List)
827{
828 if (CurrentFile == 0)
829 return true;
830
831 // Get a structure
832 map_pointer_t const DescFile = AllocateInMap(sizeof(pkgCache::DescFile));
833 if (DescFile == 0)
834 return false;
835
836 pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
837 DF->File = CurrentFile - Cache.PkgFileP;
838
839 // Link it to the end of the list
840 map_pointer_t *Last = &Desc->FileList;
841 for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; ++D)
842 Last = &D->NextFile;
843
844 DF->NextFile = *Last;
845 *Last = DF.Index();
846
847 DF->Offset = List.Offset();
848 DF->Size = List.Size();
849 if (Cache.HeaderP->MaxDescFileSize < DF->Size)
850 Cache.HeaderP->MaxDescFileSize = DF->Size;
851 Cache.HeaderP->DescFileCount++;
852
853 return true;
854}
855 /*}}}*/
856// CacheGenerator::NewDescription - Create a new Description /*{{{*/
857// ---------------------------------------------------------------------
858/* This puts a description structure in the linked list */
859map_pointer_t pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
860 const string &Lang,
861 const MD5SumValue &md5sum,
862 map_stringitem_t const idxmd5str)
863{
864 // Get a structure
865 map_pointer_t const Description = AllocateInMap(sizeof(pkgCache::Description));
866 if (Description == 0)
867 return 0;
868
869 // Fill it in
870 Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
871 Desc->ID = Cache.HeaderP->DescriptionCount++;
872 map_stringitem_t const idxlanguage_code = StoreString(MIXED, Lang);
873 if (unlikely(idxlanguage_code == 0))
874 return 0;
875 Desc->language_code = idxlanguage_code;
876
877 if (idxmd5str != 0)
878 Desc->md5sum = idxmd5str;
879 else
880 {
881 map_stringitem_t const idxmd5sum = WriteStringInMap(md5sum.Value());
882 if (unlikely(idxmd5sum == 0))
883 return 0;
884 Desc->md5sum = idxmd5sum;
885 }
886
887 return Description;
888}
889 /*}}}*/
890// CacheGenerator::NewDepends - Create a dependency element /*{{{*/
891// ---------------------------------------------------------------------
892/* This creates a dependency element in the tree. It is linked to the
893 version and to the package that it is pointing to. */
894bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
895 pkgCache::VerIterator &Ver,
896 map_pointer_t const Version,
897 uint8_t const Op,
898 uint8_t const Type,
899 map_pointer_t* &OldDepLast)
900{
901 void const * const oldMap = Map.Data();
902 // Get a structure
903 map_pointer_t const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
904 if (unlikely(Dependency == 0))
905 return false;
906
907 bool isDuplicate = false;
908 map_pointer_t DependencyData = 0;
909 map_pointer_t PreviousData = 0;
910 if (Pkg->RevDepends != 0)
911 {
912 pkgCache::Dependency const * const L = Cache.DepP + Pkg->RevDepends;
913 DependencyData = L->DependencyData;
914 do {
915 pkgCache::DependencyData const * const D = Cache.DepDataP + DependencyData;
916 if (Version > D->Version)
917 break;
918 if (D->Version == Version && D->Type == Type && D->CompareOp == Op)
919 {
920 isDuplicate = true;
921 break;
922 }
923 PreviousData = DependencyData;
924 DependencyData = D->NextData;
925 } while (DependencyData != 0);
926 }
927
928 if (isDuplicate == false)
929 {
930 DependencyData = AllocateInMap(sizeof(pkgCache::DependencyData));
931 if (unlikely(DependencyData == 0))
932 return false;
933 }
934
935 pkgCache::Dependency * Link = Cache.DepP + Dependency;
936 Link->ParentVer = Ver.Index();
937 Link->DependencyData = DependencyData;
938 Link->ID = Cache.HeaderP->DependsCount++;
939
940 pkgCache::DepIterator Dep(Cache, Link);
941 if (isDuplicate == false)
942 {
943 Dep->Type = Type;
944 Dep->CompareOp = Op;
945 Dep->Version = Version;
946 Dep->Package = Pkg.Index();
947 ++Cache.HeaderP->DependsDataCount;
948 if (PreviousData != 0)
949 {
950 pkgCache::DependencyData * const D = Cache.DepDataP + PreviousData;
951 Dep->NextData = D->NextData;
952 D->NextData = DependencyData;
953 }
954 else if (Pkg->RevDepends != 0)
955 {
956 pkgCache::Dependency const * const D = Cache.DepP + Pkg->RevDepends;
957 Dep->NextData = D->DependencyData;
958 }
959 }
960
961 if (isDuplicate == true || PreviousData != 0)
962 {
963 pkgCache::Dependency * const L = Cache.DepP + Pkg->RevDepends;
964 Link->NextRevDepends = L->NextRevDepends;
965 L->NextRevDepends = Dependency;
966 }
967 else
968 {
969 Link->NextRevDepends = Pkg->RevDepends;
970 Pkg->RevDepends = Dependency;
971 }
972
973
974 // Do we know where to link the Dependency to?
975 if (OldDepLast == NULL)
976 {
977 OldDepLast = &Ver->DependsList;
978 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
979 OldDepLast = &D->NextDepends;
980 } else if (oldMap != Map.Data())
981 OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
982
983 Dep->NextDepends = *OldDepLast;
984 *OldDepLast = Dependency;
985 OldDepLast = &Dep->NextDepends;
986 return true;
987}
988 /*}}}*/
989// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
990// ---------------------------------------------------------------------
991/* This creates a Group and the Package to link this dependency to if
992 needed and handles also the caching of the old endpoint */
993bool pkgCacheListParser::NewDepends(pkgCache::VerIterator &Ver,
994 const string &PackageName,
995 const string &Arch,
996 const string &Version,
997 uint8_t const Op,
998 uint8_t const Type)
999{
1000 pkgCache::GrpIterator Grp;
1001 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
1002 if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
1003 return false;
1004
1005 map_stringitem_t idxVersion = 0;
1006 if (Version.empty() == false)
1007 {
1008 int const CmpOp = Op & 0x0F;
1009 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
1010 if (CmpOp == pkgCache::Dep::Equals && strcmp(Version.c_str(), Ver.VerStr()) == 0)
1011 idxVersion = Ver->VerStr;
1012
1013 if (idxVersion == 0)
1014 {
1015 idxVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version);
1016 if (unlikely(idxVersion == 0))
1017 return false;
1018 }
1019 }
1020
1021 bool const isNegative = (Type == pkgCache::Dep::DpkgBreaks ||
1022 Type == pkgCache::Dep::Conflicts ||
1023 Type == pkgCache::Dep::Replaces);
1024
1025 pkgCache::PkgIterator Pkg;
1026 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
1027 if (isNegative == false || (Op & pkgCache::Dep::ArchSpecific) == pkgCache::Dep::ArchSpecific || Grp->FirstPackage == 0)
1028 {
1029 // Locate the target package
1030 Pkg = Grp.FindPkg(Arch);
1031 if (Pkg.end() == true) {
1032 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
1033 return false;
1034 }
1035
1036 /* Caching the old end point speeds up generation substantially */
1037 if (OldDepVer != Ver) {
1038 OldDepLast = NULL;
1039 OldDepVer = Ver;
1040 }
1041
1042 return Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast);
1043 }
1044 else
1045 {
1046 /* Caching the old end point speeds up generation substantially */
1047 if (OldDepVer != Ver) {
1048 OldDepLast = NULL;
1049 OldDepVer = Ver;
1050 }
1051
1052 for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
1053 {
1054 if (Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast) == false)
1055 return false;
1056 }
1057 }
1058 return true;
1059}
1060 /*}}}*/
1061// ListParser::NewProvides - Create a Provides element /*{{{*/
1062bool pkgCacheListParser::NewProvides(pkgCache::VerIterator &Ver,
1063 const string &PkgName,
1064 const string &PkgArch,
1065 const string &Version,
1066 uint8_t const Flags)
1067{
1068 pkgCache const &Cache = Owner->Cache;
1069
1070 // We do not add self referencing provides
1071 if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
1072 (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
1073 return true;
1074
1075 // Locate the target package
1076 pkgCache::PkgIterator Pkg;
1077 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
1078 if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
1079 return false;
1080
1081 map_stringitem_t idxProvideVersion = 0;
1082 if (Version.empty() == false) {
1083 idxProvideVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version);
1084 if (unlikely(idxProvideVersion == 0))
1085 return false;
1086 }
1087 return Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags);
1088}
1089bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator &Ver,
1090 pkgCache::PkgIterator &Pkg,
1091 map_pointer_t const ProvideVersion,
1092 uint8_t const Flags)
1093{
1094 // Get a structure
1095 map_pointer_t const Provides = AllocateInMap(sizeof(pkgCache::Provides));
1096 if (unlikely(Provides == 0))
1097 return false;
1098 ++Cache.HeaderP->ProvidesCount;
1099
1100 // Fill it in
1101 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
1102 Prv->Version = Ver.Index();
1103 Prv->ProvideVersion = ProvideVersion;
1104 Prv->Flags = Flags;
1105 Prv->NextPkgProv = Ver->ProvidesList;
1106 Ver->ProvidesList = Prv.Index();
1107
1108 // Link it to the package
1109 Prv->ParentPkg = Pkg.Index();
1110 Prv->NextProvides = Pkg->ProvidesList;
1111 Pkg->ProvidesList = Prv.Index();
1112 return true;
1113}
1114 /*}}}*/
1115// ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
1116bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, string const &Package,
1117 string const &Version, uint8_t const Flags) {
1118 pkgCache &Cache = Owner->Cache;
1119 pkgCache::GrpIterator Grp = Cache.FindGrp(Package);
1120 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
1121
1122 if (Grp.end() == true)
1123 return NewProvides(Ver, Package, Cache.NativeArch(), Version, Flags);
1124 else
1125 {
1126 map_stringitem_t idxProvideVersion = 0;
1127 if (Version.empty() == false) {
1128 idxProvideVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version);
1129 if (unlikely(idxProvideVersion == 0))
1130 return false;
1131 }
1132
1133 bool const isImplicit = (Flags & pkgCache::Flag::MultiArchImplicit) == pkgCache::Flag::MultiArchImplicit;
1134 bool const isArchSpecific = (Flags & pkgCache::Flag::ArchSpecific) == pkgCache::Flag::ArchSpecific;
1135 pkgCache::PkgIterator OwnerPkg = Ver.ParentPkg();
1136 Dynamic<pkgCache::PkgIterator> DynOwnerPkg(OwnerPkg);
1137 pkgCache::PkgIterator Pkg;
1138 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
1139 for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
1140 {
1141 if (isImplicit && OwnerPkg == Pkg)
1142 continue;
1143 if (isArchSpecific == false && APT::Configuration::checkArchitecture(OwnerPkg.Arch()) == false)
1144 continue;
1145 if (Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags) == false)
1146 return false;
1147 }
1148 }
1149 return true;
1150}
1151 /*}}}*/
1152bool pkgCacheListParser::SameVersion(unsigned short const Hash, /*{{{*/
1153 pkgCache::VerIterator const &Ver)
1154{
1155 return Hash == Ver->Hash;
1156}
1157 /*}}}*/
1158// CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1159bool pkgCacheGenerator::SelectReleaseFile(const string &File,const string &Site,
1160 unsigned long Flags)
1161{
1162 if (File.empty() && Site.empty())
1163 {
1164 CurrentRlsFile = NULL;
1165 return true;
1166 }
1167
1168 // Get some space for the structure
1169 map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentRlsFile));
1170 if (unlikely(idxFile == 0))
1171 return false;
1172 CurrentRlsFile = Cache.RlsFileP + idxFile;
1173
1174 // Fill it in
1175 map_stringitem_t const idxFileName = WriteStringInMap(File);
1176 map_stringitem_t const idxSite = StoreString(MIXED, Site);
1177 if (unlikely(idxFileName == 0 || idxSite == 0))
1178 return false;
1179 CurrentRlsFile->FileName = idxFileName;
1180 CurrentRlsFile->Site = idxSite;
1181 CurrentRlsFile->NextFile = Cache.HeaderP->RlsFileList;
1182 CurrentRlsFile->Flags = Flags;
1183 CurrentRlsFile->ID = Cache.HeaderP->ReleaseFileCount;
1184 RlsFileName = File;
1185 Cache.HeaderP->RlsFileList = CurrentRlsFile - Cache.RlsFileP;
1186 Cache.HeaderP->ReleaseFileCount++;
1187
1188 return true;
1189}
1190 /*}}}*/
1191// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1192// ---------------------------------------------------------------------
1193/* This is used to select which file is to be associated with all newly
1194 added versions. The caller is responsible for setting the IMS fields. */
1195bool pkgCacheGenerator::SelectFile(std::string const &File,
1196 pkgIndexFile const &Index,
1197 std::string const &Architecture,
1198 std::string const &Component,
1199 unsigned long const Flags)
1200{
1201 // Get some space for the structure
1202 map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentFile));
1203 if (unlikely(idxFile == 0))
1204 return false;
1205 CurrentFile = Cache.PkgFileP + idxFile;
1206
1207 // Fill it in
1208 map_stringitem_t const idxFileName = WriteStringInMap(File);
1209 if (unlikely(idxFileName == 0))
1210 return false;
1211 CurrentFile->FileName = idxFileName;
1212 CurrentFile->NextFile = Cache.HeaderP->FileList;
1213 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
1214 map_stringitem_t const idxIndexType = StoreString(MIXED, Index.GetType()->Label);
1215 if (unlikely(idxIndexType == 0))
1216 return false;
1217 CurrentFile->IndexType = idxIndexType;
1218 if (Architecture.empty())
1219 CurrentFile->Architecture = 0;
1220 else
1221 {
1222 map_stringitem_t const arch = StoreString(pkgCacheGenerator::MIXED, Architecture);
1223 if (unlikely(arch == 0))
1224 return false;
1225 CurrentFile->Architecture = arch;
1226 }
1227 map_stringitem_t const component = StoreString(pkgCacheGenerator::MIXED, Component);
1228 if (unlikely(component == 0))
1229 return false;
1230 CurrentFile->Component = component;
1231 CurrentFile->Flags = Flags;
1232 if (CurrentRlsFile != NULL)
1233 CurrentFile->Release = CurrentRlsFile - Cache.RlsFileP;
1234 else
1235 CurrentFile->Release = 0;
1236 PkgFileName = File;
1237 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
1238 Cache.HeaderP->PackageFileCount++;
1239
1240 if (Progress != 0)
1241 Progress->SubProgress(Index.Size());
1242 return true;
1243}
1244 /*}}}*/
1245// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1246// ---------------------------------------------------------------------
1247/* This is used to create handles to strings. Given the same text it
1248 always returns the same number */
1249map_stringitem_t pkgCacheGenerator::StoreString(enum StringType const type, const char *S,
1250 unsigned int Size)
1251{
1252 std::string const key(S, Size);
1253
1254 std::map<std::string,map_stringitem_t> * strings;
1255 switch(type) {
1256 case MIXED: strings = &strMixed; break;
1257 case PKGNAME: strings = &strPkgNames; break;
1258 case VERSIONNUMBER: strings = &strVersions; break;
1259 case SECTION: strings = &strSections; break;
1260 default: _error->Fatal("Unknown enum type used for string storage of '%s'", key.c_str()); return 0;
1261 }
1262
1263 std::map<std::string,map_stringitem_t>::const_iterator const item = strings->find(key);
1264 if (item != strings->end())
1265 return item->second;
1266
1267 map_stringitem_t const idxString = WriteStringInMap(S,Size);
1268 strings->insert(std::make_pair(key, idxString));
1269 return idxString;
1270}
1271 /*}}}*/
1272// CheckValidity - Check that a cache is up-to-date /*{{{*/
1273// ---------------------------------------------------------------------
1274/* This just verifies that each file in the list of index files exists,
1275 has matching attributes with the cache and the cache does not have
1276 any extra files. */
1277static bool CheckValidity(const string &CacheFile,
1278 pkgSourceList &List,
1279 FileIterator const Start,
1280 FileIterator const End,
1281 MMap **OutMap = 0)
1282{
1283 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
1284 // No file, certainly invalid
1285 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
1286 {
1287 if (Debug == true)
1288 std::clog << "CacheFile " << CacheFile << " doesn't exist" << std::endl;
1289 return false;
1290 }
1291
1292 if (List.GetLastModifiedTime() > GetModificationTime(CacheFile))
1293 {
1294 if (Debug == true)
1295 std::clog << "sources.list is newer than the cache" << std::endl;
1296 return false;
1297 }
1298
1299 // Map it
1300 FileFd CacheF(CacheFile,FileFd::ReadOnly);
1301 std::unique_ptr<MMap> Map(new MMap(CacheF,0));
1302 pkgCache Cache(Map.get());
1303 if (_error->PendingError() == true || Map->Size() == 0)
1304 {
1305 if (Debug == true)
1306 std::clog << "Errors are pending or Map is empty() for " << CacheFile << std::endl;
1307 _error->Discard();
1308 return false;
1309 }
1310
1311 std::unique_ptr<bool[]> RlsVisited(new bool[Cache.HeaderP->ReleaseFileCount]);
1312 memset(RlsVisited.get(),0,sizeof(RlsVisited[0])*Cache.HeaderP->ReleaseFileCount);
1313 std::vector<pkgIndexFile *> Files;
1314 for (pkgSourceList::const_iterator i = List.begin(); i != List.end(); ++i)
1315 {
1316 if (Debug == true)
1317 std::clog << "Checking RlsFile " << (*i)->Describe() << ": ";
1318 pkgCache::RlsFileIterator const RlsFile = (*i)->FindInCache(Cache, true);
1319 if (RlsFile.end() == true)
1320 {
1321 if (Debug == true)
1322 std::clog << "FindInCache returned end-Pointer" << std::endl;
1323 return false;
1324 }
1325
1326 RlsVisited[RlsFile->ID] = true;
1327 if (Debug == true)
1328 std::clog << "with ID " << RlsFile->ID << " is valid" << std::endl;
1329
1330 std::vector <pkgIndexFile *> const * const Indexes = (*i)->GetIndexFiles();
1331 std::copy_if(Indexes->begin(), Indexes->end(), std::back_inserter(Files),
1332 [](pkgIndexFile const * const I) { return I->HasPackages(); });
1333 }
1334 for (unsigned I = 0; I != Cache.HeaderP->ReleaseFileCount; ++I)
1335 if (RlsVisited[I] == false)
1336 {
1337 if (Debug == true)
1338 std::clog << "RlsFile with ID" << I << " wasn't visited" << std::endl;
1339 return false;
1340 }
1341
1342 std::copy(Start, End, std::back_inserter(Files));
1343
1344 /* Now we check every index file, see if it is in the cache,
1345 verify the IMS data and check that it is on the disk too.. */
1346 std::unique_ptr<bool[]> Visited(new bool[Cache.HeaderP->PackageFileCount]);
1347 memset(Visited.get(),0,sizeof(Visited[0])*Cache.HeaderP->PackageFileCount);
1348 for (std::vector<pkgIndexFile *>::const_reverse_iterator PkgFile = Files.rbegin(); PkgFile != Files.rend(); ++PkgFile)
1349 {
1350 if (Debug == true)
1351 std::clog << "Checking PkgFile " << (*PkgFile)->Describe() << ": ";
1352 if ((*PkgFile)->Exists() == false)
1353 {
1354 if (Debug == true)
1355 std::clog << "file doesn't exist" << std::endl;
1356 continue;
1357 }
1358
1359 // FindInCache is also expected to do an IMS check.
1360 pkgCache::PkgFileIterator File = (*PkgFile)->FindInCache(Cache);
1361 if (File.end() == true)
1362 {
1363 if (Debug == true)
1364 std::clog << "FindInCache returned end-Pointer" << std::endl;
1365 return false;
1366 }
1367
1368 Visited[File->ID] = true;
1369 if (Debug == true)
1370 std::clog << "with ID " << File->ID << " is valid" << std::endl;
1371 }
1372
1373 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
1374 if (Visited[I] == false)
1375 {
1376 if (Debug == true)
1377 std::clog << "PkgFile with ID" << I << " wasn't visited" << std::endl;
1378 return false;
1379 }
1380
1381 if (_error->PendingError() == true)
1382 {
1383 if (Debug == true)
1384 {
1385 std::clog << "Validity failed because of pending errors:" << std::endl;
1386 _error->DumpErrors();
1387 }
1388 _error->Discard();
1389 return false;
1390 }
1391
1392 if (OutMap != 0)
1393 *OutMap = Map.release();
1394 return true;
1395}
1396 /*}}}*/
1397// ComputeSize - Compute the total size of a bunch of files /*{{{*/
1398// ---------------------------------------------------------------------
1399/* Size is kind of an abstract notion that is only used for the progress
1400 meter */
1401static map_filesize_t ComputeSize(pkgSourceList const * const List, FileIterator Start,FileIterator End)
1402{
1403 map_filesize_t TotalSize = 0;
1404 if (List != NULL)
1405 {
1406 for (pkgSourceList::const_iterator i = List->begin(); i != List->end(); ++i)
1407 {
1408 std::vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1409 for (std::vector<pkgIndexFile *>::const_iterator j = Indexes->begin(); j != Indexes->end(); ++j)
1410 if ((*j)->HasPackages() == true)
1411 TotalSize += (*j)->Size();
1412 }
1413 }
1414
1415 for (; Start < End; ++Start)
1416 {
1417 if ((*Start)->HasPackages() == false)
1418 continue;
1419 TotalSize += (*Start)->Size();
1420 }
1421 return TotalSize;
1422}
1423 /*}}}*/
1424// BuildCache - Merge the list of index files into the cache /*{{{*/
1425static bool BuildCache(pkgCacheGenerator &Gen,
1426 OpProgress * const Progress,
1427 map_filesize_t &CurrentSize,map_filesize_t TotalSize,
1428 pkgSourceList const * const List,
1429 FileIterator const Start, FileIterator const End)
1430{
1431 std::vector<pkgIndexFile *> Files;
1432 bool mergeFailure = false;
1433
1434 auto const indexFileMerge = [&](pkgIndexFile * const I) {
1435 if (I->HasPackages() == false || mergeFailure)
1436 return;
1437
1438 if (I->Exists() == false)
1439 return;
1440
1441 if (I->FindInCache(Gen.GetCache()).end() == false)
1442 {
1443 _error->Warning("Duplicate sources.list entry %s",
1444 I->Describe().c_str());
1445 return;
1446 }
1447
1448 map_filesize_t const Size = I->Size();
1449 if (Progress != NULL)
1450 Progress->OverallProgress(CurrentSize, TotalSize, Size, _("Reading package lists"));
1451 CurrentSize += Size;
1452
1453 if (I->Merge(Gen,Progress) == false)
1454 mergeFailure = true;
1455 };
1456
1457 if (List != NULL)
1458 {
1459 for (pkgSourceList::const_iterator i = List->begin(); i != List->end(); ++i)
1460 {
1461 if ((*i)->FindInCache(Gen.GetCache(), false).end() == false)
1462 {
1463 _error->Warning("Duplicate sources.list entry %s",
1464 (*i)->Describe().c_str());
1465 continue;
1466 }
1467
1468 if ((*i)->Merge(Gen, Progress) == false)
1469 return false;
1470
1471 std::vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1472 if (Indexes != NULL)
1473 std::for_each(Indexes->begin(), Indexes->end(), indexFileMerge);
1474 if (mergeFailure)
1475 return false;
1476 }
1477 }
1478
1479 if (Start != End)
1480 {
1481 Gen.SelectReleaseFile("", "");
1482 std::for_each(Start, End, indexFileMerge);
1483 if (mergeFailure)
1484 return false;
1485 }
1486 return true;
1487}
1488 /*}}}*/
1489// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1490// ---------------------------------------------------------------------
1491/* This makes sure that the status cache (the cache that has all
1492 index files from the sources list and all local ones) is ready
1493 to be mmaped. If OutMap is not zero then a MMap object representing
1494 the cache will be stored there. This is pretty much mandetory if you
1495 are using AllowMem. AllowMem lets the function be run as non-root
1496 where it builds the cache 'fast' into a memory buffer. */
1497static DynamicMMap* CreateDynamicMMap(FileFd * const CacheF, unsigned long Flags)
1498{
1499 map_filesize_t const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1500 map_filesize_t const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1501 map_filesize_t const MapLimit = _config->FindI("APT::Cache-Limit", 0);
1502 Flags |= MMap::Moveable;
1503 if (_config->FindB("APT::Cache-Fallback", false) == true)
1504 Flags |= MMap::Fallback;
1505 if (CacheF != NULL)
1506 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1507 else
1508 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1509}
1510static bool writeBackMMapToFile(pkgCacheGenerator * const Gen, DynamicMMap * const Map,
1511 std::string const &FileName)
1512{
1513 FileFd SCacheF(FileName, FileFd::WriteAtomic);
1514 if (_error->PendingError() == true)
1515 return false;
1516
1517 fchmod(SCacheF.Fd(),0644);
1518
1519 // Write out the main data
1520 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1521 return _error->Error(_("IO Error saving source cache"));
1522 SCacheF.Sync();
1523
1524 // Write out the proper header
1525 Gen->GetCache().HeaderP->Dirty = false;
1526 if (SCacheF.Seek(0) == false ||
1527 SCacheF.Write(Map->Data(),sizeof(*Gen->GetCache().HeaderP)) == false)
1528 return _error->Error(_("IO Error saving source cache"));
1529 Gen->GetCache().HeaderP->Dirty = true;
1530 SCacheF.Sync();
1531 return true;
1532}
1533static bool loadBackMMapFromFile(std::unique_ptr<pkgCacheGenerator> &Gen,
1534 std::unique_ptr<DynamicMMap> &Map, OpProgress * const Progress, std::string const &FileName)
1535{
1536 Map.reset(CreateDynamicMMap(NULL, 0));
1537 FileFd CacheF(FileName, FileFd::ReadOnly);
1538 map_pointer_t const alloc = Map->RawAllocate(CacheF.Size());
1539 if ((alloc == 0 && _error->PendingError())
1540 || CacheF.Read((unsigned char *)Map->Data() + alloc,
1541 CacheF.Size()) == false)
1542 return false;
1543 Gen.reset(new pkgCacheGenerator(Map.get(),Progress));
1544 return true;
1545}
1546APT_DEPRECATED bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
1547 MMap **OutMap, bool AllowMem)
1548 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1549bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
1550 MMap **OutMap,bool)
1551{
1552 // FIXME: deprecate the ignored AllowMem parameter
1553 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
1554
1555 std::vector<pkgIndexFile *> Files;
1556 if (_system->AddStatusFiles(Files) == false)
1557 return false;
1558
1559 // Decide if we can write to the files..
1560 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1561 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1562
1563 // ensure the cache directory exists
1564 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1565 {
1566 string dir = _config->FindDir("Dir::Cache");
1567 size_t const len = dir.size();
1568 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1569 dir = dir.substr(0, len - 5);
1570 if (CacheFile.empty() == false)
1571 CreateDirectory(dir, flNotFile(CacheFile));
1572 if (SrcCacheFile.empty() == false)
1573 CreateDirectory(dir, flNotFile(SrcCacheFile));
1574 }
1575
1576 if (Progress != NULL)
1577 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1578
1579 bool pkgcache_fine = false;
1580 bool srcpkgcache_fine = false;
1581 bool volatile_fine = List.GetVolatileFiles().empty();
1582
1583 if (CheckValidity(CacheFile, List, Files.begin(), Files.end(), volatile_fine ? OutMap : NULL) == true)
1584 {
1585 if (Debug == true)
1586 std::clog << "pkgcache.bin is valid - no need to build any cache" << std::endl;
1587 pkgcache_fine = true;
1588 srcpkgcache_fine = true;
1589 }
1590 if (pkgcache_fine == false)
1591 {
1592 if (CheckValidity(SrcCacheFile, List, Files.end(), Files.end()) == true)
1593 {
1594 if (Debug == true)
1595 std::clog << "srcpkgcache.bin is valid - it can be reused" << std::endl;
1596 srcpkgcache_fine = true;
1597 }
1598 }
1599
1600 if (volatile_fine == true && srcpkgcache_fine == true && pkgcache_fine == true)
1601 {
1602 if (Progress != NULL)
1603 Progress->OverallProgress(1,1,1,_("Reading package lists"));
1604 return true;
1605 }
1606
1607 bool Writeable = false;
1608 if (srcpkgcache_fine == false || pkgcache_fine == false)
1609 {
1610 if (CacheFile.empty() == false)
1611 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1612 else if (SrcCacheFile.empty() == false)
1613 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
1614
1615 if (Debug == true)
1616 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1617 }
1618
1619 // At this point we know we need to construct something, so get storage ready
1620 std::unique_ptr<DynamicMMap> Map(CreateDynamicMMap(NULL, 0));
1621 if (Debug == true)
1622 std::clog << "Open memory Map (not filebased)" << std::endl;
1623
1624 std::unique_ptr<pkgCacheGenerator> Gen{nullptr};
1625 map_filesize_t CurrentSize = 0;
1626 std::vector<pkgIndexFile*> VolatileFiles = List.GetVolatileFiles();
1627 map_filesize_t TotalSize = ComputeSize(NULL, VolatileFiles.begin(), VolatileFiles.end());
1628 if (srcpkgcache_fine == true && pkgcache_fine == false)
1629 {
1630 if (Debug == true)
1631 std::clog << "srcpkgcache.bin was valid - populate MMap with it" << std::endl;
1632 if (loadBackMMapFromFile(Gen, Map, Progress, SrcCacheFile) == false)
1633 return false;
1634 srcpkgcache_fine = true;
1635 TotalSize += ComputeSize(NULL, Files.begin(), Files.end());
1636 }
1637 else if (srcpkgcache_fine == false)
1638 {
1639 if (Debug == true)
1640 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
1641 Gen.reset(new pkgCacheGenerator(Map.get(),Progress));
1642
1643 TotalSize += ComputeSize(&List, Files.begin(),Files.end());
1644 if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, &List,
1645 Files.end(),Files.end()) == false)
1646 return false;
1647
1648 if (Writeable == true && SrcCacheFile.empty() == false)
1649 if (writeBackMMapToFile(Gen.get(), Map.get(), SrcCacheFile) == false)
1650 return false;
1651 }
1652
1653 if (pkgcache_fine == false)
1654 {
1655 if (Debug == true)
1656 std::clog << "Building status cache in pkgcache.bin now" << std::endl;
1657 if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, NULL,
1658 Files.begin(), Files.end()) == false)
1659 return false;
1660
1661 if (Writeable == true && CacheFile.empty() == false)
1662 if (writeBackMMapToFile(Gen.get(), Map.get(), CacheFile) == false)
1663 return false;
1664 }
1665
1666 if (Debug == true)
1667 std::clog << "Caches done. Now bring in the volatile files (if any)" << std::endl;
1668
1669 if (volatile_fine == false)
1670 {
1671 if (Gen == nullptr)
1672 {
1673 if (Debug == true)
1674 std::clog << "Populate new MMap with cachefile contents" << std::endl;
1675 if (loadBackMMapFromFile(Gen, Map, Progress, CacheFile) == false)
1676 return false;
1677 }
1678
1679 Files = List.GetVolatileFiles();
1680 if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, NULL,
1681 Files.begin(), Files.end()) == false)
1682 return false;
1683 }
1684
1685 if (OutMap != nullptr)
1686 *OutMap = Map.release();
1687
1688 if (Debug == true)
1689 std::clog << "Everything is ready for shipping" << std::endl;
1690 return true;
1691}
1692 /*}}}*/
1693// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1694// ---------------------------------------------------------------------
1695/* */
1696APT_DEPRECATED bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
1697 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1698bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
1699{
1700 std::vector<pkgIndexFile *> Files;
1701 if (_system->AddStatusFiles(Files) == false)
1702 return false;
1703
1704 std::unique_ptr<DynamicMMap> Map(CreateDynamicMMap(NULL, 0));
1705 map_filesize_t CurrentSize = 0;
1706 map_filesize_t TotalSize = 0;
1707
1708 TotalSize = ComputeSize(NULL, Files.begin(), Files.end());
1709
1710 // Build the status cache
1711 if (Progress != NULL)
1712 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1713 pkgCacheGenerator Gen(Map.get(),Progress);
1714 if (_error->PendingError() == true)
1715 return false;
1716 if (BuildCache(Gen,Progress,CurrentSize,TotalSize, NULL,
1717 Files.begin(), Files.end()) == false)
1718 return false;
1719
1720 if (_error->PendingError() == true)
1721 return false;
1722 *OutMap = Map.release();
1723
1724 return true;
1725}
1726 /*}}}*/
1727// IsDuplicateDescription /*{{{*/
1728static bool IsDuplicateDescription(pkgCache::DescIterator Desc,
1729 MD5SumValue const &CurMd5, std::string const &CurLang)
1730{
1731 // Descriptions in the same link-list have all the same md5
1732 if (Desc.end() == true || MD5SumValue(Desc.md5()) != CurMd5)
1733 return false;
1734 for (; Desc.end() == false; ++Desc)
1735 if (Desc.LanguageCode() == CurLang)
1736 return true;
1737 return false;
1738}
1739 /*}}}*/
1740
1741pkgCacheListParser::pkgCacheListParser() : Owner(NULL), OldDepLast(NULL), d(NULL) {}
1742pkgCacheListParser::~pkgCacheListParser() {}