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