* apt-pkg/pkgcachegen.cc:
[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;
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 640 {
33dd02e3 641 pkgCache::PkgIterator allPkg;
a9fe5928
DK
642 Dynamic<pkgCache::PkgIterator> DynallPkg(allPkg);
643 pkgCache::VerIterator V = P.VersionList();
644 Dynamic<pkgCache::VerIterator> DynV(V);
645 for (; V.end() != true; V++)
33dd02e3 646 {
a1ac2ca8 647 char const * const Arch = P.Arch();
33dd02e3
DK
648 map_ptrloc *OldDepLast = NULL;
649 /* MultiArch handling introduces a lot of implicit Dependencies:
650 - MultiArch: same → Co-Installable if they have the same version
651 - Architecture: all → Need to be Co-Installable for internal reasons
652 - All others conflict with all other group members */
a1ac2ca8 653 bool const coInstall = ((V->MultiArch == pkgCache::Version::All && strcmp(Arch, "all") != 0) ||
33dd02e3
DK
654 V->MultiArch == pkgCache::Version::Same);
655 if (V->MultiArch == pkgCache::Version::All && allPkg.end() == true)
656 allPkg = G.FindPkg("all");
657 for (vector<string>::const_iterator A = archs.begin(); A != archs.end(); ++A)
658 {
659 if (*A == Arch)
660 continue;
661 /* We allow only one installed arch at the time
662 per group, therefore each group member conflicts
663 with all other group members */
664 pkgCache::PkgIterator D = G.FindPkg(*A);
a9fe5928 665 Dynamic<pkgCache::PkgIterator> DynD(D);
33dd02e3
DK
666 if (D.end() == true)
667 continue;
668 if (coInstall == true)
669 {
670 // Replaces: ${self}:other ( << ${binary:Version})
671 NewDepends(D, V, V.VerStr(),
672 pkgCache::Dep::Less, pkgCache::Dep::Replaces,
673 OldDepLast);
674 // Breaks: ${self}:other (!= ${binary:Version})
675 NewDepends(D, V, V.VerStr(),
3b527295 676 pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks,
33dd02e3
DK
677 OldDepLast);
678 if (V->MultiArch == pkgCache::Version::All)
679 {
680 // Depend on ${self}:all which does depend on nothing
681 NewDepends(allPkg, V, V.VerStr(),
682 pkgCache::Dep::Equals, pkgCache::Dep::Depends,
683 OldDepLast);
684 }
685 } else {
686 // Conflicts: ${self}:other
a1ac2ca8
DK
687 if (strcmp(Arch, "all") == 0) {
688 NewDepends(D, V, V.VerStr(),
689 pkgCache::Dep::NotEquals, pkgCache::Dep::Conflicts,
690 OldDepLast);
691 } else {
692 NewDepends(D, V, "",
693 pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
694 OldDepLast);
695 }
33dd02e3
DK
696 }
697 }
698 }
699 }
700 }
701 }
702 return true;
25396fb0
DK
703}
704 /*}}}*/
705// CacheGenerator::NewDepends - Create a dependency element /*{{{*/
dcb79bae
AL
706// ---------------------------------------------------------------------
707/* This creates a dependency element in the tree. It is linked to the
708 version and to the package that it is pointing to. */
25396fb0
DK
709bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
710 pkgCache::VerIterator &Ver,
711 string const &Version,
712 unsigned int const &Op,
713 unsigned int const &Type,
714 map_ptrloc *OldDepLast)
dcb79bae 715{
a9fe5928 716 void const * const oldMap = Map.Data();
dcb79bae 717 // Get a structure
a9fe5928 718 map_ptrloc const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
5bf15716 719 if (unlikely(Dependency == 0))
dcb79bae
AL
720 return false;
721
722 // Fill it in
723 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
a9fe5928 724 Dynamic<pkgCache::DepIterator> DynDep(Dep);
dcb79bae
AL
725 Dep->ParentVer = Ver.Index();
726 Dep->Type = Type;
727 Dep->CompareOp = Op;
728 Dep->ID = Cache.HeaderP->DependsCount++;
5bf15716 729
dcb79bae
AL
730 // Probe the reverse dependency list for a version string that matches
731 if (Version.empty() == false)
732 {
b2e465d6 733/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
dcb79bae 734 if (I->Version != 0 && I.TargetVer() == Version)
f9eec0e7 735 Dep->Version = I->Version;*/
a9fe5928
DK
736 if (Dep->Version == 0) {
737 map_ptrloc const index = WriteStringInMap(Version);
738 if (unlikely(index == 0))
dcb79bae 739 return false;
a9fe5928
DK
740 Dep->Version = index;
741 }
dcb79bae 742 }
25396fb0 743
dcb79bae
AL
744 // Link it to the package
745 Dep->Package = Pkg.Index();
746 Dep->NextRevDepends = Pkg->RevDepends;
747 Pkg->RevDepends = Dep.Index();
25396fb0
DK
748
749 // Do we know where to link the Dependency to?
750 if (OldDepLast == NULL)
c1a22377 751 {
f9eec0e7 752 OldDepLast = &Ver->DependsList;
eb162ff7 753 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
f9eec0e7 754 OldDepLast = &D->NextDepends;
a9fe5928
DK
755 } else if (oldMap != Map.Data())
756 OldDepLast += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap;
45415543 757
f9eec0e7
AL
758 Dep->NextDepends = *OldDepLast;
759 *OldDepLast = Dep.Index();
760 OldDepLast = &Dep->NextDepends;
c1a22377 761
dcb79bae
AL
762 return true;
763}
764 /*}}}*/
25396fb0
DK
765// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
766// ---------------------------------------------------------------------
767/* This creates a Group and the Package to link this dependency to if
768 needed and handles also the caching of the old endpoint */
32b9a14c 769bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver,
25396fb0
DK
770 const string &PackageName,
771 const string &Arch,
772 const string &Version,
773 unsigned int Op,
774 unsigned int Type)
775{
776 pkgCache::GrpIterator Grp;
a9fe5928 777 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
25396fb0
DK
778 if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
779 return false;
780
781 // Locate the target package
782 pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
a9fe5928 783 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
25396fb0
DK
784 if (Pkg.end() == true) {
785 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
786 return false;
787 }
788
789 // Is it a file dependency?
790 if (unlikely(PackageName[0] == '/'))
791 FoundFileDeps = true;
792
793 /* Caching the old end point speeds up generation substantially */
794 if (OldDepVer != Ver) {
795 OldDepLast = NULL;
796 OldDepVer = Ver;
797 }
798
799 return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
800}
801 /*}}}*/
dcb79bae
AL
802// ListParser::NewProvides - Create a Provides element /*{{{*/
803// ---------------------------------------------------------------------
804/* */
32b9a14c 805bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
67e0766f
DK
806 const string &PkgName,
807 const string &PkgArch,
171c75f1 808 const string &Version)
dcb79bae
AL
809{
810 pkgCache &Cache = Owner->Cache;
8efa2a3b
AL
811
812 // We do not add self referencing provides
803ea2a8 813 if (Ver.ParentPkg().Name() == PkgName && PkgArch == Ver.Arch(true))
8efa2a3b 814 return true;
dcb79bae
AL
815
816 // Get a structure
a9fe5928 817 map_ptrloc const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
5bf15716 818 if (unlikely(Provides == 0))
dcb79bae 819 return false;
a7e66b17 820 Cache.HeaderP->ProvidesCount++;
dcb79bae
AL
821
822 // Fill it in
823 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
a9fe5928 824 Dynamic<pkgCache::PrvIterator> DynPrv(Prv);
dcb79bae
AL
825 Prv->Version = Ver.Index();
826 Prv->NextPkgProv = Ver->ProvidesList;
827 Ver->ProvidesList = Prv.Index();
5bf15716 828 if (Version.empty() == false && unlikely((Prv->ProvideVersion = WriteString(Version)) == 0))
dcb79bae
AL
829 return false;
830
831 // Locate the target package
8efa2a3b 832 pkgCache::PkgIterator Pkg;
a9fe5928 833 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
67e0766f 834 if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
8efa2a3b 835 return false;
dcb79bae
AL
836
837 // Link it to the package
838 Prv->ParentPkg = Pkg.Index();
839 Prv->NextProvides = Pkg->ProvidesList;
840 Pkg->ProvidesList = Prv.Index();
841
842 return true;
843}
844 /*}}}*/
578bfd0a
AL
845// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
846// ---------------------------------------------------------------------
847/* This is used to select which file is to be associated with all newly
b2e465d6 848 added versions. The caller is responsible for setting the IMS fields. */
171c75f1 849bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
b2e465d6
AL
850 const pkgIndexFile &Index,
851 unsigned long Flags)
578bfd0a 852{
578bfd0a 853 // Get some space for the structure
a9fe5928
DK
854 map_ptrloc const idxFile = AllocateInMap(sizeof(*CurrentFile));
855 if (unlikely(idxFile == 0))
578bfd0a 856 return false;
a9fe5928
DK
857 CurrentFile = Cache.PkgFileP + idxFile;
858
578bfd0a 859 // Fill it in
a9fe5928
DK
860 map_ptrloc const idxFileName = WriteStringInMap(File);
861 map_ptrloc const idxSite = WriteUniqString(Site);
862 if (unlikely(idxFileName == 0 || idxSite == 0))
863 return false;
864 CurrentFile->FileName = idxFileName;
865 CurrentFile->Site = idxSite;
578bfd0a
AL
866 CurrentFile->NextFile = Cache.HeaderP->FileList;
867 CurrentFile->Flags = Flags;
e1b74f61 868 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
a9fe5928
DK
869 map_ptrloc const idxIndexType = WriteUniqString(Index.GetType()->Label);
870 if (unlikely(idxIndexType == 0))
871 return false;
872 CurrentFile->IndexType = idxIndexType;
578bfd0a 873 PkgFileName = File;
ad00ae81 874 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
b35d2f5f 875 Cache.HeaderP->PackageFileCount++;
b2e465d6 876
ddc1d8d0 877 if (Progress != 0)
b2e465d6 878 Progress->SubProgress(Index.Size());
8efa2a3b 879 return true;
578bfd0a
AL
880}
881 /*}}}*/
f55a958f
AL
882// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
883// ---------------------------------------------------------------------
884/* This is used to create handles to strings. Given the same text it
885 always returns the same number */
886unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
887 unsigned int Size)
888{
f9eec0e7
AL
889 /* We use a very small transient hash table here, this speeds up generation
890 by a fair amount on slower machines */
891 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
892 if (Bucket != 0 &&
893 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
894 return Bucket->String;
895
f55a958f
AL
896 // Search for an insertion point
897 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
898 int Res = 1;
349cd3b8 899 map_ptrloc *Last = &Cache.HeaderP->StringList;
f55a958f
AL
900 for (; I != Cache.StringItemP; Last = &I->NextItem,
901 I = Cache.StringItemP + I->NextItem)
902 {
9c14e3d6 903 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
f55a958f
AL
904 if (Res >= 0)
905 break;
906 }
907
908 // Match
909 if (Res == 0)
f9eec0e7
AL
910 {
911 Bucket = I;
0149949b 912 return I->String;
f9eec0e7 913 }
f55a958f
AL
914
915 // Get a structure
a9fe5928
DK
916 void const * const oldMap = Map.Data();
917 map_ptrloc const Item = AllocateInMap(sizeof(pkgCache::StringItem));
f55a958f 918 if (Item == 0)
0149949b
AL
919 return 0;
920
a9fe5928
DK
921 map_ptrloc const idxString = WriteStringInMap(S,Size);
922 if (unlikely(idxString == 0))
923 return 0;
924 if (oldMap != Map.Data()) {
925 Last += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap;
926 I += (pkgCache::StringItem*) Map.Data() - (pkgCache::StringItem*) oldMap;
927 }
928 *Last = Item;
929
f55a958f
AL
930 // Fill in the structure
931 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
932 ItemP->NextItem = I - Cache.StringItemP;
a9fe5928
DK
933 ItemP->String = idxString;
934
f9eec0e7 935 Bucket = ItemP;
0149949b 936 return ItemP->String;
f55a958f
AL
937}
938 /*}}}*/
b2e465d6 939// CheckValidity - Check that a cache is up-to-date /*{{{*/
b35d2f5f 940// ---------------------------------------------------------------------
b2e465d6
AL
941/* This just verifies that each file in the list of index files exists,
942 has matching attributes with the cache and the cache does not have
943 any extra files. */
171c75f1 944static bool CheckValidity(const string &CacheFile, FileIterator Start,
e7b470ee 945 FileIterator End,MMap **OutMap = 0)
b35d2f5f 946{
c8e572e3 947 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
b2e465d6
AL
948 // No file, certainly invalid
949 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
c8e572e3
MV
950 {
951 if (Debug == true)
952 std::clog << "CacheFile doesn't exist" << std::endl;
b35d2f5f 953 return false;
c8e572e3
MV
954 }
955
b2e465d6 956 // Map it
b35d2f5f 957 FileFd CacheF(CacheFile,FileFd::ReadOnly);
eb162ff7 958 SPtr<MMap> Map = new MMap(CacheF,0);
b35d2f5f 959 pkgCache Cache(Map);
b2e465d6 960 if (_error->PendingError() == true || Map->Size() == 0)
b35d2f5f 961 {
c8e572e3
MV
962 if (Debug == true)
963 std::clog << "Errors are pending or Map is empty()" << std::endl;
b35d2f5f
AL
964 _error->Discard();
965 return false;
966 }
b35d2f5f 967
b2e465d6
AL
968 /* Now we check every index file, see if it is in the cache,
969 verify the IMS data and check that it is on the disk too.. */
970 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
971 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
972 for (; Start != End; Start++)
c8e572e3
MV
973 {
974 if (Debug == true)
975 std::clog << "Checking PkgFile " << (*Start)->Describe() << ": ";
b2e465d6 976 if ((*Start)->HasPackages() == false)
c8e572e3
MV
977 {
978 if (Debug == true)
979 std::clog << "Has NO packages" << std::endl;
b2e465d6 980 continue;
c8e572e3 981 }
a77ad7c3 982
b2e465d6 983 if ((*Start)->Exists() == false)
b35d2f5f 984 {
a791a450 985#if 0 // mvo: we no longer give a message here (Default Sources spec)
b2e465d6
AL
986 _error->WarningE("stat",_("Couldn't stat source package list %s"),
987 (*Start)->Describe().c_str());
a791a450 988#endif
c8e572e3
MV
989 if (Debug == true)
990 std::clog << "file doesn't exist" << std::endl;
b2e465d6 991 continue;
b35d2f5f 992 }
b2e465d6
AL
993
994 // FindInCache is also expected to do an IMS check.
995 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
996 if (File.end() == true)
c8e572e3
MV
997 {
998 if (Debug == true)
999 std::clog << "FindInCache returned end-Pointer" << std::endl;
b35d2f5f 1000 return false;
c8e572e3 1001 }
a52f938b 1002
b2e465d6 1003 Visited[File->ID] = true;
c8e572e3
MV
1004 if (Debug == true)
1005 std::clog << "with ID " << File->ID << " is valid" << std::endl;
b35d2f5f
AL
1006 }
1007
b2e465d6
AL
1008 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
1009 if (Visited[I] == false)
c8e572e3
MV
1010 {
1011 if (Debug == true)
1012 std::clog << "File with ID" << I << " wasn't visited" << std::endl;
b2e465d6 1013 return false;
c8e572e3 1014 }
b35d2f5f 1015
b35d2f5f
AL
1016 if (_error->PendingError() == true)
1017 {
c8e572e3
MV
1018 if (Debug == true)
1019 {
1020 std::clog << "Validity failed because of pending errors:" << std::endl;
1021 _error->DumpErrors();
1022 }
b35d2f5f
AL
1023 _error->Discard();
1024 return false;
1025 }
b35d2f5f 1026
b2e465d6
AL
1027 if (OutMap != 0)
1028 *OutMap = Map.UnGuard();
b35d2f5f
AL
1029 return true;
1030}
1031 /*}}}*/
b2e465d6 1032// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 1033// ---------------------------------------------------------------------
b2e465d6
AL
1034/* Size is kind of an abstract notion that is only used for the progress
1035 meter */
e7b470ee 1036static unsigned long ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 1037{
b2e465d6
AL
1038 unsigned long TotalSize = 0;
1039 for (; Start != End; Start++)
b35d2f5f 1040 {
b2e465d6
AL
1041 if ((*Start)->HasPackages() == false)
1042 continue;
1043 TotalSize += (*Start)->Size();
b35d2f5f 1044 }
b2e465d6 1045 return TotalSize;
2d11135a
AL
1046}
1047 /*}}}*/
b2e465d6 1048// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 1049// ---------------------------------------------------------------------
b2e465d6
AL
1050/* */
1051static bool BuildCache(pkgCacheGenerator &Gen,
2e5f4e45 1052 OpProgress *Progress,
b2e465d6 1053 unsigned long &CurrentSize,unsigned long TotalSize,
e7b470ee 1054 FileIterator Start, FileIterator End)
2d11135a 1055{
45415543
AL
1056 FileIterator I;
1057 for (I = Start; I != End; I++)
2d11135a 1058 {
45415543 1059 if ((*I)->HasPackages() == false)
2d11135a
AL
1060 continue;
1061
45415543 1062 if ((*I)->Exists() == false)
2d11135a 1063 continue;
b2e465d6 1064
45415543 1065 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
a77ad7c3
AL
1066 {
1067 _error->Warning("Duplicate sources.list entry %s",
45415543 1068 (*I)->Describe().c_str());
a77ad7c3
AL
1069 continue;
1070 }
1071
45415543 1072 unsigned long Size = (*I)->Size();
2e5f4e45
DK
1073 if (Progress != NULL)
1074 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
b2e465d6 1075 CurrentSize += Size;
2d11135a 1076
45415543 1077 if ((*I)->Merge(Gen,Progress) == false)
b2e465d6
AL
1078 return false;
1079 }
45415543
AL
1080
1081 if (Gen.HasFileDeps() == true)
1082 {
2e5f4e45
DK
1083 if (Progress != NULL)
1084 Progress->Done();
45415543
AL
1085 TotalSize = ComputeSize(Start, End);
1086 CurrentSize = 0;
1087 for (I = Start; I != End; I++)
1088 {
1089 unsigned long Size = (*I)->Size();
2e5f4e45
DK
1090 if (Progress != NULL)
1091 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
45415543
AL
1092 CurrentSize += Size;
1093 if ((*I)->MergeFileProvides(Gen,Progress) == false)
1094 return false;
1095 }
1096 }
2d11135a 1097
b35d2f5f
AL
1098 return true;
1099}
1100 /*}}}*/
dd13742e 1101// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
dcdf1ef1
DK
1102DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) {
1103 unsigned long const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1104 unsigned long const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1105 unsigned long const MapLimit = _config->FindI("APT::Cache-Limit", 0);
1106 Flags |= MMap::Moveable;
1107 if (_config->FindB("APT::Cache-Fallback", false) == true)
1108 Flags |= MMap::Fallback;
1109 if (CacheF != NULL)
1110 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1111 else
1112 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1113}
dd13742e 1114 /*}}}*/
2e5f4e45 1115// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 1116// ---------------------------------------------------------------------
b2e465d6
AL
1117/* This makes sure that the status cache (the cache that has all
1118 index files from the sources list and all local ones) is ready
1119 to be mmaped. If OutMap is not zero then a MMap object representing
1120 the cache will be stored there. This is pretty much mandetory if you
1121 are using AllowMem. AllowMem lets the function be run as non-root
1122 where it builds the cache 'fast' into a memory buffer. */
2e5f4e45
DK
1123__deprecated bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
1124 MMap **OutMap, bool AllowMem)
1125 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1126bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
b2e465d6 1127 MMap **OutMap,bool AllowMem)
b35d2f5f 1128{
c8e572e3 1129 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
67db871e 1130
7db98ffc
MZ
1131 vector<pkgIndexFile *> Files;
1132 for (vector<metaIndex *>::const_iterator i = List.begin();
1133 i != List.end();
1134 i++)
1135 {
1136 vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1137 for (vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
1138 j != Indexes->end();
1139 j++)
1140 Files.push_back (*j);
1141 }
1142
c8e572e3 1143 unsigned long const EndOfSource = Files.size();
b2e465d6
AL
1144 if (_system->AddStatusFiles(Files) == false)
1145 return false;
c5f44afc 1146
b2e465d6 1147 // Decide if we can write to the files..
c8e572e3
MV
1148 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1149 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1cd1c398
DK
1150
1151 // ensure the cache directory exists
1152 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1153 {
1154 string dir = _config->FindDir("Dir::Cache");
1155 size_t const len = dir.size();
1156 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1157 dir = dir.substr(0, len - 5);
1158 if (CacheFile.empty() == false)
1159 CreateDirectory(dir, flNotFile(CacheFile));
1160 if (SrcCacheFile.empty() == false)
1161 CreateDirectory(dir, flNotFile(SrcCacheFile));
1162 }
1163
b2e465d6
AL
1164 // Decide if we can write to the cache
1165 bool Writeable = false;
1166 if (CacheFile.empty() == false)
1167 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1168 else
1169 if (SrcCacheFile.empty() == false)
1170 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
c8e572e3
MV
1171 if (Debug == true)
1172 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1173
b2e465d6
AL
1174 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
1175 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
2e5f4e45
DK
1176
1177 if (Progress != NULL)
1178 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1179
b2e465d6
AL
1180 // Cache is OK, Fin.
1181 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
1182 {
2e5f4e45
DK
1183 if (Progress != NULL)
1184 Progress->OverallProgress(1,1,1,_("Reading package lists"));
c8e572e3
MV
1185 if (Debug == true)
1186 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
b2e465d6
AL
1187 return true;
1188 }
c8e572e3
MV
1189 else if (Debug == true)
1190 std::clog << "pkgcache.bin is NOT valid" << std::endl;
b2e465d6
AL
1191
1192 /* At this point we know we need to reconstruct the package cache,
1193 begin. */
1194 SPtr<FileFd> CacheF;
1195 SPtr<DynamicMMap> Map;
1196 if (Writeable == true && CacheFile.empty() == false)
1197 {
1198 unlink(CacheFile.c_str());
22041bd2 1199 CacheF = new FileFd(CacheFile,FileFd::WriteAtomic);
7a3c2ab0 1200 fchmod(CacheF->Fd(),0644);
dcdf1ef1 1201 Map = CreateDynamicMMap(CacheF, MMap::Public);
b35d2f5f
AL
1202 if (_error->PendingError() == true)
1203 return false;
c8e572e3
MV
1204 if (Debug == true)
1205 std::clog << "Open filebased MMap" << std::endl;
b35d2f5f 1206 }
b2e465d6 1207 else
8ce4327b 1208 {
b2e465d6 1209 // Just build it in memory..
dcdf1ef1 1210 Map = CreateDynamicMMap(NULL);
c8e572e3
MV
1211 if (Debug == true)
1212 std::clog << "Open memory Map (not filebased)" << std::endl;
8ce4327b 1213 }
b35d2f5f 1214
b2e465d6 1215 // Lets try the source cache.
b35d2f5f 1216 unsigned long CurrentSize = 0;
b2e465d6
AL
1217 unsigned long TotalSize = 0;
1218 if (CheckValidity(SrcCacheFile,Files.begin(),
1219 Files.begin()+EndOfSource) == true)
2d11135a 1220 {
c8e572e3
MV
1221 if (Debug == true)
1222 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
b2e465d6
AL
1223 // Preload the map with the source cache
1224 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
c8e572e3 1225 unsigned long const alloc = Map->RawAllocate(SCacheF.Size());
eb162ff7
DK
1226 if ((alloc == 0 && _error->PendingError())
1227 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
1228 SCacheF.Size()) == false)
b2e465d6
AL
1229 return false;
1230
1231 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
c8e572e3 1232
b2e465d6 1233 // Build the status cache
2e5f4e45 1234 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1235 if (_error->PendingError() == true)
b2e465d6
AL
1236 return false;
1237 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1238 Files.begin()+EndOfSource,Files.end()) == false)
1239 return false;
25396fb0
DK
1240
1241 // FIXME: move me to a better place
1242 Gen.FinishCache(Progress);
b2e465d6
AL
1243 }
1244 else
2d11135a 1245 {
c8e572e3
MV
1246 if (Debug == true)
1247 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
b2e465d6 1248 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 1249
b2e465d6 1250 // Build the source cache
2e5f4e45 1251 pkgCacheGenerator Gen(Map.Get(),Progress);
b2e465d6
AL
1252 if (_error->PendingError() == true)
1253 return false;
1254 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1255 Files.begin(),Files.begin()+EndOfSource) == false)
1256 return false;
2d11135a 1257
b2e465d6
AL
1258 // Write it back
1259 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 1260 {
22041bd2 1261 FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic);
b2e465d6
AL
1262 if (_error->PendingError() == true)
1263 return false;
7a3c2ab0
AL
1264
1265 fchmod(SCacheF.Fd(),0644);
1266
b2e465d6
AL
1267 // Write out the main data
1268 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1269 return _error->Error(_("IO Error saving source cache"));
1270 SCacheF.Sync();
1271
1272 // Write out the proper header
1273 Gen.GetCache().HeaderP->Dirty = false;
1274 if (SCacheF.Seek(0) == false ||
1275 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
1276 return _error->Error(_("IO Error saving source cache"));
b2e465d6 1277 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 1278 SCacheF.Sync();
2d11135a
AL
1279 }
1280
b2e465d6
AL
1281 // Build the status cache
1282 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1283 Files.begin()+EndOfSource,Files.end()) == false)
1284 return false;
25396fb0
DK
1285
1286 // FIXME: move me to a better place
1287 Gen.FinishCache(Progress);
2d11135a 1288 }
c8e572e3
MV
1289 if (Debug == true)
1290 std::clog << "Caches are ready for shipping" << std::endl;
2d11135a 1291
b2e465d6
AL
1292 if (_error->PendingError() == true)
1293 return false;
1294 if (OutMap != 0)
2d11135a 1295 {
b2e465d6 1296 if (CacheF != 0)
2d11135a 1297 {
b2e465d6 1298 delete Map.UnGuard();
eb162ff7 1299 *OutMap = new MMap(*CacheF,0);
2d11135a 1300 }
b2e465d6
AL
1301 else
1302 {
1303 *OutMap = Map.UnGuard();
1304 }
2d11135a
AL
1305 }
1306
b2e465d6
AL
1307 return true;
1308}
1309 /*}}}*/
2e5f4e45 1310// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
b2e465d6
AL
1311// ---------------------------------------------------------------------
1312/* */
2e5f4e45
DK
1313__deprecated bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
1314 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1315bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
b2e465d6 1316{
b2e465d6
AL
1317 vector<pkgIndexFile *> Files;
1318 unsigned long EndOfSource = Files.size();
1319 if (_system->AddStatusFiles(Files) == false)
1320 return false;
dcdf1ef1
DK
1321
1322 SPtr<DynamicMMap> Map = CreateDynamicMMap(NULL);
b2e465d6
AL
1323 unsigned long CurrentSize = 0;
1324 unsigned long TotalSize = 0;
1325
1326 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1327
1328 // Build the status cache
2e5f4e45
DK
1329 if (Progress != NULL)
1330 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1331 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1332 if (_error->PendingError() == true)
b2e465d6
AL
1333 return false;
1334 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1335 Files.begin()+EndOfSource,Files.end()) == false)
1336 return false;
25396fb0
DK
1337
1338 // FIXME: move me to a better place
1339 Gen.FinishCache(Progress);
1340
b2e465d6
AL
1341 if (_error->PendingError() == true)
1342 return false;
1343 *OutMap = Map.UnGuard();
2d11135a 1344
b2e465d6 1345 return true;
2d11135a
AL
1346}
1347 /*}}}*/