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