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