]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
delay build-dep variable initialisation until needed
[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 {
ecc138f8
DK
575 // but first get implicit provides done
576 if (APT::Configuration::checkArchitecture(Pkg.Arch()) == true)
577 {
578 pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false); // native or any foreign pkg will do
a6deb7a0
JAK
579 if (M.end() == false) {
580 pkgCache::PrvIterator Prv;
581 Dynamic<pkgCache::PrvIterator> DynPrv(Prv);
582 for (Prv = M.ProvidesList(); Prv.end() == false; ++Prv)
ecc138f8
DK
583 {
584 if ((Prv->Flags & pkgCache::Flag::ArchSpecific) != 0)
585 continue;
586 pkgCache::VerIterator Ver = Prv.OwnerVer();
a6deb7a0 587 Dynamic<pkgCache::VerIterator> DynVer(Ver);
ecc138f8
DK
588 if ((Ver->MultiArch & pkgCache::Version::Allowed) == pkgCache::Version::Allowed ||
589 ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign &&
590 (Prv->Flags & pkgCache::Flag::MultiArchImplicit) == 0))
591 if (NewProvides(Ver, Pkg, Prv->ProvideVersion, Prv->Flags) == false)
592 return false;
593 }
a6deb7a0
JAK
594 }
595
596
597 pkgCache::PkgIterator P;
598 pkgCache::VerIterator Ver;
599 Dynamic<pkgCache::PkgIterator> DynP(P);
600 Dynamic<pkgCache::VerIterator> DynVer(Ver);
ecc138f8 601
a6deb7a0
JAK
602 for (P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
603 for (Ver = P.VersionList(); Ver.end() == false; ++Ver)
ecc138f8
DK
604 if ((Ver->MultiArch & pkgCache::Version::Foreign) == pkgCache::Version::Foreign)
605 if (NewProvides(Ver, Pkg, Ver->VerStr, pkgCache::Flag::MultiArchImplicit) == false)
606 return false;
607 }
bb0f6a34
DK
608 // and negative dependencies, don't forget negative dependencies
609 {
610 pkgCache::PkgIterator const M = Grp.FindPreferredPkg(false);
05c001c8
JAK
611 if (M.end() == false) {
612 pkgCache::DepIterator Dep;
613 Dynamic<pkgCache::DepIterator> DynDep(Dep);
614 for (Dep = M.RevDependsList(); Dep.end() == false; ++Dep)
bb0f6a34
DK
615 {
616 if ((Dep->CompareOp & (pkgCache::Dep::ArchSpecific | pkgCache::Dep::MultiArchImplicit)) != 0)
617 continue;
618 if (Dep->Type != pkgCache::Dep::DpkgBreaks && Dep->Type != pkgCache::Dep::Conflicts &&
619 Dep->Type != pkgCache::Dep::Replaces)
620 continue;
621 pkgCache::VerIterator Ver = Dep.ParentVer();
05c001c8 622 Dynamic<pkgCache::VerIterator> DynVer(Ver);
bb0f6a34
DK
623 map_pointer_t * unused = NULL;
624 if (NewDepends(Pkg, Ver, Dep->Version, Dep->CompareOp, Dep->Type, unused) == false)
625 return false;
626 }
05c001c8 627 }
bb0f6a34 628 }
ecc138f8 629
c408e01e
DK
630 // this package is the new last package
631 pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
32ab4bd0
DK
632 Pkg->NextPackage = LastPkg->NextPackage;
633 LastPkg->NextPackage = Package;
c408e01e
DK
634 }
635 Grp->LastPackage = Package;
3addaba1
DK
636
637 // lazy-create foo (of amd64) provides foo:amd64 at the time we first need it
638 if (Arch == "any")
639 {
640 size_t const found = Name.find(':');
eff0c22e
JAK
641 StringView const NameA = Name.substr(0, found);
642 StringView const ArchA = Name.substr(found + 1);
3addaba1
DK
643 pkgCache::PkgIterator PkgA = Cache.FindPkg(NameA, ArchA);
644 if (PkgA.end() == false)
645 {
646 Dynamic<pkgCache::PkgIterator> DynPkgA(PkgA);
647 pkgCache::PrvIterator Prv = PkgA.ProvidesList();
648 for (; Prv.end() == false; ++Prv)
649 {
650 if (Prv.IsMultiArchImplicit())
651 continue;
652 pkgCache::VerIterator V = Prv.OwnerVer();
653 if (ArchA != V.ParentPkg().Arch())
654 continue;
655 if (NewProvides(V, Pkg, V->VerStr, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
656 return false;
657 }
658 pkgCache::VerIterator V = PkgA.VersionList();
659 Dynamic<pkgCache::VerIterator> DynV(V);
660 for (; V.end() == false; ++V)
661 {
662 if (NewProvides(V, Pkg, V->VerStr, pkgCache::Flag::MultiArchImplicit | pkgCache::Flag::ArchSpecific) == false)
663 return false;
664 }
665 }
666 }
578bfd0a
AL
667 return true;
668}
5a8e963b
DK
669 /*}}}*/
670// CacheGenerator::AddImplicitDepends /*{{{*/
671bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator &G,
672 pkgCache::PkgIterator &P,
673 pkgCache::VerIterator &V)
674{
675 // copy P.Arch() into a string here as a cache remap
676 // in NewDepends() later may alter the pointer location
677 string Arch = P.Arch() == NULL ? "" : P.Arch();
4ad8619b 678 map_pointer_t *OldDepLast = NULL;
5a8e963b
DK
679 /* MultiArch handling introduces a lot of implicit Dependencies:
680 - MultiArch: same → Co-Installable if they have the same version
681 - All others conflict with all other group members */
682 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
683 pkgCache::PkgIterator D = G.PackageList();
684 Dynamic<pkgCache::PkgIterator> DynD(D);
4ad8619b 685 map_stringitem_t const VerStrIdx = V->VerStr;
5a8e963b
DK
686 for (; D.end() != true; D = G.NextPkg(D))
687 {
688 if (Arch == D.Arch() || D->VersionList == 0)
689 continue;
690 /* We allow only one installed arch at the time
691 per group, therefore each group member conflicts
692 with all other group members */
693 if (coInstall == true)
694 {
695 // Replaces: ${self}:other ( << ${binary:Version})
9c44383f 696 NewDepends(D, V, VerStrIdx,
8c7af4d4 697 pkgCache::Dep::Less | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Replaces,
5a8e963b
DK
698 OldDepLast);
699 // Breaks: ${self}:other (!= ${binary:Version})
9c44383f 700 NewDepends(D, V, VerStrIdx,
8c7af4d4 701 pkgCache::Dep::NotEquals | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::DpkgBreaks,
5a8e963b
DK
702 OldDepLast);
703 } else {
704 // Conflicts: ${self}:other
9c44383f 705 NewDepends(D, V, 0,
8c7af4d4 706 pkgCache::Dep::NoOp | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Conflicts,
5a8e963b
DK
707 OldDepLast);
708 }
709 }
710 return true;
711}
712bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator &V,
713 pkgCache::PkgIterator &D)
714{
715 /* MultiArch handling introduces a lot of implicit Dependencies:
716 - MultiArch: same → Co-Installable if they have the same version
717 - All others conflict with all other group members */
4ad8619b 718 map_pointer_t *OldDepLast = NULL;
5a8e963b
DK
719 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
720 if (coInstall == true)
721 {
4ad8619b 722 map_stringitem_t const VerStrIdx = V->VerStr;
5a8e963b 723 // Replaces: ${self}:other ( << ${binary:Version})
9c44383f 724 NewDepends(D, V, VerStrIdx,
8c7af4d4 725 pkgCache::Dep::Less | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Replaces,
5a8e963b
DK
726 OldDepLast);
727 // Breaks: ${self}:other (!= ${binary:Version})
9c44383f 728 NewDepends(D, V, VerStrIdx,
8c7af4d4 729 pkgCache::Dep::NotEquals | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::DpkgBreaks,
5a8e963b
DK
730 OldDepLast);
731 } else {
732 // Conflicts: ${self}:other
9c44383f 733 NewDepends(D, V, 0,
8c7af4d4 734 pkgCache::Dep::NoOp | pkgCache::Dep::MultiArchImplicit, pkgCache::Dep::Conflicts,
5a8e963b
DK
735 OldDepLast);
736 }
737 return true;
738}
739
578bfd0a
AL
740 /*}}}*/
741// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
742// ---------------------------------------------------------------------
743/* */
f55a958f 744bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
578bfd0a
AL
745 ListParser &List)
746{
ddc1d8d0
AL
747 if (CurrentFile == 0)
748 return true;
749
dcb79bae 750 // Get a structure
4ad8619b 751 map_pointer_t const VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
dcb79bae 752 if (VerFile == 0)
ac2c559b 753 return false;
dcb79bae
AL
754
755 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
756 VF->File = CurrentFile - Cache.PkgFileP;
03e39e59
AL
757
758 // Link it to the end of the list
4ad8619b 759 map_pointer_t *Last = &Ver->FileList;
f7f0d6c7 760 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; ++V)
03e39e59
AL
761 Last = &V->NextFile;
762 VF->NextFile = *Last;
763 *Last = VF.Index();
764
dcb79bae
AL
765 VF->Offset = List.Offset();
766 VF->Size = List.Size();
ad00ae81
AL
767 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
768 Cache.HeaderP->MaxVerFileSize = VF->Size;
a7e66b17
AL
769 Cache.HeaderP->VerFileCount++;
770
f55a958f 771 return true;
578bfd0a
AL
772}
773 /*}}}*/
774// CacheGenerator::NewVersion - Create a new Version /*{{{*/
775// ---------------------------------------------------------------------
f55a958f 776/* This puts a version structure in the linked list */
4ad8619b 777map_pointer_t pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
171c75f1 778 const string &VerStr,
4ad8619b
DK
779 map_pointer_t const ParentPkg,
780 unsigned short const Hash,
781 map_pointer_t const Next)
578bfd0a 782{
f55a958f 783 // Get a structure
4ad8619b 784 map_pointer_t const Version = AllocateInMap(sizeof(pkgCache::Version));
f55a958f 785 if (Version == 0)
0149949b 786 return 0;
f55a958f
AL
787
788 // Fill it in
789 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
dfe45e1f 790 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
f55a958f 791 Ver->NextVer = Next;
885594fc
DK
792 Ver->ParentPkg = ParentPkg;
793 Ver->Hash = Hash;
f55a958f 794 Ver->ID = Cache.HeaderP->VersionCount++;
885594fc
DK
795
796 // try to find the version string in the group for reuse
797 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
798 pkgCache::GrpIterator Grp = Pkg.Group();
799 if (Pkg.end() == false && Grp.end() == false)
800 {
801 for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
802 {
803 if (Pkg == P)
804 continue;
805 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
806 {
807 int const cmp = strcmp(V.VerStr(), VerStr.c_str());
808 if (cmp == 0)
809 {
810 Ver->VerStr = V->VerStr;
811 return Version;
812 }
813 else if (cmp < 0)
814 break;
815 }
816 }
817 }
818 // haven't found the version string, so create
30b45652 819 map_stringitem_t const idxVerStr = StoreString(VERSIONNUMBER, VerStr);
a9fe5928 820 if (unlikely(idxVerStr == 0))
0149949b 821 return 0;
a9fe5928 822 Ver->VerStr = idxVerStr;
0149949b 823 return Version;
578bfd0a
AL
824}
825 /*}}}*/
a52f938b
OS
826// CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
827// ---------------------------------------------------------------------
828/* */
829bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
830 ListParser &List)
831{
832 if (CurrentFile == 0)
833 return true;
834
835 // Get a structure
4ad8619b 836 map_pointer_t const DescFile = AllocateInMap(sizeof(pkgCache::DescFile));
a52f938b 837 if (DescFile == 0)
c5f44afc 838 return false;
770c32ec 839
a52f938b
OS
840 pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
841 DF->File = CurrentFile - Cache.PkgFileP;
770c32ec 842
a52f938b 843 // Link it to the end of the list
4ad8619b 844 map_pointer_t *Last = &Desc->FileList;
f7f0d6c7 845 for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; ++D)
a52f938b 846 Last = &D->NextFile;
770c32ec 847
a52f938b
OS
848 DF->NextFile = *Last;
849 *Last = DF.Index();
850
851 DF->Offset = List.Offset();
852 DF->Size = List.Size();
853 if (Cache.HeaderP->MaxDescFileSize < DF->Size)
854 Cache.HeaderP->MaxDescFileSize = DF->Size;
855 Cache.HeaderP->DescFileCount++;
856
857 return true;
858}
859 /*}}}*/
860// CacheGenerator::NewDescription - Create a new Description /*{{{*/
861// ---------------------------------------------------------------------
862/* This puts a description structure in the linked list */
4ad8619b 863map_pointer_t pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
a65e22c6
DK
864 const string &Lang,
865 const MD5SumValue &md5sum,
4ad8619b 866 map_stringitem_t const idxmd5str)
a52f938b
OS
867{
868 // Get a structure
4ad8619b 869 map_pointer_t const Description = AllocateInMap(sizeof(pkgCache::Description));
a52f938b
OS
870 if (Description == 0)
871 return 0;
872
873 // Fill it in
874 Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
a52f938b 875 Desc->ID = Cache.HeaderP->DescriptionCount++;
78a5476f 876 map_stringitem_t const idxlanguage_code = StoreString(MIXED, Lang);
a65e22c6 877 if (unlikely(idxlanguage_code == 0))
c5f44afc 878 return 0;
a9fe5928 879 Desc->language_code = idxlanguage_code;
a65e22c6
DK
880
881 if (idxmd5str != 0)
882 Desc->md5sum = idxmd5str;
883 else
884 {
4ad8619b 885 map_stringitem_t const idxmd5sum = WriteStringInMap(md5sum.Value());
a65e22c6
DK
886 if (unlikely(idxmd5sum == 0))
887 return 0;
888 Desc->md5sum = idxmd5sum;
889 }
a52f938b
OS
890
891 return Description;
892}
893 /*}}}*/
25396fb0 894// CacheGenerator::NewDepends - Create a dependency element /*{{{*/
dcb79bae
AL
895// ---------------------------------------------------------------------
896/* This creates a dependency element in the tree. It is linked to the
897 version and to the package that it is pointing to. */
9c44383f
DK
898bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
899 pkgCache::VerIterator &Ver,
4ad8619b 900 map_pointer_t const Version,
8c7af4d4
DK
901 uint8_t const Op,
902 uint8_t const Type,
4ad8619b 903 map_pointer_t* &OldDepLast)
dcb79bae 904{
a9fe5928 905 void const * const oldMap = Map.Data();
dcb79bae 906 // Get a structure
4ad8619b 907 map_pointer_t const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
5bf15716 908 if (unlikely(Dependency == 0))
dcb79bae 909 return false;
9c44383f 910
71c9e95b
DK
911 bool isDuplicate = false;
912 map_pointer_t DependencyData = 0;
b291aa59
DK
913 map_pointer_t PreviousData = 0;
914 if (Pkg->RevDepends != 0)
71c9e95b 915 {
b291aa59
DK
916 pkgCache::Dependency const * const L = Cache.DepP + Pkg->RevDepends;
917 DependencyData = L->DependencyData;
918 do {
919 pkgCache::DependencyData const * const D = Cache.DepDataP + DependencyData;
920 if (Version > D->Version)
921 break;
922 if (D->Version == Version && D->Type == Type && D->CompareOp == Op)
923 {
924 isDuplicate = true;
925 break;
926 }
927 PreviousData = DependencyData;
928 DependencyData = D->NextData;
929 } while (DependencyData != 0);
71c9e95b
DK
930 }
931
932 if (isDuplicate == false)
933 {
71c9e95b
DK
934 DependencyData = AllocateInMap(sizeof(pkgCache::DependencyData));
935 if (unlikely(DependencyData == 0))
936 return false;
71c9e95b 937 }
5bf15716 938
71c9e95b
DK
939 pkgCache::Dependency * Link = Cache.DepP + Dependency;
940 Link->ParentVer = Ver.Index();
941 Link->DependencyData = DependencyData;
942 Link->ID = Cache.HeaderP->DependsCount++;
943
944 pkgCache::DepIterator Dep(Cache, Link);
71c9e95b
DK
945 if (isDuplicate == false)
946 {
947 Dep->Type = Type;
948 Dep->CompareOp = Op;
949 Dep->Version = Version;
950 Dep->Package = Pkg.Index();
951 ++Cache.HeaderP->DependsDataCount;
b291aa59
DK
952 if (PreviousData != 0)
953 {
954 pkgCache::DependencyData * const D = Cache.DepDataP + PreviousData;
955 Dep->NextData = D->NextData;
956 D->NextData = DependencyData;
957 }
958 else if (Pkg->RevDepends != 0)
959 {
960 pkgCache::Dependency const * const D = Cache.DepP + Pkg->RevDepends;
961 Dep->NextData = D->DependencyData;
962 }
963 }
964
965 if (isDuplicate == true || PreviousData != 0)
966 {
967 pkgCache::Dependency * const L = Cache.DepP + Pkg->RevDepends;
968 Link->NextRevDepends = L->NextRevDepends;
969 L->NextRevDepends = Dependency;
71c9e95b
DK
970 }
971 else
972 {
b291aa59
DK
973 Link->NextRevDepends = Pkg->RevDepends;
974 Pkg->RevDepends = Dependency;
71c9e95b 975 }
25396fb0 976
b291aa59 977
25396fb0
DK
978 // Do we know where to link the Dependency to?
979 if (OldDepLast == NULL)
c1a22377 980 {
f9eec0e7 981 OldDepLast = &Ver->DependsList;
f7f0d6c7 982 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
f9eec0e7 983 OldDepLast = &D->NextDepends;
a9fe5928 984 } else if (oldMap != Map.Data())
4ad8619b 985 OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
45415543 986
f9eec0e7 987 Dep->NextDepends = *OldDepLast;
71c9e95b 988 *OldDepLast = Dependency;
f9eec0e7 989 OldDepLast = &Dep->NextDepends;
dcb79bae
AL
990 return true;
991}
992 /*}}}*/
25396fb0
DK
993// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
994// ---------------------------------------------------------------------
995/* This creates a Group and the Package to link this dependency to if
996 needed and handles also the caching of the old endpoint */
c9443c01 997bool pkgCacheListParser::NewDepends(pkgCache::VerIterator &Ver,
eff0c22e
JAK
998 StringView PackageName,
999 StringView Arch,
1000 StringView Version,
8c7af4d4
DK
1001 uint8_t const Op,
1002 uint8_t const Type)
25396fb0
DK
1003{
1004 pkgCache::GrpIterator Grp;
a9fe5928 1005 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
25396fb0
DK
1006 if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
1007 return false;
1008
bb0f6a34
DK
1009 map_stringitem_t idxVersion = 0;
1010 if (Version.empty() == false)
1011 {
1012 int const CmpOp = Op & 0x0F;
1013 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
57590d3c 1014 if (CmpOp == pkgCache::Dep::Equals && Version == Ver.VerStr())
bb0f6a34
DK
1015 idxVersion = Ver->VerStr;
1016
1017 if (idxVersion == 0)
1018 {
dd592790 1019 idxVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version);
bb0f6a34
DK
1020 if (unlikely(idxVersion == 0))
1021 return false;
1022 }
25396fb0
DK
1023 }
1024
bb0f6a34
DK
1025 bool const isNegative = (Type == pkgCache::Dep::DpkgBreaks ||
1026 Type == pkgCache::Dep::Conflicts ||
1027 Type == pkgCache::Dep::Replaces);
1028
1029 pkgCache::PkgIterator Pkg;
1030 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
1031 if (isNegative == false || (Op & pkgCache::Dep::ArchSpecific) == pkgCache::Dep::ArchSpecific || Grp->FirstPackage == 0)
1032 {
1033 // Locate the target package
1034 Pkg = Grp.FindPkg(Arch);
1035 if (Pkg.end() == true) {
1036 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
1037 return false;
1038 }
1039
1040 /* Caching the old end point speeds up generation substantially */
1041 if (OldDepVer != Ver) {
1042 OldDepLast = NULL;
1043 OldDepVer = Ver;
1044 }
1045
1046 return Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast);
1047 }
1048 else
1049 {
1050 /* Caching the old end point speeds up generation substantially */
1051 if (OldDepVer != Ver) {
1052 OldDepLast = NULL;
1053 OldDepVer = Ver;
1054 }
1055
1056 for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
1057 {
1058 if (Owner->NewDepends(Pkg, Ver, idxVersion, Op, Type, OldDepLast) == false)
1059 return false;
1060 }
1061 }
1062 return true;
25396fb0
DK
1063}
1064 /*}}}*/
dcb79bae 1065// ListParser::NewProvides - Create a Provides element /*{{{*/
c9443c01 1066bool pkgCacheListParser::NewProvides(pkgCache::VerIterator &Ver,
eff0c22e
JAK
1067 StringView PkgName,
1068 StringView PkgArch,
1069 StringView Version,
8c7af4d4 1070 uint8_t const Flags)
dcb79bae 1071{
ecc138f8 1072 pkgCache const &Cache = Owner->Cache;
8efa2a3b
AL
1073
1074 // We do not add self referencing provides
566046f4 1075 if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
b755de25
DK
1076 (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)) &&
1077 (Version.empty() || Version == Ver.VerStr()))
8efa2a3b 1078 return true;
ecc138f8
DK
1079
1080 // Locate the target package
1081 pkgCache::PkgIterator Pkg;
1082 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
1083 if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
1084 return false;
1085
1086 map_stringitem_t idxProvideVersion = 0;
1087 if (Version.empty() == false) {
dd592790 1088 idxProvideVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version);
ecc138f8
DK
1089 if (unlikely(idxProvideVersion == 0))
1090 return false;
1091 }
1092 return Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags);
1093}
1094bool pkgCacheGenerator::NewProvides(pkgCache::VerIterator &Ver,
1095 pkgCache::PkgIterator &Pkg,
1096 map_pointer_t const ProvideVersion,
1097 uint8_t const Flags)
1098{
dcb79bae 1099 // Get a structure
ecc138f8 1100 map_pointer_t const Provides = AllocateInMap(sizeof(pkgCache::Provides));
5bf15716 1101 if (unlikely(Provides == 0))
dcb79bae 1102 return false;
ecc138f8
DK
1103 ++Cache.HeaderP->ProvidesCount;
1104
dcb79bae
AL
1105 // Fill it in
1106 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
1107 Prv->Version = Ver.Index();
ecc138f8 1108 Prv->ProvideVersion = ProvideVersion;
8c7af4d4 1109 Prv->Flags = Flags;
dcb79bae
AL
1110 Prv->NextPkgProv = Ver->ProvidesList;
1111 Ver->ProvidesList = Prv.Index();
ecc138f8 1112
dcb79bae
AL
1113 // Link it to the package
1114 Prv->ParentPkg = Pkg.Index();
1115 Prv->NextProvides = Pkg->ProvidesList;
1116 Pkg->ProvidesList = Prv.Index();
ecc138f8
DK
1117 return true;
1118}
1119 /*}}}*/
1120// ListParser::NewProvidesAllArch - add provides for all architectures /*{{{*/
eff0c22e
JAK
1121bool pkgCacheListParser::NewProvidesAllArch(pkgCache::VerIterator &Ver, StringView Package,
1122 StringView Version, uint8_t const Flags) {
ecc138f8 1123 pkgCache &Cache = Owner->Cache;
a6deb7a0
JAK
1124 pkgCache::GrpIterator Grp = Cache.FindGrp(Package);
1125 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
1126
ecc138f8
DK
1127 if (Grp.end() == true)
1128 return NewProvides(Ver, Package, Cache.NativeArch(), Version, Flags);
1129 else
1130 {
1131 map_stringitem_t idxProvideVersion = 0;
1132 if (Version.empty() == false) {
dd592790 1133 idxProvideVersion = StoreString(pkgCacheGenerator::VERSIONNUMBER, Version);
ecc138f8
DK
1134 if (unlikely(idxProvideVersion == 0))
1135 return false;
1136 }
1137
1138 bool const isImplicit = (Flags & pkgCache::Flag::MultiArchImplicit) == pkgCache::Flag::MultiArchImplicit;
1139 bool const isArchSpecific = (Flags & pkgCache::Flag::ArchSpecific) == pkgCache::Flag::ArchSpecific;
a6deb7a0
JAK
1140 pkgCache::PkgIterator OwnerPkg = Ver.ParentPkg();
1141 Dynamic<pkgCache::PkgIterator> DynOwnerPkg(OwnerPkg);
1142 pkgCache::PkgIterator Pkg;
1143 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
1144 for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
ecc138f8
DK
1145 {
1146 if (isImplicit && OwnerPkg == Pkg)
1147 continue;
1148 if (isArchSpecific == false && APT::Configuration::checkArchitecture(OwnerPkg.Arch()) == false)
1149 continue;
1150 if (Owner->NewProvides(Ver, Pkg, idxProvideVersion, Flags) == false)
1151 return false;
1152 }
1153 }
dcb79bae
AL
1154 return true;
1155}
1156 /*}}}*/
c9443c01 1157bool pkgCacheListParser::SameVersion(unsigned short const Hash, /*{{{*/
68134bda
DK
1158 pkgCache::VerIterator const &Ver)
1159{
1160 return Hash == Ver->Hash;
1161}
1162 /*}}}*/
b07aeb1a
DK
1163// CacheGenerator::SelectReleaseFile - Select the current release file the indexes belong to /*{{{*/
1164bool pkgCacheGenerator::SelectReleaseFile(const string &File,const string &Site,
1165 unsigned long Flags)
1166{
1167 if (File.empty() && Site.empty())
1168 {
1169 CurrentRlsFile = NULL;
1170 return true;
1171 }
1172
1173 // Get some space for the structure
1174 map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentRlsFile));
1175 if (unlikely(idxFile == 0))
1176 return false;
1177 CurrentRlsFile = Cache.RlsFileP + idxFile;
1178
1179 // Fill it in
1180 map_stringitem_t const idxFileName = WriteStringInMap(File);
1181 map_stringitem_t const idxSite = StoreString(MIXED, Site);
1182 if (unlikely(idxFileName == 0 || idxSite == 0))
1183 return false;
1184 CurrentRlsFile->FileName = idxFileName;
1185 CurrentRlsFile->Site = idxSite;
1186 CurrentRlsFile->NextFile = Cache.HeaderP->RlsFileList;
1187 CurrentRlsFile->Flags = Flags;
1188 CurrentRlsFile->ID = Cache.HeaderP->ReleaseFileCount;
1189 RlsFileName = File;
1190 Cache.HeaderP->RlsFileList = CurrentRlsFile - Cache.RlsFileP;
1191 Cache.HeaderP->ReleaseFileCount++;
1192
1193 return true;
1194}
1195 /*}}}*/
578bfd0a
AL
1196// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1197// ---------------------------------------------------------------------
1198/* This is used to select which file is to be associated with all newly
b2e465d6 1199 added versions. The caller is responsible for setting the IMS fields. */
b07aeb1a
DK
1200bool pkgCacheGenerator::SelectFile(std::string const &File,
1201 pkgIndexFile const &Index,
e185d8b3 1202 std::string const &Architecture,
b07aeb1a
DK
1203 std::string const &Component,
1204 unsigned long const Flags)
578bfd0a 1205{
578bfd0a 1206 // Get some space for the structure
4ad8619b 1207 map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentFile));
a9fe5928 1208 if (unlikely(idxFile == 0))
578bfd0a 1209 return false;
a9fe5928
DK
1210 CurrentFile = Cache.PkgFileP + idxFile;
1211
578bfd0a 1212 // Fill it in
4ad8619b 1213 map_stringitem_t const idxFileName = WriteStringInMap(File);
b07aeb1a 1214 if (unlikely(idxFileName == 0))
a9fe5928
DK
1215 return false;
1216 CurrentFile->FileName = idxFileName;
578bfd0a 1217 CurrentFile->NextFile = Cache.HeaderP->FileList;
e1b74f61 1218 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
78a5476f 1219 map_stringitem_t const idxIndexType = StoreString(MIXED, Index.GetType()->Label);
a9fe5928
DK
1220 if (unlikely(idxIndexType == 0))
1221 return false;
1222 CurrentFile->IndexType = idxIndexType;
e185d8b3
DK
1223 if (Architecture.empty())
1224 CurrentFile->Architecture = 0;
1225 else
1226 {
1227 map_stringitem_t const arch = StoreString(pkgCacheGenerator::MIXED, Architecture);
1228 if (unlikely(arch == 0))
1229 return false;
1230 CurrentFile->Architecture = arch;
1231 }
b07aeb1a
DK
1232 map_stringitem_t const component = StoreString(pkgCacheGenerator::MIXED, Component);
1233 if (unlikely(component == 0))
1234 return false;
1235 CurrentFile->Component = component;
1236 CurrentFile->Flags = Flags;
1237 if (CurrentRlsFile != NULL)
1238 CurrentFile->Release = CurrentRlsFile - Cache.RlsFileP;
1239 else
1240 CurrentFile->Release = 0;
578bfd0a 1241 PkgFileName = File;
ad00ae81 1242 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
b35d2f5f 1243 Cache.HeaderP->PackageFileCount++;
b2e465d6 1244
ddc1d8d0 1245 if (Progress != 0)
b2e465d6 1246 Progress->SubProgress(Index.Size());
8efa2a3b 1247 return true;
578bfd0a
AL
1248}
1249 /*}}}*/
f55a958f
AL
1250// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1251// ---------------------------------------------------------------------
1252/* This is used to create handles to strings. Given the same text it
1253 always returns the same number */
78a5476f 1254map_stringitem_t pkgCacheGenerator::StoreString(enum StringType const type, const char *S,
f55a958f
AL
1255 unsigned int Size)
1256{
869700d8 1257 auto strings = &strMixed;
78a5476f
DK
1258 switch(type) {
1259 case MIXED: strings = &strMixed; break;
1260 case PKGNAME: strings = &strPkgNames; break;
30b45652 1261 case VERSIONNUMBER: strings = &strVersions; break;
78a5476f 1262 case SECTION: strings = &strSections; break;
869700d8 1263 default: _error->Fatal("Unknown enum type used for string storage of '%.*s'", Size, S); return 0;
f55a958f 1264 }
a9fe5928 1265
869700d8 1266 auto const item = strings->find({S, Size, nullptr, 0});
78a5476f 1267 if (item != strings->end())
869700d8 1268 return item->item;
a9fe5928 1269
78a5476f 1270 map_stringitem_t const idxString = WriteStringInMap(S,Size);
869700d8 1271 strings->insert({nullptr, Size, this, idxString});
78a5476f 1272 return idxString;
f55a958f
AL
1273}
1274 /*}}}*/
b2e465d6 1275// CheckValidity - Check that a cache is up-to-date /*{{{*/
b35d2f5f 1276// ---------------------------------------------------------------------
b2e465d6
AL
1277/* This just verifies that each file in the list of index files exists,
1278 has matching attributes with the cache and the cache does not have
1279 any extra files. */
95278287
DK
1280class APT_HIDDEN ScopedErrorRevert {
1281public:
1282 ScopedErrorRevert() { _error->PushToStack(); }
1283 ~ScopedErrorRevert() { _error->RevertToStack(); }
1284};
5465192b 1285static bool CheckValidity(const string &CacheFile,
2ec858bc 1286 pkgSourceList &List,
5465192b
DK
1287 FileIterator const Start,
1288 FileIterator const End,
f1616039
JAK
1289 MMap **OutMap = 0,
1290 pkgCache **OutCache = 0)
b35d2f5f 1291{
95278287 1292 ScopedErrorRevert ser;
c8e572e3 1293 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
b2e465d6
AL
1294 // No file, certainly invalid
1295 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
c8e572e3
MV
1296 {
1297 if (Debug == true)
5465192b 1298 std::clog << "CacheFile " << CacheFile << " doesn't exist" << std::endl;
b35d2f5f 1299 return false;
c8e572e3
MV
1300 }
1301
96d14a91 1302 if (List.GetLastModifiedTime() > GetModificationTime(CacheFile))
2ec858bc
MV
1303 {
1304 if (Debug == true)
1305 std::clog << "sources.list is newer than the cache" << std::endl;
1306 return false;
1307 }
1308
b2e465d6 1309 // Map it
b35d2f5f 1310 FileFd CacheF(CacheFile,FileFd::ReadOnly);
6c413b18 1311 std::unique_ptr<MMap> Map(new MMap(CacheF,0));
6789e01e
DK
1312 if (unlikely(Map->validData()) == false)
1313 return false;
f1616039
JAK
1314 std::unique_ptr<pkgCache> CacheP(new pkgCache(Map.get()));
1315 pkgCache &Cache = *CacheP.get();
95278287 1316 if (_error->PendingError() || Map->Size() == 0)
b35d2f5f 1317 {
c8e572e3 1318 if (Debug == true)
5465192b 1319 std::clog << "Errors are pending or Map is empty() for " << CacheFile << std::endl;
b35d2f5f
AL
1320 return false;
1321 }
b07aeb1a 1322
98cc7fd2
JAK
1323 std::unique_ptr<bool[]> RlsVisited(new bool[Cache.HeaderP->ReleaseFileCount]);
1324 memset(RlsVisited.get(),0,sizeof(RlsVisited[0])*Cache.HeaderP->ReleaseFileCount);
b07aeb1a
DK
1325 std::vector<pkgIndexFile *> Files;
1326 for (pkgSourceList::const_iterator i = List.begin(); i != List.end(); ++i)
1327 {
1328 if (Debug == true)
1329 std::clog << "Checking RlsFile " << (*i)->Describe() << ": ";
3fd89e62 1330 pkgCache::RlsFileIterator const RlsFile = (*i)->FindInCache(Cache, true);
b07aeb1a
DK
1331 if (RlsFile.end() == true)
1332 {
1333 if (Debug == true)
1334 std::clog << "FindInCache returned end-Pointer" << std::endl;
1335 return false;
1336 }
1337
1338 RlsVisited[RlsFile->ID] = true;
1339 if (Debug == true)
1340 std::clog << "with ID " << RlsFile->ID << " is valid" << std::endl;
1341
5465192b
DK
1342 std::vector <pkgIndexFile *> const * const Indexes = (*i)->GetIndexFiles();
1343 std::copy_if(Indexes->begin(), Indexes->end(), std::back_inserter(Files),
1344 [](pkgIndexFile const * const I) { return I->HasPackages(); });
b07aeb1a
DK
1345 }
1346 for (unsigned I = 0; I != Cache.HeaderP->ReleaseFileCount; ++I)
1347 if (RlsVisited[I] == false)
1348 {
1349 if (Debug == true)
1350 std::clog << "RlsFile with ID" << I << " wasn't visited" << std::endl;
1351 return false;
1352 }
1353
5465192b 1354 std::copy(Start, End, std::back_inserter(Files));
b07aeb1a 1355
b2e465d6
AL
1356 /* Now we check every index file, see if it is in the cache,
1357 verify the IMS data and check that it is on the disk too.. */
98cc7fd2
JAK
1358 std::unique_ptr<bool[]> Visited(new bool[Cache.HeaderP->PackageFileCount]);
1359 memset(Visited.get(),0,sizeof(Visited[0])*Cache.HeaderP->PackageFileCount);
b07aeb1a 1360 for (std::vector<pkgIndexFile *>::const_reverse_iterator PkgFile = Files.rbegin(); PkgFile != Files.rend(); ++PkgFile)
c8e572e3
MV
1361 {
1362 if (Debug == true)
b07aeb1a
DK
1363 std::clog << "Checking PkgFile " << (*PkgFile)->Describe() << ": ";
1364 if ((*PkgFile)->Exists() == false)
b35d2f5f 1365 {
c8e572e3
MV
1366 if (Debug == true)
1367 std::clog << "file doesn't exist" << std::endl;
b2e465d6 1368 continue;
b35d2f5f 1369 }
b2e465d6
AL
1370
1371 // FindInCache is also expected to do an IMS check.
b07aeb1a 1372 pkgCache::PkgFileIterator File = (*PkgFile)->FindInCache(Cache);
b2e465d6 1373 if (File.end() == true)
c8e572e3
MV
1374 {
1375 if (Debug == true)
1376 std::clog << "FindInCache returned end-Pointer" << std::endl;
b35d2f5f 1377 return false;
c8e572e3 1378 }
a52f938b 1379
b2e465d6 1380 Visited[File->ID] = true;
c8e572e3
MV
1381 if (Debug == true)
1382 std::clog << "with ID " << File->ID << " is valid" << std::endl;
b35d2f5f 1383 }
b07aeb1a 1384
b2e465d6
AL
1385 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
1386 if (Visited[I] == false)
c8e572e3
MV
1387 {
1388 if (Debug == true)
b07aeb1a 1389 std::clog << "PkgFile with ID" << I << " wasn't visited" << std::endl;
b2e465d6 1390 return false;
c8e572e3 1391 }
b07aeb1a 1392
b35d2f5f
AL
1393 if (_error->PendingError() == true)
1394 {
c8e572e3
MV
1395 if (Debug == true)
1396 {
1397 std::clog << "Validity failed because of pending errors:" << std::endl;
95278287 1398 _error->DumpErrors(std::clog, GlobalError::DEBUG, false);
c8e572e3 1399 }
b35d2f5f
AL
1400 return false;
1401 }
95278287 1402
b2e465d6 1403 if (OutMap != 0)
6c413b18 1404 *OutMap = Map.release();
f1616039
JAK
1405 if (OutCache != 0)
1406 *OutCache = CacheP.release();
b35d2f5f
AL
1407 return true;
1408}
1409 /*}}}*/
b2e465d6 1410// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 1411// ---------------------------------------------------------------------
b2e465d6
AL
1412/* Size is kind of an abstract notion that is only used for the progress
1413 meter */
b07aeb1a 1414static map_filesize_t ComputeSize(pkgSourceList const * const List, FileIterator Start,FileIterator End)
b35d2f5f 1415{
4ad8619b 1416 map_filesize_t TotalSize = 0;
b07aeb1a
DK
1417 if (List != NULL)
1418 {
1419 for (pkgSourceList::const_iterator i = List->begin(); i != List->end(); ++i)
1420 {
1421 std::vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1422 for (std::vector<pkgIndexFile *>::const_iterator j = Indexes->begin(); j != Indexes->end(); ++j)
1423 if ((*j)->HasPackages() == true)
1424 TotalSize += (*j)->Size();
1425 }
1426 }
1427
ef74268b 1428 for (; Start < End; ++Start)
b35d2f5f 1429 {
b2e465d6 1430 if ((*Start)->HasPackages() == false)
ef74268b 1431 continue;
b2e465d6 1432 TotalSize += (*Start)->Size();
b35d2f5f 1433 }
b2e465d6 1434 return TotalSize;
2d11135a
AL
1435}
1436 /*}}}*/
b2e465d6 1437// BuildCache - Merge the list of index files into the cache /*{{{*/
b2e465d6 1438static bool BuildCache(pkgCacheGenerator &Gen,
5465192b 1439 OpProgress * const Progress,
4ad8619b 1440 map_filesize_t &CurrentSize,map_filesize_t TotalSize,
b07aeb1a 1441 pkgSourceList const * const List,
5465192b 1442 FileIterator const Start, FileIterator const End)
2d11135a 1443{
5465192b
DK
1444 bool mergeFailure = false;
1445
1446 auto const indexFileMerge = [&](pkgIndexFile * const I) {
5465192b
DK
1447 if (I->HasPackages() == false || mergeFailure)
1448 return;
1449
1450 if (I->Exists() == false)
1451 return;
1452
1453 if (I->FindInCache(Gen.GetCache()).end() == false)
1454 {
1455 _error->Warning("Duplicate sources.list entry %s",
1456 I->Describe().c_str());
1457 return;
1458 }
1459
1460 map_filesize_t const Size = I->Size();
1461 if (Progress != NULL)
1462 Progress->OverallProgress(CurrentSize, TotalSize, Size, _("Reading package lists"));
1463 CurrentSize += Size;
1464
1465 if (I->Merge(Gen,Progress) == false)
1466 mergeFailure = true;
1467 };
b07aeb1a
DK
1468
1469 if (List != NULL)
1470 {
1471 for (pkgSourceList::const_iterator i = List->begin(); i != List->end(); ++i)
1472 {
3fd89e62 1473 if ((*i)->FindInCache(Gen.GetCache(), false).end() == false)
b07aeb1a
DK
1474 {
1475 _error->Warning("Duplicate sources.list entry %s",
1476 (*i)->Describe().c_str());
1477 continue;
1478 }
1479
1480 if ((*i)->Merge(Gen, Progress) == false)
1481 return false;
1482
1483 std::vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
5465192b
DK
1484 if (Indexes != NULL)
1485 std::for_each(Indexes->begin(), Indexes->end(), indexFileMerge);
1486 if (mergeFailure)
1487 return false;
b07aeb1a
DK
1488 }
1489 }
1490
5465192b 1491 if (Start != End)
2d11135a 1492 {
5465192b
DK
1493 Gen.SelectReleaseFile("", "");
1494 std::for_each(Start, End, indexFileMerge);
1495 if (mergeFailure)
b2e465d6 1496 return false;
5465192b 1497 }
b35d2f5f
AL
1498 return true;
1499}
1500 /*}}}*/
5465192b
DK
1501// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1502// ---------------------------------------------------------------------
1503/* This makes sure that the status cache (the cache that has all
1504 index files from the sources list and all local ones) is ready
1505 to be mmaped. If OutMap is not zero then a MMap object representing
1506 the cache will be stored there. This is pretty much mandetory if you
1507 are using AllowMem. AllowMem lets the function be run as non-root
1508 where it builds the cache 'fast' into a memory buffer. */
1509static DynamicMMap* CreateDynamicMMap(FileFd * const CacheF, unsigned long Flags)
1510{
4ad8619b
DK
1511 map_filesize_t const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1512 map_filesize_t const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1513 map_filesize_t const MapLimit = _config->FindI("APT::Cache-Limit", 0);
dcdf1ef1
DK
1514 Flags |= MMap::Moveable;
1515 if (_config->FindB("APT::Cache-Fallback", false) == true)
1516 Flags |= MMap::Fallback;
1517 if (CacheF != NULL)
1518 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1519 else
1520 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1521}
5465192b
DK
1522static bool writeBackMMapToFile(pkgCacheGenerator * const Gen, DynamicMMap * const Map,
1523 std::string const &FileName)
1524{
1525 FileFd SCacheF(FileName, FileFd::WriteAtomic);
95278287 1526 if (SCacheF.IsOpen() == false || SCacheF.Failed())
5465192b
DK
1527 return false;
1528
1529 fchmod(SCacheF.Fd(),0644);
1530
1531 // Write out the main data
1532 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1533 return _error->Error(_("IO Error saving source cache"));
5465192b
DK
1534
1535 // Write out the proper header
1536 Gen->GetCache().HeaderP->Dirty = false;
25c7a09d 1537 Gen->GetCache().HeaderP->CacheFileSize = Gen->GetCache().CacheHash();
5465192b
DK
1538 if (SCacheF.Seek(0) == false ||
1539 SCacheF.Write(Map->Data(),sizeof(*Gen->GetCache().HeaderP)) == false)
1540 return _error->Error(_("IO Error saving source cache"));
1541 Gen->GetCache().HeaderP->Dirty = true;
5465192b
DK
1542 return true;
1543}
1544static bool loadBackMMapFromFile(std::unique_ptr<pkgCacheGenerator> &Gen,
6c413b18 1545 std::unique_ptr<DynamicMMap> &Map, OpProgress * const Progress, std::string const &FileName)
5465192b 1546{
6c413b18 1547 Map.reset(CreateDynamicMMap(NULL, 0));
6789e01e
DK
1548 if (unlikely(Map->validData()) == false)
1549 return false;
5465192b 1550 FileFd CacheF(FileName, FileFd::ReadOnly);
95278287
DK
1551 if (CacheF.IsOpen() == false || CacheF.Failed())
1552 return false;
1553 _error->PushToStack();
5465192b 1554 map_pointer_t const alloc = Map->RawAllocate(CacheF.Size());
95278287
DK
1555 bool const newError = _error->PendingError();
1556 _error->MergeWithStack();
1557 if (alloc == 0 && newError)
1558 return false;
1559 if (CacheF.Read((unsigned char *)Map->Data() + alloc, CacheF.Size()) == false)
5465192b 1560 return false;
6c413b18 1561 Gen.reset(new pkgCacheGenerator(Map.get(),Progress));
5465192b
DK
1562 return true;
1563}
5dd00edb 1564bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
2e5f4e45
DK
1565 MMap **OutMap, bool AllowMem)
1566 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1567bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
c4171975 1568 MMap **OutMap,bool)
f1616039
JAK
1569{
1570 return pkgCacheGenerator::MakeStatusCache(List, Progress, OutMap, nullptr, true);
1571}
1572bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
1573 MMap **OutMap,pkgCache **OutCache, bool)
b35d2f5f 1574{
c4171975 1575 // FIXME: deprecate the ignored AllowMem parameter
c8e572e3 1576 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
73688d27
DK
1577
1578 std::vector<pkgIndexFile *> Files;
b2e465d6
AL
1579 if (_system->AddStatusFiles(Files) == false)
1580 return false;
c5f44afc 1581
b2e465d6 1582 // Decide if we can write to the files..
c8e572e3
MV
1583 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1584 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1cd1c398
DK
1585
1586 // ensure the cache directory exists
1587 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1588 {
1589 string dir = _config->FindDir("Dir::Cache");
1590 size_t const len = dir.size();
1591 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1592 dir = dir.substr(0, len - 5);
1593 if (CacheFile.empty() == false)
1594 CreateDirectory(dir, flNotFile(CacheFile));
1595 if (SrcCacheFile.empty() == false)
1596 CreateDirectory(dir, flNotFile(SrcCacheFile));
1597 }
1598
2e5f4e45
DK
1599 if (Progress != NULL)
1600 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1601
5465192b
DK
1602 bool pkgcache_fine = false;
1603 bool srcpkgcache_fine = false;
1604 bool volatile_fine = List.GetVolatileFiles().empty();
1605
f1616039
JAK
1606 if (CheckValidity(CacheFile, List, Files.begin(), Files.end(), volatile_fine ? OutMap : NULL,
1607 volatile_fine ? OutCache : NULL) == true)
b2e465d6 1608 {
c8e572e3 1609 if (Debug == true)
5465192b
DK
1610 std::clog << "pkgcache.bin is valid - no need to build any cache" << std::endl;
1611 pkgcache_fine = true;
1612 srcpkgcache_fine = true;
b2e465d6 1613 }
5465192b 1614 if (pkgcache_fine == false)
b2e465d6 1615 {
5465192b 1616 if (CheckValidity(SrcCacheFile, List, Files.end(), Files.end()) == true)
41b4dee4 1617 {
41b4dee4 1618 if (Debug == true)
5465192b
DK
1619 std::clog << "srcpkgcache.bin is valid - it can be reused" << std::endl;
1620 srcpkgcache_fine = true;
41b4dee4 1621 }
b35d2f5f 1622 }
5465192b
DK
1623
1624 if (volatile_fine == true && srcpkgcache_fine == true && pkgcache_fine == true)
8ce4327b 1625 {
5465192b
DK
1626 if (Progress != NULL)
1627 Progress->OverallProgress(1,1,1,_("Reading package lists"));
1628 return true;
8ce4327b 1629 }
5465192b
DK
1630
1631 bool Writeable = false;
1632 if (srcpkgcache_fine == false || pkgcache_fine == false)
2d11135a 1633 {
5465192b
DK
1634 if (CacheFile.empty() == false)
1635 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1636 else if (SrcCacheFile.empty() == false)
1637 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
1638
c8e572e3 1639 if (Debug == true)
5465192b 1640 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
5465192b 1641 }
b2e465d6 1642
5465192b 1643 // At this point we know we need to construct something, so get storage ready
6c413b18 1644 std::unique_ptr<DynamicMMap> Map(CreateDynamicMMap(NULL, 0));
6789e01e
DK
1645 if (unlikely(Map->validData()) == false)
1646 return false;
5465192b
DK
1647 if (Debug == true)
1648 std::clog << "Open memory Map (not filebased)" << std::endl;
c8e572e3 1649
5465192b
DK
1650 std::unique_ptr<pkgCacheGenerator> Gen{nullptr};
1651 map_filesize_t CurrentSize = 0;
1652 std::vector<pkgIndexFile*> VolatileFiles = List.GetVolatileFiles();
1653 map_filesize_t TotalSize = ComputeSize(NULL, VolatileFiles.begin(), VolatileFiles.end());
1654 if (srcpkgcache_fine == true && pkgcache_fine == false)
1655 {
1656 if (Debug == true)
1657 std::clog << "srcpkgcache.bin was valid - populate MMap with it" << std::endl;
1658 if (loadBackMMapFromFile(Gen, Map, Progress, SrcCacheFile) == false)
b2e465d6 1659 return false;
5465192b
DK
1660 srcpkgcache_fine = true;
1661 TotalSize += ComputeSize(NULL, Files.begin(), Files.end());
b2e465d6 1662 }
5465192b 1663 else if (srcpkgcache_fine == false)
2d11135a 1664 {
c8e572e3
MV
1665 if (Debug == true)
1666 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
6c413b18 1667 Gen.reset(new pkgCacheGenerator(Map.get(),Progress));
5465192b
DK
1668
1669 TotalSize += ComputeSize(&List, Files.begin(),Files.end());
1670 if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, &List,
1671 Files.end(),Files.end()) == false)
b2e465d6 1672 return false;
5465192b 1673
b2e465d6 1674 if (Writeable == true && SrcCacheFile.empty() == false)
6c413b18 1675 if (writeBackMMapToFile(Gen.get(), Map.get(), SrcCacheFile) == false)
b2e465d6 1676 return false;
5465192b
DK
1677 }
1678
1679 if (pkgcache_fine == false)
1680 {
1681 if (Debug == true)
1682 std::clog << "Building status cache in pkgcache.bin now" << std::endl;
1683 if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, NULL,
1684 Files.begin(), Files.end()) == false)
b2e465d6 1685 return false;
5465192b
DK
1686
1687 if (Writeable == true && CacheFile.empty() == false)
6c413b18 1688 if (writeBackMMapToFile(Gen.get(), Map.get(), CacheFile) == false)
5465192b 1689 return false;
2d11135a 1690 }
5465192b 1691
c8e572e3 1692 if (Debug == true)
5465192b 1693 std::clog << "Caches done. Now bring in the volatile files (if any)" << std::endl;
2d11135a 1694
5465192b 1695 if (volatile_fine == false)
2d11135a 1696 {
5465192b 1697 if (Gen == nullptr)
2d11135a 1698 {
5465192b
DK
1699 if (Debug == true)
1700 std::clog << "Populate new MMap with cachefile contents" << std::endl;
1701 if (loadBackMMapFromFile(Gen, Map, Progress, CacheFile) == false)
1702 return false;
2d11135a 1703 }
5465192b
DK
1704
1705 Files = List.GetVolatileFiles();
1706 if (BuildCache(*Gen, Progress, CurrentSize, TotalSize, NULL,
1707 Files.begin(), Files.end()) == false)
1708 return false;
2d11135a 1709 }
5465192b
DK
1710
1711 if (OutMap != nullptr)
6c413b18 1712 *OutMap = Map.release();
5465192b
DK
1713
1714 if (Debug == true)
1715 std::clog << "Everything is ready for shipping" << std::endl;
b2e465d6
AL
1716 return true;
1717}
1718 /*}}}*/
2e5f4e45 1719// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
95278287
DK
1720class APT_HIDDEN ScopedErrorMerge {
1721public:
1722 ScopedErrorMerge() { _error->PushToStack(); }
1723 ~ScopedErrorMerge() { _error->MergeWithStack(); }
1724};
5dd00edb 1725bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
2e5f4e45
DK
1726 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1727bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
b2e465d6 1728{
73688d27 1729 std::vector<pkgIndexFile *> Files;
b2e465d6
AL
1730 if (_system->AddStatusFiles(Files) == false)
1731 return false;
dcdf1ef1 1732
95278287 1733 ScopedErrorMerge sem;
6c413b18 1734 std::unique_ptr<DynamicMMap> Map(CreateDynamicMMap(NULL, 0));
6789e01e
DK
1735 if (unlikely(Map->validData()) == false)
1736 return false;
4ad8619b
DK
1737 map_filesize_t CurrentSize = 0;
1738 map_filesize_t TotalSize = 0;
b07aeb1a 1739 TotalSize = ComputeSize(NULL, Files.begin(), Files.end());
95278287 1740
b2e465d6 1741 // Build the status cache
2e5f4e45
DK
1742 if (Progress != NULL)
1743 Progress->OverallProgress(0,1,1,_("Reading package lists"));
6c413b18 1744 pkgCacheGenerator Gen(Map.get(),Progress);
2d11135a 1745 if (_error->PendingError() == true)
b2e465d6 1746 return false;
b07aeb1a
DK
1747 if (BuildCache(Gen,Progress,CurrentSize,TotalSize, NULL,
1748 Files.begin(), Files.end()) == false)
b2e465d6 1749 return false;
25396fb0 1750
b2e465d6
AL
1751 if (_error->PendingError() == true)
1752 return false;
6c413b18 1753 *OutMap = Map.release();
2d11135a 1754
b2e465d6 1755 return true;
2d11135a
AL
1756}
1757 /*}}}*/
5f4db009 1758// IsDuplicateDescription /*{{{*/
60683765 1759static bool IsDuplicateDescription(pkgCache::DescIterator Desc,
5f4db009
DK
1760 MD5SumValue const &CurMd5, std::string const &CurLang)
1761{
22f07fc5 1762 // Descriptions in the same link-list have all the same md5
7f5aab82 1763 if (Desc.end() == true || MD5SumValue(Desc.md5()) != CurMd5)
22f07fc5
DK
1764 return false;
1765 for (; Desc.end() == false; ++Desc)
1766 if (Desc.LanguageCode() == CurLang)
5f4db009
DK
1767 return true;
1768 return false;
1769}
1770 /*}}}*/
c8a4ce6c 1771
1d3eea5c 1772pkgCacheListParser::pkgCacheListParser() : Owner(NULL), OldDepLast(NULL), d(NULL) {}
c9443c01 1773pkgCacheListParser::~pkgCacheListParser() {}