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