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