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