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