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