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