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