]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
* apt-pkg/cdrom.{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;
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. */
171c75f1 919static bool CheckValidity(const string &CacheFile, FileIterator Start,
e7b470ee 920 FileIterator End,MMap **OutMap = 0)
b35d2f5f 921{
c8e572e3 922 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
b2e465d6
AL
923 // No file, certainly invalid
924 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
c8e572e3
MV
925 {
926 if (Debug == true)
927 std::clog << "CacheFile doesn't exist" << std::endl;
b35d2f5f 928 return false;
c8e572e3
MV
929 }
930
b2e465d6 931 // Map it
b35d2f5f 932 FileFd CacheF(CacheFile,FileFd::ReadOnly);
eb162ff7 933 SPtr<MMap> Map = new MMap(CacheF,0);
b35d2f5f 934 pkgCache Cache(Map);
b2e465d6 935 if (_error->PendingError() == true || Map->Size() == 0)
b35d2f5f 936 {
c8e572e3
MV
937 if (Debug == true)
938 std::clog << "Errors are pending or Map is empty()" << std::endl;
b35d2f5f
AL
939 _error->Discard();
940 return false;
941 }
b35d2f5f 942
b2e465d6
AL
943 /* Now we check every index file, see if it is in the cache,
944 verify the IMS data and check that it is on the disk too.. */
945 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
946 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
947 for (; Start != End; Start++)
c8e572e3
MV
948 {
949 if (Debug == true)
950 std::clog << "Checking PkgFile " << (*Start)->Describe() << ": ";
b2e465d6 951 if ((*Start)->HasPackages() == false)
c8e572e3
MV
952 {
953 if (Debug == true)
954 std::clog << "Has NO packages" << std::endl;
b2e465d6 955 continue;
c8e572e3 956 }
a77ad7c3 957
b2e465d6 958 if ((*Start)->Exists() == false)
b35d2f5f 959 {
a791a450 960#if 0 // mvo: we no longer give a message here (Default Sources spec)
b2e465d6
AL
961 _error->WarningE("stat",_("Couldn't stat source package list %s"),
962 (*Start)->Describe().c_str());
a791a450 963#endif
c8e572e3
MV
964 if (Debug == true)
965 std::clog << "file doesn't exist" << std::endl;
b2e465d6 966 continue;
b35d2f5f 967 }
b2e465d6
AL
968
969 // FindInCache is also expected to do an IMS check.
970 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
971 if (File.end() == true)
c8e572e3
MV
972 {
973 if (Debug == true)
974 std::clog << "FindInCache returned end-Pointer" << std::endl;
b35d2f5f 975 return false;
c8e572e3 976 }
a52f938b 977
b2e465d6 978 Visited[File->ID] = true;
c8e572e3
MV
979 if (Debug == true)
980 std::clog << "with ID " << File->ID << " is valid" << std::endl;
b35d2f5f
AL
981 }
982
b2e465d6
AL
983 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
984 if (Visited[I] == false)
c8e572e3
MV
985 {
986 if (Debug == true)
987 std::clog << "File with ID" << I << " wasn't visited" << std::endl;
b2e465d6 988 return false;
c8e572e3 989 }
b35d2f5f 990
b35d2f5f
AL
991 if (_error->PendingError() == true)
992 {
c8e572e3
MV
993 if (Debug == true)
994 {
995 std::clog << "Validity failed because of pending errors:" << std::endl;
996 _error->DumpErrors();
997 }
b35d2f5f
AL
998 _error->Discard();
999 return false;
1000 }
b35d2f5f 1001
b2e465d6
AL
1002 if (OutMap != 0)
1003 *OutMap = Map.UnGuard();
b35d2f5f
AL
1004 return true;
1005}
1006 /*}}}*/
b2e465d6 1007// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 1008// ---------------------------------------------------------------------
b2e465d6
AL
1009/* Size is kind of an abstract notion that is only used for the progress
1010 meter */
e7b470ee 1011static unsigned long ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 1012{
b2e465d6
AL
1013 unsigned long TotalSize = 0;
1014 for (; Start != End; Start++)
b35d2f5f 1015 {
b2e465d6
AL
1016 if ((*Start)->HasPackages() == false)
1017 continue;
1018 TotalSize += (*Start)->Size();
b35d2f5f 1019 }
b2e465d6 1020 return TotalSize;
2d11135a
AL
1021}
1022 /*}}}*/
b2e465d6 1023// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 1024// ---------------------------------------------------------------------
b2e465d6
AL
1025/* */
1026static bool BuildCache(pkgCacheGenerator &Gen,
2e5f4e45 1027 OpProgress *Progress,
b2e465d6 1028 unsigned long &CurrentSize,unsigned long TotalSize,
e7b470ee 1029 FileIterator Start, FileIterator End)
2d11135a 1030{
45415543
AL
1031 FileIterator I;
1032 for (I = Start; I != End; I++)
2d11135a 1033 {
45415543 1034 if ((*I)->HasPackages() == false)
2d11135a
AL
1035 continue;
1036
45415543 1037 if ((*I)->Exists() == false)
2d11135a 1038 continue;
b2e465d6 1039
45415543 1040 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
a77ad7c3
AL
1041 {
1042 _error->Warning("Duplicate sources.list entry %s",
45415543 1043 (*I)->Describe().c_str());
a77ad7c3
AL
1044 continue;
1045 }
1046
45415543 1047 unsigned long Size = (*I)->Size();
2e5f4e45
DK
1048 if (Progress != NULL)
1049 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
b2e465d6 1050 CurrentSize += Size;
2d11135a 1051
45415543 1052 if ((*I)->Merge(Gen,Progress) == false)
b2e465d6
AL
1053 return false;
1054 }
45415543
AL
1055
1056 if (Gen.HasFileDeps() == true)
1057 {
2e5f4e45
DK
1058 if (Progress != NULL)
1059 Progress->Done();
45415543
AL
1060 TotalSize = ComputeSize(Start, End);
1061 CurrentSize = 0;
1062 for (I = Start; I != End; I++)
1063 {
1064 unsigned long Size = (*I)->Size();
2e5f4e45
DK
1065 if (Progress != NULL)
1066 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
45415543
AL
1067 CurrentSize += Size;
1068 if ((*I)->MergeFileProvides(Gen,Progress) == false)
1069 return false;
1070 }
1071 }
2d11135a 1072
b35d2f5f
AL
1073 return true;
1074}
1075 /*}}}*/
dd13742e 1076// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
dcdf1ef1
DK
1077DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) {
1078 unsigned long const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1079 unsigned long const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1080 unsigned long const MapLimit = _config->FindI("APT::Cache-Limit", 0);
1081 Flags |= MMap::Moveable;
1082 if (_config->FindB("APT::Cache-Fallback", false) == true)
1083 Flags |= MMap::Fallback;
1084 if (CacheF != NULL)
1085 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1086 else
1087 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1088}
dd13742e 1089 /*}}}*/
2e5f4e45 1090// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 1091// ---------------------------------------------------------------------
b2e465d6
AL
1092/* This makes sure that the status cache (the cache that has all
1093 index files from the sources list and all local ones) is ready
1094 to be mmaped. If OutMap is not zero then a MMap object representing
1095 the cache will be stored there. This is pretty much mandetory if you
1096 are using AllowMem. AllowMem lets the function be run as non-root
1097 where it builds the cache 'fast' into a memory buffer. */
2e5f4e45
DK
1098__deprecated bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
1099 MMap **OutMap, bool AllowMem)
1100 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1101bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
b2e465d6 1102 MMap **OutMap,bool AllowMem)
b35d2f5f 1103{
c8e572e3 1104 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
67db871e 1105
7db98ffc
MZ
1106 vector<pkgIndexFile *> Files;
1107 for (vector<metaIndex *>::const_iterator i = List.begin();
1108 i != List.end();
1109 i++)
1110 {
1111 vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1112 for (vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
1113 j != Indexes->end();
1114 j++)
1115 Files.push_back (*j);
1116 }
1117
c8e572e3 1118 unsigned long const EndOfSource = Files.size();
b2e465d6
AL
1119 if (_system->AddStatusFiles(Files) == false)
1120 return false;
c5f44afc 1121
b2e465d6 1122 // Decide if we can write to the files..
c8e572e3
MV
1123 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1124 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1cd1c398
DK
1125
1126 // ensure the cache directory exists
1127 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1128 {
1129 string dir = _config->FindDir("Dir::Cache");
1130 size_t const len = dir.size();
1131 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1132 dir = dir.substr(0, len - 5);
1133 if (CacheFile.empty() == false)
1134 CreateDirectory(dir, flNotFile(CacheFile));
1135 if (SrcCacheFile.empty() == false)
1136 CreateDirectory(dir, flNotFile(SrcCacheFile));
1137 }
1138
b2e465d6
AL
1139 // Decide if we can write to the cache
1140 bool Writeable = false;
1141 if (CacheFile.empty() == false)
1142 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1143 else
1144 if (SrcCacheFile.empty() == false)
1145 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
c8e572e3
MV
1146 if (Debug == true)
1147 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1148
b2e465d6
AL
1149 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
1150 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
2e5f4e45
DK
1151
1152 if (Progress != NULL)
1153 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1154
b2e465d6
AL
1155 // Cache is OK, Fin.
1156 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
1157 {
2e5f4e45
DK
1158 if (Progress != NULL)
1159 Progress->OverallProgress(1,1,1,_("Reading package lists"));
c8e572e3
MV
1160 if (Debug == true)
1161 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
b2e465d6
AL
1162 return true;
1163 }
c8e572e3
MV
1164 else if (Debug == true)
1165 std::clog << "pkgcache.bin is NOT valid" << std::endl;
b2e465d6
AL
1166
1167 /* At this point we know we need to reconstruct the package cache,
1168 begin. */
1169 SPtr<FileFd> CacheF;
1170 SPtr<DynamicMMap> Map;
1171 if (Writeable == true && CacheFile.empty() == false)
1172 {
41b4dee4 1173 _error->PushToStack();
b2e465d6 1174 unlink(CacheFile.c_str());
22041bd2 1175 CacheF = new FileFd(CacheFile,FileFd::WriteAtomic);
7a3c2ab0 1176 fchmod(CacheF->Fd(),0644);
dcdf1ef1 1177 Map = CreateDynamicMMap(CacheF, MMap::Public);
b35d2f5f 1178 if (_error->PendingError() == true)
41b4dee4
DK
1179 {
1180 delete CacheF.UnGuard();
1181 delete Map.UnGuard();
1182 if (Debug == true)
1183 std::clog << "Open filebased MMap FAILED" << std::endl;
1184 Writeable = false;
1185 if (AllowMem == false)
1186 {
1187 _error->MergeWithStack();
1188 return false;
1189 }
1190 _error->RevertToStack();
1191 }
1192 else if (Debug == true)
1193 {
1194 _error->MergeWithStack();
c8e572e3 1195 std::clog << "Open filebased MMap" << std::endl;
41b4dee4 1196 }
b35d2f5f 1197 }
41b4dee4 1198 if (Writeable == false || CacheFile.empty() == true)
8ce4327b 1199 {
b2e465d6 1200 // Just build it in memory..
dcdf1ef1 1201 Map = CreateDynamicMMap(NULL);
c8e572e3
MV
1202 if (Debug == true)
1203 std::clog << "Open memory Map (not filebased)" << std::endl;
8ce4327b 1204 }
b35d2f5f 1205
b2e465d6 1206 // Lets try the source cache.
b35d2f5f 1207 unsigned long CurrentSize = 0;
b2e465d6
AL
1208 unsigned long TotalSize = 0;
1209 if (CheckValidity(SrcCacheFile,Files.begin(),
1210 Files.begin()+EndOfSource) == true)
2d11135a 1211 {
c8e572e3
MV
1212 if (Debug == true)
1213 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
b2e465d6
AL
1214 // Preload the map with the source cache
1215 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
c8e572e3 1216 unsigned long const alloc = Map->RawAllocate(SCacheF.Size());
eb162ff7
DK
1217 if ((alloc == 0 && _error->PendingError())
1218 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
1219 SCacheF.Size()) == false)
b2e465d6
AL
1220 return false;
1221
1222 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
c8e572e3 1223
b2e465d6 1224 // Build the status cache
2e5f4e45 1225 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1226 if (_error->PendingError() == true)
b2e465d6
AL
1227 return false;
1228 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1229 Files.begin()+EndOfSource,Files.end()) == false)
1230 return false;
25396fb0
DK
1231
1232 // FIXME: move me to a better place
1233 Gen.FinishCache(Progress);
b2e465d6
AL
1234 }
1235 else
2d11135a 1236 {
c8e572e3
MV
1237 if (Debug == true)
1238 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
b2e465d6 1239 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 1240
b2e465d6 1241 // Build the source cache
2e5f4e45 1242 pkgCacheGenerator Gen(Map.Get(),Progress);
b2e465d6
AL
1243 if (_error->PendingError() == true)
1244 return false;
1245 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1246 Files.begin(),Files.begin()+EndOfSource) == false)
1247 return false;
2d11135a 1248
b2e465d6
AL
1249 // Write it back
1250 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 1251 {
22041bd2 1252 FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic);
b2e465d6
AL
1253 if (_error->PendingError() == true)
1254 return false;
7a3c2ab0
AL
1255
1256 fchmod(SCacheF.Fd(),0644);
1257
b2e465d6
AL
1258 // Write out the main data
1259 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1260 return _error->Error(_("IO Error saving source cache"));
1261 SCacheF.Sync();
1262
1263 // Write out the proper header
1264 Gen.GetCache().HeaderP->Dirty = false;
1265 if (SCacheF.Seek(0) == false ||
1266 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
1267 return _error->Error(_("IO Error saving source cache"));
b2e465d6 1268 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 1269 SCacheF.Sync();
2d11135a
AL
1270 }
1271
b2e465d6
AL
1272 // Build the status cache
1273 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1274 Files.begin()+EndOfSource,Files.end()) == false)
1275 return false;
25396fb0
DK
1276
1277 // FIXME: move me to a better place
1278 Gen.FinishCache(Progress);
2d11135a 1279 }
c8e572e3
MV
1280 if (Debug == true)
1281 std::clog << "Caches are ready for shipping" << std::endl;
2d11135a 1282
b2e465d6
AL
1283 if (_error->PendingError() == true)
1284 return false;
1285 if (OutMap != 0)
2d11135a 1286 {
b2e465d6 1287 if (CacheF != 0)
2d11135a 1288 {
b2e465d6 1289 delete Map.UnGuard();
eb162ff7 1290 *OutMap = new MMap(*CacheF,0);
2d11135a 1291 }
b2e465d6
AL
1292 else
1293 {
1294 *OutMap = Map.UnGuard();
1295 }
2d11135a
AL
1296 }
1297
b2e465d6
AL
1298 return true;
1299}
1300 /*}}}*/
2e5f4e45 1301// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
b2e465d6
AL
1302// ---------------------------------------------------------------------
1303/* */
2e5f4e45
DK
1304__deprecated bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
1305 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1306bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
b2e465d6 1307{
b2e465d6
AL
1308 vector<pkgIndexFile *> Files;
1309 unsigned long EndOfSource = Files.size();
1310 if (_system->AddStatusFiles(Files) == false)
1311 return false;
dcdf1ef1
DK
1312
1313 SPtr<DynamicMMap> Map = CreateDynamicMMap(NULL);
b2e465d6
AL
1314 unsigned long CurrentSize = 0;
1315 unsigned long TotalSize = 0;
1316
1317 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1318
1319 // Build the status cache
2e5f4e45
DK
1320 if (Progress != NULL)
1321 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1322 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1323 if (_error->PendingError() == true)
b2e465d6
AL
1324 return false;
1325 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1326 Files.begin()+EndOfSource,Files.end()) == false)
1327 return false;
25396fb0
DK
1328
1329 // FIXME: move me to a better place
1330 Gen.FinishCache(Progress);
1331
b2e465d6
AL
1332 if (_error->PendingError() == true)
1333 return false;
1334 *OutMap = Map.UnGuard();
2d11135a 1335
b2e465d6 1336 return true;
2d11135a
AL
1337}
1338 /*}}}*/