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