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