]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
doesn't use a default separator in ExplodeString (halfway losted in merge)
[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>
5c0d3668 25#include <apt-pkg/macros.h>
578bfd0a 26
afb1e2e3
MV
27#include <apt-pkg/tagfile.h>
28
b2e465d6 29#include <apti18n.h>
e7b470ee
AL
30
31#include <vector>
32
578bfd0a
AL
33#include <sys/stat.h>
34#include <unistd.h>
803fafcb 35#include <errno.h>
7ef72446 36#include <stdio.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{
c8e572e3 811 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
b2e465d6
AL
812 // No file, certainly invalid
813 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
c8e572e3
MV
814 {
815 if (Debug == true)
816 std::clog << "CacheFile doesn't exist" << std::endl;
b35d2f5f 817 return false;
c8e572e3
MV
818 }
819
b2e465d6 820 // Map it
b35d2f5f 821 FileFd CacheF(CacheFile,FileFd::ReadOnly);
eb162ff7 822 SPtr<MMap> Map = new MMap(CacheF,0);
b35d2f5f 823 pkgCache Cache(Map);
b2e465d6 824 if (_error->PendingError() == true || Map->Size() == 0)
b35d2f5f 825 {
c8e572e3
MV
826 if (Debug == true)
827 std::clog << "Errors are pending or Map is empty()" << std::endl;
b35d2f5f
AL
828 _error->Discard();
829 return false;
830 }
b35d2f5f 831
b2e465d6
AL
832 /* Now we check every index file, see if it is in the cache,
833 verify the IMS data and check that it is on the disk too.. */
834 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
835 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
836 for (; Start != End; Start++)
c8e572e3
MV
837 {
838 if (Debug == true)
839 std::clog << "Checking PkgFile " << (*Start)->Describe() << ": ";
b2e465d6 840 if ((*Start)->HasPackages() == false)
c8e572e3
MV
841 {
842 if (Debug == true)
843 std::clog << "Has NO packages" << std::endl;
b2e465d6 844 continue;
c8e572e3 845 }
a77ad7c3 846
b2e465d6 847 if ((*Start)->Exists() == false)
b35d2f5f 848 {
a791a450 849#if 0 // mvo: we no longer give a message here (Default Sources spec)
b2e465d6
AL
850 _error->WarningE("stat",_("Couldn't stat source package list %s"),
851 (*Start)->Describe().c_str());
a791a450 852#endif
c8e572e3
MV
853 if (Debug == true)
854 std::clog << "file doesn't exist" << std::endl;
b2e465d6 855 continue;
b35d2f5f 856 }
b2e465d6
AL
857
858 // FindInCache is also expected to do an IMS check.
859 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
860 if (File.end() == true)
c8e572e3
MV
861 {
862 if (Debug == true)
863 std::clog << "FindInCache returned end-Pointer" << std::endl;
b35d2f5f 864 return false;
c8e572e3 865 }
a52f938b 866
b2e465d6 867 Visited[File->ID] = true;
c8e572e3
MV
868 if (Debug == true)
869 std::clog << "with ID " << File->ID << " is valid" << std::endl;
b35d2f5f
AL
870 }
871
b2e465d6
AL
872 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
873 if (Visited[I] == false)
c8e572e3
MV
874 {
875 if (Debug == true)
876 std::clog << "File with ID" << I << " wasn't visited" << std::endl;
b2e465d6 877 return false;
c8e572e3 878 }
b35d2f5f 879
b35d2f5f
AL
880 if (_error->PendingError() == true)
881 {
c8e572e3
MV
882 if (Debug == true)
883 {
884 std::clog << "Validity failed because of pending errors:" << std::endl;
885 _error->DumpErrors();
886 }
b35d2f5f
AL
887 _error->Discard();
888 return false;
889 }
b35d2f5f 890
b2e465d6
AL
891 if (OutMap != 0)
892 *OutMap = Map.UnGuard();
b35d2f5f
AL
893 return true;
894}
895 /*}}}*/
b2e465d6 896// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 897// ---------------------------------------------------------------------
b2e465d6
AL
898/* Size is kind of an abstract notion that is only used for the progress
899 meter */
e7b470ee 900static unsigned long ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 901{
b2e465d6
AL
902 unsigned long TotalSize = 0;
903 for (; Start != End; Start++)
b35d2f5f 904 {
b2e465d6
AL
905 if ((*Start)->HasPackages() == false)
906 continue;
907 TotalSize += (*Start)->Size();
b35d2f5f 908 }
b2e465d6 909 return TotalSize;
2d11135a
AL
910}
911 /*}}}*/
b2e465d6 912// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 913// ---------------------------------------------------------------------
b2e465d6
AL
914/* */
915static bool BuildCache(pkgCacheGenerator &Gen,
916 OpProgress &Progress,
917 unsigned long &CurrentSize,unsigned long TotalSize,
e7b470ee 918 FileIterator Start, FileIterator End)
2d11135a 919{
45415543
AL
920 FileIterator I;
921 for (I = Start; I != End; I++)
2d11135a 922 {
45415543 923 if ((*I)->HasPackages() == false)
2d11135a
AL
924 continue;
925
45415543 926 if ((*I)->Exists() == false)
2d11135a 927 continue;
b2e465d6 928
45415543 929 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
a77ad7c3
AL
930 {
931 _error->Warning("Duplicate sources.list entry %s",
45415543 932 (*I)->Describe().c_str());
a77ad7c3
AL
933 continue;
934 }
935
45415543 936 unsigned long Size = (*I)->Size();
db0db9fe 937 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
b2e465d6 938 CurrentSize += Size;
2d11135a 939
45415543 940 if ((*I)->Merge(Gen,Progress) == false)
b2e465d6
AL
941 return false;
942 }
45415543
AL
943
944 if (Gen.HasFileDeps() == true)
945 {
946 Progress.Done();
947 TotalSize = ComputeSize(Start, End);
948 CurrentSize = 0;
949 for (I = Start; I != End; I++)
950 {
951 unsigned long Size = (*I)->Size();
952 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
953 CurrentSize += Size;
954 if ((*I)->MergeFileProvides(Gen,Progress) == false)
955 return false;
956 }
957 }
2d11135a 958
b35d2f5f
AL
959 return true;
960}
961 /*}}}*/
b2e465d6 962// MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 963// ---------------------------------------------------------------------
b2e465d6
AL
964/* This makes sure that the status cache (the cache that has all
965 index files from the sources list and all local ones) is ready
966 to be mmaped. If OutMap is not zero then a MMap object representing
967 the cache will be stored there. This is pretty much mandetory if you
968 are using AllowMem. AllowMem lets the function be run as non-root
969 where it builds the cache 'fast' into a memory buffer. */
970bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
971 MMap **OutMap,bool AllowMem)
b35d2f5f 972{
c8e572e3
MV
973 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
974 unsigned long const MapSize = _config->FindI("APT::Cache-Limit",24*1024*1024);
67db871e 975
7db98ffc
MZ
976 vector<pkgIndexFile *> Files;
977 for (vector<metaIndex *>::const_iterator i = List.begin();
978 i != List.end();
979 i++)
980 {
981 vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
982 for (vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
983 j != Indexes->end();
984 j++)
985 Files.push_back (*j);
986 }
987
c8e572e3 988 unsigned long const EndOfSource = Files.size();
b2e465d6
AL
989 if (_system->AddStatusFiles(Files) == false)
990 return false;
c5f44afc 991
b2e465d6 992 // Decide if we can write to the files..
c8e572e3
MV
993 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
994 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
b2e465d6
AL
995
996 // Decide if we can write to the cache
997 bool Writeable = false;
998 if (CacheFile.empty() == false)
999 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1000 else
1001 if (SrcCacheFile.empty() == false)
1002 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
c8e572e3
MV
1003 if (Debug == true)
1004 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1005
b2e465d6
AL
1006 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
1007 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
1008
db0db9fe 1009 Progress.OverallProgress(0,1,1,_("Reading package lists"));
b2e465d6
AL
1010
1011 // Cache is OK, Fin.
1012 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
1013 {
db0db9fe 1014 Progress.OverallProgress(1,1,1,_("Reading package lists"));
c8e572e3
MV
1015 if (Debug == true)
1016 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
b2e465d6
AL
1017 return true;
1018 }
c8e572e3
MV
1019 else if (Debug == true)
1020 std::clog << "pkgcache.bin is NOT valid" << std::endl;
b2e465d6
AL
1021
1022 /* At this point we know we need to reconstruct the package cache,
1023 begin. */
1024 SPtr<FileFd> CacheF;
1025 SPtr<DynamicMMap> Map;
1026 if (Writeable == true && CacheFile.empty() == false)
1027 {
1028 unlink(CacheFile.c_str());
1029 CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
7a3c2ab0 1030 fchmod(CacheF->Fd(),0644);
b2e465d6 1031 Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
b35d2f5f
AL
1032 if (_error->PendingError() == true)
1033 return false;
c8e572e3
MV
1034 if (Debug == true)
1035 std::clog << "Open filebased MMap" << std::endl;
b35d2f5f 1036 }
b2e465d6 1037 else
8ce4327b 1038 {
b2e465d6 1039 // Just build it in memory..
eb162ff7 1040 Map = new DynamicMMap(0,MapSize);
c8e572e3
MV
1041 if (Debug == true)
1042 std::clog << "Open memory Map (not filebased)" << std::endl;
8ce4327b 1043 }
b35d2f5f 1044
b2e465d6 1045 // Lets try the source cache.
b35d2f5f 1046 unsigned long CurrentSize = 0;
b2e465d6
AL
1047 unsigned long TotalSize = 0;
1048 if (CheckValidity(SrcCacheFile,Files.begin(),
1049 Files.begin()+EndOfSource) == true)
2d11135a 1050 {
c8e572e3
MV
1051 if (Debug == true)
1052 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
b2e465d6
AL
1053 // Preload the map with the source cache
1054 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
c8e572e3 1055 unsigned long const alloc = Map->RawAllocate(SCacheF.Size());
eb162ff7
DK
1056 if ((alloc == 0 && _error->PendingError())
1057 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
1058 SCacheF.Size()) == false)
b2e465d6
AL
1059 return false;
1060
1061 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
c8e572e3 1062
b2e465d6
AL
1063 // Build the status cache
1064 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 1065 if (_error->PendingError() == true)
b2e465d6
AL
1066 return false;
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);
b2e465d6
AL
1073 }
1074 else
2d11135a 1075 {
c8e572e3
MV
1076 if (Debug == true)
1077 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
b2e465d6 1078 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 1079
b2e465d6
AL
1080 // Build the source cache
1081 pkgCacheGenerator Gen(Map.Get(),&Progress);
1082 if (_error->PendingError() == true)
1083 return false;
1084 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1085 Files.begin(),Files.begin()+EndOfSource) == false)
1086 return false;
2d11135a 1087
b2e465d6
AL
1088 // Write it back
1089 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 1090 {
b2e465d6
AL
1091 FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
1092 if (_error->PendingError() == true)
1093 return false;
7a3c2ab0
AL
1094
1095 fchmod(SCacheF.Fd(),0644);
1096
b2e465d6
AL
1097 // Write out the main data
1098 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1099 return _error->Error(_("IO Error saving source cache"));
1100 SCacheF.Sync();
1101
1102 // Write out the proper header
1103 Gen.GetCache().HeaderP->Dirty = false;
1104 if (SCacheF.Seek(0) == false ||
1105 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
1106 return _error->Error(_("IO Error saving source cache"));
b2e465d6 1107 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 1108 SCacheF.Sync();
2d11135a
AL
1109 }
1110
b2e465d6
AL
1111 // Build the status cache
1112 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1113 Files.begin()+EndOfSource,Files.end()) == false)
1114 return false;
25396fb0
DK
1115
1116 // FIXME: move me to a better place
1117 Gen.FinishCache(Progress);
2d11135a 1118 }
c8e572e3
MV
1119 if (Debug == true)
1120 std::clog << "Caches are ready for shipping" << std::endl;
2d11135a 1121
b2e465d6
AL
1122 if (_error->PendingError() == true)
1123 return false;
1124 if (OutMap != 0)
2d11135a 1125 {
b2e465d6 1126 if (CacheF != 0)
2d11135a 1127 {
b2e465d6 1128 delete Map.UnGuard();
eb162ff7 1129 *OutMap = new MMap(*CacheF,0);
2d11135a 1130 }
b2e465d6
AL
1131 else
1132 {
1133 *OutMap = Map.UnGuard();
1134 }
2d11135a
AL
1135 }
1136
b2e465d6
AL
1137 return true;
1138}
1139 /*}}}*/
1140// MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
1141// ---------------------------------------------------------------------
1142/* */
1143bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
1144{
5177f802 1145 unsigned long MapSize = _config->FindI("APT::Cache-Limit",20*1024*1024);
b2e465d6
AL
1146 vector<pkgIndexFile *> Files;
1147 unsigned long EndOfSource = Files.size();
1148 if (_system->AddStatusFiles(Files) == false)
1149 return false;
1150
eb162ff7 1151 SPtr<DynamicMMap> Map = new DynamicMMap(0,MapSize);
b2e465d6
AL
1152 unsigned long CurrentSize = 0;
1153 unsigned long TotalSize = 0;
1154
1155 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1156
1157 // Build the status cache
db0db9fe 1158 Progress.OverallProgress(0,1,1,_("Reading package lists"));
b2e465d6 1159 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 1160 if (_error->PendingError() == true)
b2e465d6
AL
1161 return false;
1162 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1163 Files.begin()+EndOfSource,Files.end()) == false)
1164 return false;
25396fb0
DK
1165
1166 // FIXME: move me to a better place
1167 Gen.FinishCache(Progress);
1168
b2e465d6
AL
1169 if (_error->PendingError() == true)
1170 return false;
1171 *OutMap = Map.UnGuard();
2d11135a 1172
b2e465d6 1173 return true;
2d11135a
AL
1174}
1175 /*}}}*/