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