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