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