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