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