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