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