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