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