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