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