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