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