]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
* apt-pkg/deb/debsrcrecords.cc:
[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;
d10cef82 39template <typename Iter> std::vector<Iter*> pkgCacheGenerator::Dynamic<Iter>::toReMap;
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 117 i != Dynamic<pkgCache::GrpIterator>::toReMap.end(); ++i)
f7a35f2e 118 (*i)->ReMap(oldMap, newMap);
7635093c 119 for (std::vector<pkgCache::PkgIterator*>::const_iterator i = Dynamic<pkgCache::PkgIterator>::toReMap.begin();
a9fe5928 120 i != Dynamic<pkgCache::PkgIterator>::toReMap.end(); ++i)
f7a35f2e 121 (*i)->ReMap(oldMap, newMap);
7635093c 122 for (std::vector<pkgCache::VerIterator*>::const_iterator i = Dynamic<pkgCache::VerIterator>::toReMap.begin();
a9fe5928 123 i != Dynamic<pkgCache::VerIterator>::toReMap.end(); ++i)
f7a35f2e 124 (*i)->ReMap(oldMap, newMap);
7635093c 125 for (std::vector<pkgCache::DepIterator*>::const_iterator i = Dynamic<pkgCache::DepIterator>::toReMap.begin();
a9fe5928 126 i != Dynamic<pkgCache::DepIterator>::toReMap.end(); ++i)
f7a35f2e 127 (*i)->ReMap(oldMap, newMap);
7635093c 128 for (std::vector<pkgCache::DescIterator*>::const_iterator i = Dynamic<pkgCache::DescIterator>::toReMap.begin();
a9fe5928 129 i != Dynamic<pkgCache::DescIterator>::toReMap.end(); ++i)
f7a35f2e 130 (*i)->ReMap(oldMap, newMap);
7635093c 131 for (std::vector<pkgCache::PrvIterator*>::const_iterator i = Dynamic<pkgCache::PrvIterator>::toReMap.begin();
a9fe5928 132 i != Dynamic<pkgCache::PrvIterator>::toReMap.end(); ++i)
f7a35f2e 133 (*i)->ReMap(oldMap, newMap);
7635093c 134 for (std::vector<pkgCache::PkgFileIterator*>::const_iterator i = Dynamic<pkgCache::PkgFileIterator>::toReMap.begin();
a9fe5928 135 i != Dynamic<pkgCache::PkgFileIterator>::toReMap.end(); ++i)
f7a35f2e 136 (*i)->ReMap(oldMap, newMap);
a9fe5928 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 /*}}}*/
dd13742e 1097// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
dcdf1ef1
DK
1098DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) {
1099 unsigned long const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1100 unsigned long const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1101 unsigned long const MapLimit = _config->FindI("APT::Cache-Limit", 0);
1102 Flags |= MMap::Moveable;
1103 if (_config->FindB("APT::Cache-Fallback", false) == true)
1104 Flags |= MMap::Fallback;
1105 if (CacheF != NULL)
1106 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1107 else
1108 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1109}
dd13742e 1110 /*}}}*/
2e5f4e45 1111// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 1112// ---------------------------------------------------------------------
b2e465d6
AL
1113/* This makes sure that the status cache (the cache that has all
1114 index files from the sources list and all local ones) is ready
1115 to be mmaped. If OutMap is not zero then a MMap object representing
1116 the cache will be stored there. This is pretty much mandetory if you
1117 are using AllowMem. AllowMem lets the function be run as non-root
1118 where it builds the cache 'fast' into a memory buffer. */
2e5f4e45
DK
1119__deprecated bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
1120 MMap **OutMap, bool AllowMem)
1121 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1122bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
b2e465d6 1123 MMap **OutMap,bool AllowMem)
b35d2f5f 1124{
c8e572e3 1125 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
67db871e 1126
7db98ffc
MZ
1127 vector<pkgIndexFile *> Files;
1128 for (vector<metaIndex *>::const_iterator i = List.begin();
1129 i != List.end();
1130 i++)
1131 {
1132 vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1133 for (vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
1134 j != Indexes->end();
1135 j++)
1136 Files.push_back (*j);
1137 }
1138
c8e572e3 1139 unsigned long const EndOfSource = Files.size();
b2e465d6
AL
1140 if (_system->AddStatusFiles(Files) == false)
1141 return false;
c5f44afc 1142
b2e465d6 1143 // Decide if we can write to the files..
c8e572e3
MV
1144 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1145 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1cd1c398
DK
1146
1147 // ensure the cache directory exists
1148 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1149 {
1150 string dir = _config->FindDir("Dir::Cache");
1151 size_t const len = dir.size();
1152 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1153 dir = dir.substr(0, len - 5);
1154 if (CacheFile.empty() == false)
1155 CreateDirectory(dir, flNotFile(CacheFile));
1156 if (SrcCacheFile.empty() == false)
1157 CreateDirectory(dir, flNotFile(SrcCacheFile));
1158 }
1159
b2e465d6
AL
1160 // Decide if we can write to the cache
1161 bool Writeable = false;
1162 if (CacheFile.empty() == false)
1163 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1164 else
1165 if (SrcCacheFile.empty() == false)
1166 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
c8e572e3
MV
1167 if (Debug == true)
1168 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1169
b2e465d6
AL
1170 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
1171 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
2e5f4e45
DK
1172
1173 if (Progress != NULL)
1174 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1175
b2e465d6
AL
1176 // Cache is OK, Fin.
1177 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
1178 {
2e5f4e45
DK
1179 if (Progress != NULL)
1180 Progress->OverallProgress(1,1,1,_("Reading package lists"));
c8e572e3
MV
1181 if (Debug == true)
1182 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
b2e465d6
AL
1183 return true;
1184 }
c8e572e3
MV
1185 else if (Debug == true)
1186 std::clog << "pkgcache.bin is NOT valid" << std::endl;
b2e465d6
AL
1187
1188 /* At this point we know we need to reconstruct the package cache,
1189 begin. */
1190 SPtr<FileFd> CacheF;
1191 SPtr<DynamicMMap> Map;
1192 if (Writeable == true && CacheFile.empty() == false)
1193 {
1194 unlink(CacheFile.c_str());
22041bd2 1195 CacheF = new FileFd(CacheFile,FileFd::WriteAtomic);
7a3c2ab0 1196 fchmod(CacheF->Fd(),0644);
dcdf1ef1 1197 Map = CreateDynamicMMap(CacheF, MMap::Public);
b35d2f5f
AL
1198 if (_error->PendingError() == true)
1199 return false;
c8e572e3
MV
1200 if (Debug == true)
1201 std::clog << "Open filebased MMap" << std::endl;
b35d2f5f 1202 }
b2e465d6 1203 else
8ce4327b 1204 {
b2e465d6 1205 // Just build it in memory..
dcdf1ef1 1206 Map = CreateDynamicMMap(NULL);
c8e572e3
MV
1207 if (Debug == true)
1208 std::clog << "Open memory Map (not filebased)" << std::endl;
8ce4327b 1209 }
b35d2f5f 1210
b2e465d6 1211 // Lets try the source cache.
b35d2f5f 1212 unsigned long CurrentSize = 0;
b2e465d6
AL
1213 unsigned long TotalSize = 0;
1214 if (CheckValidity(SrcCacheFile,Files.begin(),
1215 Files.begin()+EndOfSource) == true)
2d11135a 1216 {
c8e572e3
MV
1217 if (Debug == true)
1218 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
b2e465d6
AL
1219 // Preload the map with the source cache
1220 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
c8e572e3 1221 unsigned long const alloc = Map->RawAllocate(SCacheF.Size());
eb162ff7
DK
1222 if ((alloc == 0 && _error->PendingError())
1223 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
1224 SCacheF.Size()) == false)
b2e465d6
AL
1225 return false;
1226
1227 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
c8e572e3 1228
b2e465d6 1229 // Build the status cache
2e5f4e45 1230 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1231 if (_error->PendingError() == true)
b2e465d6
AL
1232 return false;
1233 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1234 Files.begin()+EndOfSource,Files.end()) == false)
1235 return false;
25396fb0
DK
1236
1237 // FIXME: move me to a better place
1238 Gen.FinishCache(Progress);
b2e465d6
AL
1239 }
1240 else
2d11135a 1241 {
c8e572e3
MV
1242 if (Debug == true)
1243 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
b2e465d6 1244 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 1245
b2e465d6 1246 // Build the source cache
2e5f4e45 1247 pkgCacheGenerator Gen(Map.Get(),Progress);
b2e465d6
AL
1248 if (_error->PendingError() == true)
1249 return false;
1250 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1251 Files.begin(),Files.begin()+EndOfSource) == false)
1252 return false;
2d11135a 1253
b2e465d6
AL
1254 // Write it back
1255 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 1256 {
22041bd2 1257 FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic);
b2e465d6
AL
1258 if (_error->PendingError() == true)
1259 return false;
7a3c2ab0
AL
1260
1261 fchmod(SCacheF.Fd(),0644);
1262
b2e465d6
AL
1263 // Write out the main data
1264 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1265 return _error->Error(_("IO Error saving source cache"));
1266 SCacheF.Sync();
1267
1268 // Write out the proper header
1269 Gen.GetCache().HeaderP->Dirty = false;
1270 if (SCacheF.Seek(0) == false ||
1271 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
1272 return _error->Error(_("IO Error saving source cache"));
b2e465d6 1273 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 1274 SCacheF.Sync();
2d11135a
AL
1275 }
1276
b2e465d6
AL
1277 // Build the status cache
1278 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1279 Files.begin()+EndOfSource,Files.end()) == false)
1280 return false;
25396fb0
DK
1281
1282 // FIXME: move me to a better place
1283 Gen.FinishCache(Progress);
2d11135a 1284 }
c8e572e3
MV
1285 if (Debug == true)
1286 std::clog << "Caches are ready for shipping" << std::endl;
2d11135a 1287
b2e465d6
AL
1288 if (_error->PendingError() == true)
1289 return false;
1290 if (OutMap != 0)
2d11135a 1291 {
b2e465d6 1292 if (CacheF != 0)
2d11135a 1293 {
b2e465d6 1294 delete Map.UnGuard();
eb162ff7 1295 *OutMap = new MMap(*CacheF,0);
2d11135a 1296 }
b2e465d6
AL
1297 else
1298 {
1299 *OutMap = Map.UnGuard();
1300 }
2d11135a
AL
1301 }
1302
b2e465d6
AL
1303 return true;
1304}
1305 /*}}}*/
2e5f4e45 1306// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
b2e465d6
AL
1307// ---------------------------------------------------------------------
1308/* */
2e5f4e45
DK
1309__deprecated bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
1310 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1311bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
b2e465d6 1312{
b2e465d6
AL
1313 vector<pkgIndexFile *> Files;
1314 unsigned long EndOfSource = Files.size();
1315 if (_system->AddStatusFiles(Files) == false)
1316 return false;
dcdf1ef1
DK
1317
1318 SPtr<DynamicMMap> Map = CreateDynamicMMap(NULL);
b2e465d6
AL
1319 unsigned long CurrentSize = 0;
1320 unsigned long TotalSize = 0;
1321
1322 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1323
1324 // Build the status cache
2e5f4e45
DK
1325 if (Progress != NULL)
1326 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1327 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1328 if (_error->PendingError() == true)
b2e465d6
AL
1329 return false;
1330 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1331 Files.begin()+EndOfSource,Files.end()) == false)
1332 return false;
25396fb0
DK
1333
1334 // FIXME: move me to a better place
1335 Gen.FinishCache(Progress);
1336
b2e465d6
AL
1337 if (_error->PendingError() == true)
1338 return false;
1339 *OutMap = Map.UnGuard();
2d11135a 1340
b2e465d6 1341 return true;
2d11135a
AL
1342}
1343 /*}}}*/