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