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