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