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