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