]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
* merged with mainline
[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 /*{{{*/
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)
6804503b 117 return _error->Error(_("Error occurred 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)
6804503b 129 return _error->Error(_("Error occurred while processing %s (UsePackage1)"),
7a3c2ab0 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)
6804503b 150 return _error->Error(_("Error occurred while processing %s (UsePackage2)"),
7a3c2ab0 151 PackageName.c_str());
f78439bf 152
578bfd0a 153 if (NewFileVer(Ver,List) == false)
6804503b 154 return _error->Error(_("Error occurred while processing %s (NewFileVer1)"),
7a3c2ab0 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)
6804503b 184 return _error->Error(_("Error occurred while processing %s (NewVersion1)"),
7a3c2ab0 185 PackageName.c_str());
0149949b 186
f55a958f 187 if (List.UsePackage(Pkg,Ver) == false)
6804503b 188 return _error->Error(_("Error occurred while processing %s (UsePackage3)"),
7a3c2ab0 189 PackageName.c_str());
f55a958f 190
578bfd0a 191 if (NewFileVer(Ver,List) == false)
6804503b 192 return _error->Error(_("Error occurred while processing %s (NewVersion2)"),
7a3c2ab0 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)
6804503b 241 return _error->Error(_("Error occurred while processing %s (FindPkg)"),
45415543
AL
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)
6804503b 254 return _error->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName.c_str());
45415543
AL
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 */
171c75f1 269bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const 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,
171c75f1 333 const 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,
171c75f1
MV
357 const string &PackageName,
358 const 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,
171c75f1
MV
422 const string &PackageName,
423 const 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 461 added versions. The caller is responsible for setting the IMS fields. */
171c75f1 462bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
b2e465d6
AL
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. */
171c75f1 546static bool CheckValidity(const string &CacheFile, FileIterator Start,
e7b470ee 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 {
a791a450 574#if 0 // mvo: we no longer give a message here (Default Sources spec)
b2e465d6
AL
575 _error->WarningE("stat",_("Couldn't stat source package list %s"),
576 (*Start)->Describe().c_str());
a791a450 577#endif
b2e465d6 578 continue;
b35d2f5f 579 }
b2e465d6
AL
580
581 // FindInCache is also expected to do an IMS check.
582 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
583 if (File.end() == true)
b35d2f5f 584 return false;
b2e465d6
AL
585
586 Visited[File->ID] = true;
b35d2f5f
AL
587 }
588
b2e465d6
AL
589 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
590 if (Visited[I] == false)
591 return false;
b35d2f5f 592
b35d2f5f
AL
593 if (_error->PendingError() == true)
594 {
595 _error->Discard();
596 return false;
597 }
b35d2f5f 598
b2e465d6
AL
599 if (OutMap != 0)
600 *OutMap = Map.UnGuard();
b35d2f5f
AL
601 return true;
602}
603 /*}}}*/
b2e465d6 604// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 605// ---------------------------------------------------------------------
b2e465d6
AL
606/* Size is kind of an abstract notion that is only used for the progress
607 meter */
e7b470ee 608static unsigned long ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 609{
b2e465d6
AL
610 unsigned long TotalSize = 0;
611 for (; Start != End; Start++)
b35d2f5f 612 {
b2e465d6
AL
613 if ((*Start)->HasPackages() == false)
614 continue;
615 TotalSize += (*Start)->Size();
b35d2f5f 616 }
b2e465d6 617 return TotalSize;
2d11135a
AL
618}
619 /*}}}*/
b2e465d6 620// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 621// ---------------------------------------------------------------------
b2e465d6
AL
622/* */
623static bool BuildCache(pkgCacheGenerator &Gen,
624 OpProgress &Progress,
625 unsigned long &CurrentSize,unsigned long TotalSize,
e7b470ee 626 FileIterator Start, FileIterator End)
2d11135a 627{
45415543
AL
628 FileIterator I;
629 for (I = Start; I != End; I++)
2d11135a 630 {
45415543 631 if ((*I)->HasPackages() == false)
2d11135a
AL
632 continue;
633
45415543 634 if ((*I)->Exists() == false)
2d11135a 635 continue;
b2e465d6 636
45415543 637 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
a77ad7c3
AL
638 {
639 _error->Warning("Duplicate sources.list entry %s",
45415543 640 (*I)->Describe().c_str());
a77ad7c3
AL
641 continue;
642 }
643
45415543 644 unsigned long Size = (*I)->Size();
db0db9fe 645 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
b2e465d6 646 CurrentSize += Size;
2d11135a 647
45415543 648 if ((*I)->Merge(Gen,Progress) == false)
b2e465d6
AL
649 return false;
650 }
45415543
AL
651
652 if (Gen.HasFileDeps() == true)
653 {
654 Progress.Done();
655 TotalSize = ComputeSize(Start, End);
656 CurrentSize = 0;
657 for (I = Start; I != End; I++)
658 {
659 unsigned long Size = (*I)->Size();
660 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
661 CurrentSize += Size;
662 if ((*I)->MergeFileProvides(Gen,Progress) == false)
663 return false;
664 }
665 }
2d11135a 666
b35d2f5f
AL
667 return true;
668}
669 /*}}}*/
b2e465d6 670// MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 671// ---------------------------------------------------------------------
b2e465d6
AL
672/* This makes sure that the status cache (the cache that has all
673 index files from the sources list and all local ones) is ready
674 to be mmaped. If OutMap is not zero then a MMap object representing
675 the cache will be stored there. This is pretty much mandetory if you
676 are using AllowMem. AllowMem lets the function be run as non-root
677 where it builds the cache 'fast' into a memory buffer. */
678bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
679 MMap **OutMap,bool AllowMem)
b35d2f5f 680{
ac13a427 681 unsigned long MapSize = _config->FindI("APT::Cache-Limit",12*1024*1024);
67db871e 682
7db98ffc
MZ
683 vector<pkgIndexFile *> Files;
684 for (vector<metaIndex *>::const_iterator i = List.begin();
685 i != List.end();
686 i++)
687 {
688 vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
689 for (vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
690 j != Indexes->end();
691 j++)
692 Files.push_back (*j);
693 }
694
b2e465d6
AL
695 unsigned long EndOfSource = Files.size();
696 if (_system->AddStatusFiles(Files) == false)
697 return false;
8ce4327b 698
b2e465d6 699 // Decide if we can write to the files..
3b5421b4 700 string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
b2e465d6
AL
701 string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
702
703 // Decide if we can write to the cache
704 bool Writeable = false;
705 if (CacheFile.empty() == false)
706 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
707 else
708 if (SrcCacheFile.empty() == false)
709 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
710
711 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
712 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
713
db0db9fe 714 Progress.OverallProgress(0,1,1,_("Reading package lists"));
b2e465d6
AL
715
716 // Cache is OK, Fin.
717 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
718 {
db0db9fe 719 Progress.OverallProgress(1,1,1,_("Reading package lists"));
b2e465d6
AL
720 return true;
721 }
722
723 /* At this point we know we need to reconstruct the package cache,
724 begin. */
725 SPtr<FileFd> CacheF;
726 SPtr<DynamicMMap> Map;
727 if (Writeable == true && CacheFile.empty() == false)
728 {
729 unlink(CacheFile.c_str());
730 CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
7a3c2ab0 731 fchmod(CacheF->Fd(),0644);
b2e465d6 732 Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
b35d2f5f
AL
733 if (_error->PendingError() == true)
734 return false;
b35d2f5f 735 }
b2e465d6 736 else
8ce4327b 737 {
b2e465d6
AL
738 // Just build it in memory..
739 Map = new DynamicMMap(MMap::Public,MapSize);
8ce4327b 740 }
b35d2f5f 741
b2e465d6 742 // Lets try the source cache.
b35d2f5f 743 unsigned long CurrentSize = 0;
b2e465d6
AL
744 unsigned long TotalSize = 0;
745 if (CheckValidity(SrcCacheFile,Files.begin(),
746 Files.begin()+EndOfSource) == true)
2d11135a 747 {
b2e465d6
AL
748 // Preload the map with the source cache
749 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
750 if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
751 SCacheF.Size()) == false)
752 return false;
753
754 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
2d11135a 755
b2e465d6
AL
756 // Build the status cache
757 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 758 if (_error->PendingError() == true)
b2e465d6
AL
759 return false;
760 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
761 Files.begin()+EndOfSource,Files.end()) == false)
762 return false;
763 }
764 else
2d11135a 765 {
b2e465d6 766 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 767
b2e465d6
AL
768 // Build the source cache
769 pkgCacheGenerator Gen(Map.Get(),&Progress);
770 if (_error->PendingError() == true)
771 return false;
772 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
773 Files.begin(),Files.begin()+EndOfSource) == false)
774 return false;
2d11135a 775
b2e465d6
AL
776 // Write it back
777 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 778 {
b2e465d6
AL
779 FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
780 if (_error->PendingError() == true)
781 return false;
7a3c2ab0
AL
782
783 fchmod(SCacheF.Fd(),0644);
784
b2e465d6
AL
785 // Write out the main data
786 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
787 return _error->Error(_("IO Error saving source cache"));
788 SCacheF.Sync();
789
790 // Write out the proper header
791 Gen.GetCache().HeaderP->Dirty = false;
792 if (SCacheF.Seek(0) == false ||
793 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
794 return _error->Error(_("IO Error saving source cache"));
b2e465d6 795 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 796 SCacheF.Sync();
2d11135a
AL
797 }
798
b2e465d6
AL
799 // Build the status cache
800 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
801 Files.begin()+EndOfSource,Files.end()) == false)
802 return false;
2d11135a
AL
803 }
804
b2e465d6
AL
805 if (_error->PendingError() == true)
806 return false;
807 if (OutMap != 0)
2d11135a 808 {
b2e465d6 809 if (CacheF != 0)
2d11135a 810 {
b2e465d6
AL
811 delete Map.UnGuard();
812 *OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly);
2d11135a 813 }
b2e465d6
AL
814 else
815 {
816 *OutMap = Map.UnGuard();
817 }
2d11135a
AL
818 }
819
b2e465d6
AL
820 return true;
821}
822 /*}}}*/
823// MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
824// ---------------------------------------------------------------------
825/* */
826bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
827{
ac13a427 828 unsigned long MapSize = _config->FindI("APT::Cache-Limit",8*1024*1024);
b2e465d6
AL
829 vector<pkgIndexFile *> Files;
830 unsigned long EndOfSource = Files.size();
831 if (_system->AddStatusFiles(Files) == false)
832 return false;
833
834 SPtr<DynamicMMap> Map;
835 Map = new DynamicMMap(MMap::Public,MapSize);
836 unsigned long CurrentSize = 0;
837 unsigned long TotalSize = 0;
838
839 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
840
841 // Build the status cache
db0db9fe 842 Progress.OverallProgress(0,1,1,_("Reading package lists"));
b2e465d6 843 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 844 if (_error->PendingError() == true)
b2e465d6
AL
845 return false;
846 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
847 Files.begin()+EndOfSource,Files.end()) == false)
848 return false;
2d11135a 849
b2e465d6
AL
850 if (_error->PendingError() == true)
851 return false;
852 *OutMap = Map.UnGuard();
2d11135a 853
b2e465d6 854 return true;
2d11135a
AL
855}
856 /*}}}*/