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