]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
apt-pkg/init.cc
[apt.git] / apt-pkg / pkgcachegen.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
6a3da7a6 3// $Id: pkgcachegen.cc,v 1.50 2001/07/01 22:28:24 jgg 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 /*{{{*/
6c139d6e 13#ifdef __GNUG__
094a497d 14#pragma implementation "apt-pkg/pkgcachegen.h"
6c139d6e
AL
15#endif
16
b2e465d6
AL
17#define APT_COMPATIBILITY 986
18
094a497d
AL
19#include <apt-pkg/pkgcachegen.h>
20#include <apt-pkg/error.h>
21#include <apt-pkg/version.h>
b35d2f5f
AL
22#include <apt-pkg/progress.h>
23#include <apt-pkg/sourcelist.h>
24#include <apt-pkg/configuration.h>
cdcc6d34 25#include <apt-pkg/strutl.h>
b2e465d6
AL
26#include <apt-pkg/sptr.h>
27#include <apt-pkg/pkgsystem.h>
578bfd0a 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>
1ae93c94 37#include <system.h>
578bfd0a 38 /*}}}*/
e7b470ee 39typedef vector<pkgIndexFile *>::iterator FileIterator;
578bfd0a
AL
40
41// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
42// ---------------------------------------------------------------------
43/* We set the diry flag and make sure that is written to the disk */
b2e465d6
AL
44pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
45 Map(*pMap), Cache(pMap,false), Progress(Prog)
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();
578bfd0a 57 Map.RawAllocate(sizeof(pkgCache::Header));
b2e465d6
AL
58 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
59
60 // Starting header
578bfd0a 61 *Cache.HeaderP = pkgCache::Header();
b2e465d6
AL
62 Cache.HeaderP->VerSysName = Map.WriteString(_system->VS->Label);
63 Cache.HeaderP->Architecture = Map.WriteString(_config->Find("APT::Architecture"));
64 Cache.ReMap();
578bfd0a 65 }
b2e465d6
AL
66 else
67 {
68 // Map directly from the existing file
69 Cache.ReMap();
70 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
71 if (Cache.VS != _system->VS)
72 {
73 _error->Error(_("Cache has an incompatible versioning system"));
74 return;
75 }
76 }
77
578bfd0a
AL
78 Cache.HeaderP->Dirty = true;
79 Map.Sync(0,sizeof(pkgCache::Header));
578bfd0a
AL
80}
81 /*}}}*/
82// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
83// ---------------------------------------------------------------------
84/* We sync the data then unset the dirty flag in two steps so as to
85 advoid a problem during a crash */
86pkgCacheGenerator::~pkgCacheGenerator()
87{
88 if (_error->PendingError() == true)
89 return;
90 if (Map.Sync() == false)
91 return;
92
93 Cache.HeaderP->Dirty = false;
94 Map.Sync(0,sizeof(pkgCache::Header));
95}
96 /*}}}*/
97// CacheGenerator::MergeList - Merge the package list /*{{{*/
98// ---------------------------------------------------------------------
99/* This provides the generation of the entries in the cache. Each loop
100 goes through a single package record from the underlying parse engine. */
ddc1d8d0
AL
101bool pkgCacheGenerator::MergeList(ListParser &List,
102 pkgCache::VerIterator *OutVer)
578bfd0a
AL
103{
104 List.Owner = this;
0149949b 105
f9eec0e7 106 unsigned int Counter = 0;
0149949b 107 while (List.Step() == true)
578bfd0a
AL
108 {
109 // Get a pointer to the package structure
9ddf7030 110 string PackageName = List.Package();
65a1e968
AL
111 if (PackageName.empty() == true)
112 return false;
113
9ddf7030 114 pkgCache::PkgIterator Pkg;
8efa2a3b 115 if (NewPackage(Pkg,PackageName) == false)
b2e465d6 116 return _error->Error(_("Error occured while processing %s (NewPackage)"),PackageName.c_str());
a246f2dc 117 Counter++;
ddc1d8d0
AL
118 if (Counter % 100 == 0 && Progress != 0)
119 Progress->Progress(List.Offset());
8ce4327b 120
578bfd0a
AL
121 /* Get a pointer to the version structure. We know the list is sorted
122 so we use that fact in the search. Insertion of new versions is
123 done with correct sorting */
124 string Version = List.Version();
f55a958f
AL
125 if (Version.empty() == true)
126 {
127 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
b2e465d6 128 return _error->Error(_("Error occured while processing %s (UsePackage1)"),PackageName.c_str());
f55a958f
AL
129 continue;
130 }
131
578bfd0a 132 pkgCache::VerIterator Ver = Pkg.VersionList();
349cd3b8 133 map_ptrloc *Last = &Pkg->VersionList;
2246928b 134 int Res = 1;
f55a958f 135 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
578bfd0a 136 {
c24972cb 137 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
578bfd0a
AL
138 if (Res >= 0)
139 break;
140 }
141
142 /* We already have a version for this item, record that we
143 saw it */
204fbdcc
AL
144 unsigned long Hash = List.VersionHash();
145 if (Res == 0 && Ver->Hash == Hash)
578bfd0a 146 {
f55a958f 147 if (List.UsePackage(Pkg,Ver) == false)
b2e465d6 148 return _error->Error(_("Error occured while processing %s (UsePackage2)"),PackageName.c_str());
f78439bf 149
578bfd0a 150 if (NewFileVer(Ver,List) == false)
b2e465d6 151 return _error->Error(_("Error occured while processing %s (NewFileVer1)"),PackageName.c_str());
578bfd0a 152
ddc1d8d0
AL
153 // Read only a single record and return
154 if (OutVer != 0)
155 {
156 *OutVer = Ver;
157 return true;
158 }
159
578bfd0a
AL
160 continue;
161 }
162
204fbdcc
AL
163 // Skip to the end of the same version set.
164 if (Res == 0)
165 {
166 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
167 {
c24972cb 168 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
204fbdcc
AL
169 if (Res != 0)
170 break;
171 }
172 }
173
578bfd0a 174 // Add a new version
f55a958f
AL
175 *Last = NewVersion(Ver,Version,*Last);
176 Ver->ParentPkg = Pkg.Index();
204fbdcc 177 Ver->Hash = Hash;
578bfd0a 178 if (List.NewVersion(Ver) == false)
b2e465d6 179 return _error->Error(_("Error occured while processing %s (NewVersion1)"),PackageName.c_str());
0149949b 180
f55a958f 181 if (List.UsePackage(Pkg,Ver) == false)
b2e465d6 182 return _error->Error(_("Error occured while processing %s (UsePackage3)"),PackageName.c_str());
f55a958f 183
578bfd0a 184 if (NewFileVer(Ver,List) == false)
b2e465d6 185 return _error->Error(_("Error occured while processing %s (NewVersion2)"),PackageName.c_str());
ddc1d8d0
AL
186
187 // Read only a single record and return
188 if (OutVer != 0)
189 {
190 *OutVer = Ver;
191 return true;
192 }
578bfd0a 193 }
0149949b 194
6a3da7a6
AL
195 if (Cache.HeaderP->PackageCount >= (1ULL<<sizeof(Cache.PkgP->ID)*8)-1)
196 return _error->Error(_("Wow, you exceeded the number of package "
197 "names this APT is capable of."));
198 if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
199 return _error->Error(_("Wow, you exceeded the number of versions "
200 "this APT is capable of."));
201 if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
202 return _error->Error(_("Wow, you exceeded the number of dependencies "
203 "this APT is capable of."));
578bfd0a
AL
204 return true;
205}
206 /*}}}*/
207// CacheGenerator::NewPackage - Add a new package /*{{{*/
208// ---------------------------------------------------------------------
209/* This creates a new package structure and adds it to the hash table */
f55a958f 210bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
578bfd0a 211{
8efa2a3b
AL
212 Pkg = Cache.FindPkg(Name);
213 if (Pkg.end() == false)
214 return true;
215
578bfd0a
AL
216 // Get a structure
217 unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
218 if (Package == 0)
219 return false;
220
f55a958f 221 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
578bfd0a
AL
222
223 // Insert it into the hash table
f55a958f 224 unsigned long Hash = Cache.Hash(Name);
578bfd0a
AL
225 Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
226 Cache.HeaderP->HashTable[Hash] = Package;
227
228 // Set the name and the ID
229 Pkg->Name = Map.WriteString(Name);
230 if (Pkg->Name == 0)
231 return false;
232 Pkg->ID = Cache.HeaderP->PackageCount++;
233
234 return true;
235}
236 /*}}}*/
237// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
238// ---------------------------------------------------------------------
239/* */
f55a958f 240bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
578bfd0a
AL
241 ListParser &List)
242{
ddc1d8d0
AL
243 if (CurrentFile == 0)
244 return true;
245
dcb79bae
AL
246 // Get a structure
247 unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
248 if (VerFile == 0)
249 return 0;
250
251 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
252 VF->File = CurrentFile - Cache.PkgFileP;
03e39e59
AL
253
254 // Link it to the end of the list
349cd3b8 255 map_ptrloc *Last = &Ver->FileList;
03e39e59
AL
256 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++)
257 Last = &V->NextFile;
258 VF->NextFile = *Last;
259 *Last = VF.Index();
260
dcb79bae
AL
261 VF->Offset = List.Offset();
262 VF->Size = List.Size();
ad00ae81
AL
263 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
264 Cache.HeaderP->MaxVerFileSize = VF->Size;
a7e66b17
AL
265 Cache.HeaderP->VerFileCount++;
266
f55a958f 267 return true;
578bfd0a
AL
268}
269 /*}}}*/
270// CacheGenerator::NewVersion - Create a new Version /*{{{*/
271// ---------------------------------------------------------------------
f55a958f 272/* This puts a version structure in the linked list */
578bfd0a 273unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
f55a958f 274 string VerStr,
578bfd0a
AL
275 unsigned long Next)
276{
f55a958f
AL
277 // Get a structure
278 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
279 if (Version == 0)
0149949b 280 return 0;
f55a958f
AL
281
282 // Fill it in
283 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
f55a958f
AL
284 Ver->NextVer = Next;
285 Ver->ID = Cache.HeaderP->VersionCount++;
286 Ver->VerStr = Map.WriteString(VerStr);
287 if (Ver->VerStr == 0)
0149949b 288 return 0;
f55a958f 289
0149949b 290 return Version;
578bfd0a
AL
291}
292 /*}}}*/
dcb79bae
AL
293// ListParser::NewDepends - Create a dependency element /*{{{*/
294// ---------------------------------------------------------------------
295/* This creates a dependency element in the tree. It is linked to the
296 version and to the package that it is pointing to. */
297bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
9ddf7030
AL
298 string PackageName,
299 string Version,
dcb79bae
AL
300 unsigned int Op,
301 unsigned int Type)
302{
303 pkgCache &Cache = Owner->Cache;
304
305 // Get a structure
306 unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
307 if (Dependency == 0)
308 return false;
309
310 // Fill it in
311 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
312 Dep->ParentVer = Ver.Index();
313 Dep->Type = Type;
314 Dep->CompareOp = Op;
315 Dep->ID = Cache.HeaderP->DependsCount++;
316
317 // Locate the target package
8efa2a3b
AL
318 pkgCache::PkgIterator Pkg;
319 if (Owner->NewPackage(Pkg,PackageName) == false)
320 return false;
dcb79bae
AL
321
322 // Probe the reverse dependency list for a version string that matches
323 if (Version.empty() == false)
324 {
b2e465d6 325/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
dcb79bae 326 if (I->Version != 0 && I.TargetVer() == Version)
f9eec0e7 327 Dep->Version = I->Version;*/
dcb79bae
AL
328 if (Dep->Version == 0)
329 if ((Dep->Version = WriteString(Version)) == 0)
330 return false;
331 }
c1a22377 332
dcb79bae
AL
333 // Link it to the package
334 Dep->Package = Pkg.Index();
335 Dep->NextRevDepends = Pkg->RevDepends;
336 Pkg->RevDepends = Dep.Index();
337
c1a22377
AL
338 /* Link it to the version (at the end of the list)
339 Caching the old end point speeds up generation substantially */
f9eec0e7 340 if (OldDepVer != Ver)
c1a22377 341 {
f9eec0e7 342 OldDepLast = &Ver->DependsList;
c1a22377 343 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
f9eec0e7
AL
344 OldDepLast = &D->NextDepends;
345 OldDepVer = Ver;
c1a22377 346 }
dcb79bae 347
f9eec0e7
AL
348 Dep->NextDepends = *OldDepLast;
349 *OldDepLast = Dep.Index();
350 OldDepLast = &Dep->NextDepends;
c1a22377 351
dcb79bae
AL
352 return true;
353}
354 /*}}}*/
355// ListParser::NewProvides - Create a Provides element /*{{{*/
356// ---------------------------------------------------------------------
357/* */
358bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
8efa2a3b 359 string PackageName,
9ddf7030 360 string Version)
dcb79bae
AL
361{
362 pkgCache &Cache = Owner->Cache;
8efa2a3b
AL
363
364 // We do not add self referencing provides
365 if (Ver.ParentPkg().Name() == PackageName)
366 return true;
dcb79bae
AL
367
368 // Get a structure
369 unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
370 if (Provides == 0)
371 return false;
a7e66b17 372 Cache.HeaderP->ProvidesCount++;
dcb79bae
AL
373
374 // Fill it in
375 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
376 Prv->Version = Ver.Index();
377 Prv->NextPkgProv = Ver->ProvidesList;
378 Ver->ProvidesList = Prv.Index();
b2e465d6 379 if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
dcb79bae
AL
380 return false;
381
382 // Locate the target package
8efa2a3b
AL
383 pkgCache::PkgIterator Pkg;
384 if (Owner->NewPackage(Pkg,PackageName) == false)
385 return false;
dcb79bae
AL
386
387 // Link it to the package
388 Prv->ParentPkg = Pkg.Index();
389 Prv->NextProvides = Pkg->ProvidesList;
390 Pkg->ProvidesList = Prv.Index();
391
392 return true;
393}
394 /*}}}*/
578bfd0a
AL
395// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
396// ---------------------------------------------------------------------
397/* This is used to select which file is to be associated with all newly
b2e465d6
AL
398 added versions. The caller is responsible for setting the IMS fields. */
399bool pkgCacheGenerator::SelectFile(string File,string Site,
400 const pkgIndexFile &Index,
401 unsigned long Flags)
578bfd0a 402{
578bfd0a
AL
403 // Get some space for the structure
404 CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
405 if (CurrentFile == Cache.PkgFileP)
406 return false;
407
408 // Fill it in
409 CurrentFile->FileName = Map.WriteString(File);
b2e465d6 410 CurrentFile->Site = WriteUniqString(Site);
578bfd0a
AL
411 CurrentFile->NextFile = Cache.HeaderP->FileList;
412 CurrentFile->Flags = Flags;
e1b74f61 413 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
b2e465d6 414 CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label);
578bfd0a 415 PkgFileName = File;
ad00ae81 416 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
b35d2f5f 417 Cache.HeaderP->PackageFileCount++;
b2e465d6 418
578bfd0a
AL
419 if (CurrentFile->FileName == 0)
420 return false;
404ec98e 421
ddc1d8d0 422 if (Progress != 0)
b2e465d6 423 Progress->SubProgress(Index.Size());
8efa2a3b 424 return true;
578bfd0a
AL
425}
426 /*}}}*/
f55a958f
AL
427// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
428// ---------------------------------------------------------------------
429/* This is used to create handles to strings. Given the same text it
430 always returns the same number */
431unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
432 unsigned int Size)
433{
f9eec0e7
AL
434 /* We use a very small transient hash table here, this speeds up generation
435 by a fair amount on slower machines */
436 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
437 if (Bucket != 0 &&
438 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
439 return Bucket->String;
440
f55a958f
AL
441 // Search for an insertion point
442 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
443 int Res = 1;
349cd3b8 444 map_ptrloc *Last = &Cache.HeaderP->StringList;
f55a958f
AL
445 for (; I != Cache.StringItemP; Last = &I->NextItem,
446 I = Cache.StringItemP + I->NextItem)
447 {
9c14e3d6 448 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
f55a958f
AL
449 if (Res >= 0)
450 break;
451 }
452
453 // Match
454 if (Res == 0)
f9eec0e7
AL
455 {
456 Bucket = I;
0149949b 457 return I->String;
f9eec0e7 458 }
f55a958f
AL
459
460 // Get a structure
461 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
462 if (Item == 0)
0149949b
AL
463 return 0;
464
f55a958f
AL
465 // Fill in the structure
466 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
467 ItemP->NextItem = I - Cache.StringItemP;
468 *Last = Item;
469 ItemP->String = Map.WriteString(S,Size);
470 if (ItemP->String == 0)
0149949b 471 return 0;
f55a958f 472
f9eec0e7 473 Bucket = ItemP;
0149949b 474 return ItemP->String;
f55a958f
AL
475}
476 /*}}}*/
b35d2f5f 477
b2e465d6 478// CheckValidity - Check that a cache is up-to-date /*{{{*/
b35d2f5f 479// ---------------------------------------------------------------------
b2e465d6
AL
480/* This just verifies that each file in the list of index files exists,
481 has matching attributes with the cache and the cache does not have
482 any extra files. */
e7b470ee
AL
483static bool CheckValidity(string CacheFile, FileIterator Start,
484 FileIterator End,MMap **OutMap = 0)
b35d2f5f 485{
b2e465d6
AL
486 // No file, certainly invalid
487 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
b35d2f5f
AL
488 return false;
489
b2e465d6 490 // Map it
b35d2f5f 491 FileFd CacheF(CacheFile,FileFd::ReadOnly);
b2e465d6 492 SPtr<MMap> Map = new MMap(CacheF,MMap::Public | MMap::ReadOnly);
b35d2f5f 493 pkgCache Cache(Map);
b2e465d6 494 if (_error->PendingError() == true || Map->Size() == 0)
b35d2f5f
AL
495 {
496 _error->Discard();
497 return false;
498 }
b35d2f5f 499
b2e465d6
AL
500 /* Now we check every index file, see if it is in the cache,
501 verify the IMS data and check that it is on the disk too.. */
502 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
503 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
504 for (; Start != End; Start++)
a77ad7c3 505 {
b2e465d6
AL
506 if ((*Start)->HasPackages() == false)
507 continue;
a77ad7c3 508
b2e465d6 509 if ((*Start)->Exists() == false)
b35d2f5f 510 {
b2e465d6
AL
511 _error->WarningE("stat",_("Couldn't stat source package list %s"),
512 (*Start)->Describe().c_str());
513 continue;
b35d2f5f 514 }
b2e465d6
AL
515
516 // FindInCache is also expected to do an IMS check.
517 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
518 if (File.end() == true)
b35d2f5f 519 return false;
b2e465d6
AL
520
521 Visited[File->ID] = true;
b35d2f5f
AL
522 }
523
b2e465d6
AL
524 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
525 if (Visited[I] == false)
526 return false;
b35d2f5f 527
b35d2f5f
AL
528 if (_error->PendingError() == true)
529 {
530 _error->Discard();
531 return false;
532 }
b35d2f5f 533
b2e465d6
AL
534 if (OutMap != 0)
535 *OutMap = Map.UnGuard();
b35d2f5f
AL
536 return true;
537}
538 /*}}}*/
b2e465d6 539// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 540// ---------------------------------------------------------------------
b2e465d6
AL
541/* Size is kind of an abstract notion that is only used for the progress
542 meter */
e7b470ee 543static unsigned long ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 544{
b2e465d6
AL
545 unsigned long TotalSize = 0;
546 for (; Start != End; Start++)
b35d2f5f 547 {
b2e465d6
AL
548 if ((*Start)->HasPackages() == false)
549 continue;
550 TotalSize += (*Start)->Size();
b35d2f5f 551 }
b2e465d6 552 return TotalSize;
2d11135a
AL
553}
554 /*}}}*/
b2e465d6 555// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 556// ---------------------------------------------------------------------
b2e465d6
AL
557/* */
558static bool BuildCache(pkgCacheGenerator &Gen,
559 OpProgress &Progress,
560 unsigned long &CurrentSize,unsigned long TotalSize,
e7b470ee 561 FileIterator Start, FileIterator End)
2d11135a 562{
b2e465d6 563 for (; Start != End; Start++)
2d11135a 564 {
b2e465d6 565 if ((*Start)->HasPackages() == false)
2d11135a
AL
566 continue;
567
b2e465d6 568 if ((*Start)->Exists() == false)
2d11135a 569 continue;
b2e465d6 570
a77ad7c3
AL
571 if ((*Start)->FindInCache(Gen.GetCache()).end() == false)
572 {
573 _error->Warning("Duplicate sources.list entry %s",
574 (*Start)->Describe().c_str());
575 continue;
576 }
577
b2e465d6
AL
578 unsigned long Size = (*Start)->Size();
579 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists"));
580 CurrentSize += Size;
2d11135a 581
b2e465d6
AL
582 if ((*Start)->Merge(Gen,Progress) == false)
583 return false;
584 }
2d11135a 585
b35d2f5f
AL
586 return true;
587}
588 /*}}}*/
b2e465d6 589// MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 590// ---------------------------------------------------------------------
b2e465d6
AL
591/* This makes sure that the status cache (the cache that has all
592 index files from the sources list and all local ones) is ready
593 to be mmaped. If OutMap is not zero then a MMap object representing
594 the cache will be stored there. This is pretty much mandetory if you
595 are using AllowMem. AllowMem lets the function be run as non-root
596 where it builds the cache 'fast' into a memory buffer. */
597bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
598 MMap **OutMap,bool AllowMem)
b35d2f5f 599{
a77ad7c3 600 unsigned long MapSize = _config->FindI("APT::Cache-Limit",6*1024*1024);
67db871e 601
b2e465d6
AL
602 vector<pkgIndexFile *> Files(List.begin(),List.end());
603 unsigned long EndOfSource = Files.size();
604 if (_system->AddStatusFiles(Files) == false)
605 return false;
8ce4327b 606
b2e465d6 607 // Decide if we can write to the files..
3b5421b4 608 string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
b2e465d6
AL
609 string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
610
611 // Decide if we can write to the cache
612 bool Writeable = false;
613 if (CacheFile.empty() == false)
614 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
615 else
616 if (SrcCacheFile.empty() == false)
617 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
618
619 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
620 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
621
622 Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
623
624 // Cache is OK, Fin.
625 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
626 {
627 Progress.OverallProgress(1,1,1,_("Reading Package Lists"));
628 return true;
629 }
630
631 /* At this point we know we need to reconstruct the package cache,
632 begin. */
633 SPtr<FileFd> CacheF;
634 SPtr<DynamicMMap> Map;
635 if (Writeable == true && CacheFile.empty() == false)
636 {
637 unlink(CacheFile.c_str());
638 CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
639 Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
b35d2f5f
AL
640 if (_error->PendingError() == true)
641 return false;
b35d2f5f 642 }
b2e465d6 643 else
8ce4327b 644 {
b2e465d6
AL
645 // Just build it in memory..
646 Map = new DynamicMMap(MMap::Public,MapSize);
8ce4327b 647 }
b35d2f5f 648
b2e465d6 649 // Lets try the source cache.
b35d2f5f 650 unsigned long CurrentSize = 0;
b2e465d6
AL
651 unsigned long TotalSize = 0;
652 if (CheckValidity(SrcCacheFile,Files.begin(),
653 Files.begin()+EndOfSource) == true)
2d11135a 654 {
b2e465d6
AL
655 // Preload the map with the source cache
656 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
657 if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
658 SCacheF.Size()) == false)
659 return false;
660
661 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
2d11135a 662
b2e465d6
AL
663 // Build the status cache
664 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 665 if (_error->PendingError() == true)
b2e465d6
AL
666 return false;
667 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
668 Files.begin()+EndOfSource,Files.end()) == false)
669 return false;
670 }
671 else
2d11135a 672 {
b2e465d6 673 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 674
b2e465d6
AL
675 // Build the source cache
676 pkgCacheGenerator Gen(Map.Get(),&Progress);
677 if (_error->PendingError() == true)
678 return false;
679 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
680 Files.begin(),Files.begin()+EndOfSource) == false)
681 return false;
2d11135a 682
b2e465d6
AL
683 // Write it back
684 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 685 {
b2e465d6
AL
686 FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
687 if (_error->PendingError() == true)
688 return false;
689 // Write out the main data
690 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
691 return _error->Error(_("IO Error saving source cache"));
692 SCacheF.Sync();
693
694 // Write out the proper header
695 Gen.GetCache().HeaderP->Dirty = false;
696 if (SCacheF.Seek(0) == false ||
697 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
698 return _error->Error(_("IO Error saving source cache"));
699 SCacheF.Sync();
700 Gen.GetCache().HeaderP->Dirty = true;
2d11135a
AL
701 }
702
b2e465d6
AL
703 // Build the status cache
704 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
705 Files.begin()+EndOfSource,Files.end()) == false)
706 return false;
2d11135a
AL
707 }
708
b2e465d6
AL
709 if (_error->PendingError() == true)
710 return false;
711 if (OutMap != 0)
2d11135a 712 {
b2e465d6 713 if (CacheF != 0)
2d11135a 714 {
b2e465d6
AL
715 delete Map.UnGuard();
716 *OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly);
2d11135a 717 }
b2e465d6
AL
718 else
719 {
720 *OutMap = Map.UnGuard();
721 }
2d11135a
AL
722 }
723
b2e465d6
AL
724 return true;
725}
726 /*}}}*/
727// MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
728// ---------------------------------------------------------------------
729/* */
730bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
731{
732 unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
733 vector<pkgIndexFile *> Files;
734 unsigned long EndOfSource = Files.size();
735 if (_system->AddStatusFiles(Files) == false)
736 return false;
737
738 SPtr<DynamicMMap> Map;
739 Map = new DynamicMMap(MMap::Public,MapSize);
740 unsigned long CurrentSize = 0;
741 unsigned long TotalSize = 0;
742
743 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
744
745 // Build the status cache
746 Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
747 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 748 if (_error->PendingError() == true)
b2e465d6
AL
749 return false;
750 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
751 Files.begin()+EndOfSource,Files.end()) == false)
752 return false;
2d11135a 753
b2e465d6
AL
754 if (_error->PendingError() == true)
755 return false;
756 *OutMap = Map.UnGuard();
2d11135a 757
b2e465d6 758 return true;
2d11135a
AL
759}
760 /*}}}*/