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