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