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