]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
Implement the first step toward Multi-Arch by setting up a Group
[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
5bf15716 111 string const PackageName = List.Package();
65a1e968
AL
112 if (PackageName.empty() == true)
113 return false;
5bf15716 114
9ddf7030 115 pkgCache::PkgIterator Pkg;
5bf15716 116 if (NewPackage(Pkg, PackageName, List.Architecture()) == 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 /*}}}*/
5bf15716
DK
326// CacheGenerator::NewGroup - Add a new group /*{{{*/
327// ---------------------------------------------------------------------
328/* This creates a new group structure and adds it to the hash table */
329bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name) {
330 Grp = Cache.FindGrp(Name);
331 if (Grp.end() == false)
332 return true;
333
334 // Get a structure
335 unsigned long const Group = Map.Allocate(sizeof(pkgCache::Group));
336 if (unlikely(Group == 0))
337 return false;
338
339 Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
340 Grp->Name = Map.WriteString(Name);
341 if (unlikely(Grp->Name == 0))
342 return false;
343
344 // Insert it into the hash table
345 unsigned long const Hash = Cache.Hash(Name);
346 Grp->Next = Cache.HeaderP->GrpHashTable[Hash];
347 Cache.HeaderP->GrpHashTable[Hash] = Group;
348
349 Cache.HeaderP->GroupCount++;
350
351 return true;
352}
353 /*}}}*/
578bfd0a
AL
354// CacheGenerator::NewPackage - Add a new package /*{{{*/
355// ---------------------------------------------------------------------
356/* This creates a new package structure and adds it to the hash table */
5bf15716
DK
357bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name,
358 const string &Arch) {
359 pkgCache::GrpIterator Grp;
360 if (unlikely(NewGroup(Grp, Name) == false))
361 return false;
362
363 Pkg = Grp.FindPkg(Arch);
364 if (Pkg.end() == false)
365 return true;
a52f938b 366
578bfd0a 367 // Get a structure
5bf15716
DK
368 unsigned long const Package = Map.Allocate(sizeof(pkgCache::Package));
369 if (unlikely(Package == 0))
578bfd0a 370 return false;
f55a958f 371 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
5bf15716 372
578bfd0a 373 // Insert it into the hash table
5bf15716
DK
374 unsigned long const Hash = Cache.Hash(Name);
375 Pkg->NextPackage = Cache.HeaderP->PkgHashTable[Hash];
376 Cache.HeaderP->PkgHashTable[Hash] = Package;
377
378 // remember the packages in the group
379 Grp->FirstPackage = Package;
380 if (Grp->LastPackage == 0)
381 Grp->LastPackage = Package;
382
383 // Set the name, arch and the ID
384 Pkg->Name = Grp->Name;
385 Pkg->Group = Grp.Index();
386 Pkg->Arch = WriteUniqString(Arch.c_str());
387 if (unlikely(Pkg->Arch == 0))
578bfd0a
AL
388 return false;
389 Pkg->ID = Cache.HeaderP->PackageCount++;
5bf15716 390
578bfd0a
AL
391 return true;
392}
393 /*}}}*/
394// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
395// ---------------------------------------------------------------------
396/* */
f55a958f 397bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
578bfd0a
AL
398 ListParser &List)
399{
ddc1d8d0
AL
400 if (CurrentFile == 0)
401 return true;
402
dcb79bae
AL
403 // Get a structure
404 unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
405 if (VerFile == 0)
406 return 0;
407
408 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
409 VF->File = CurrentFile - Cache.PkgFileP;
03e39e59
AL
410
411 // Link it to the end of the list
349cd3b8 412 map_ptrloc *Last = &Ver->FileList;
eb162ff7 413 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++)
03e39e59
AL
414 Last = &V->NextFile;
415 VF->NextFile = *Last;
416 *Last = VF.Index();
417
dcb79bae
AL
418 VF->Offset = List.Offset();
419 VF->Size = List.Size();
ad00ae81
AL
420 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
421 Cache.HeaderP->MaxVerFileSize = VF->Size;
a7e66b17
AL
422 Cache.HeaderP->VerFileCount++;
423
f55a958f 424 return true;
578bfd0a
AL
425}
426 /*}}}*/
427// CacheGenerator::NewVersion - Create a new Version /*{{{*/
428// ---------------------------------------------------------------------
f55a958f 429/* This puts a version structure in the linked list */
578bfd0a 430unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
171c75f1 431 const string &VerStr,
578bfd0a
AL
432 unsigned long Next)
433{
f55a958f
AL
434 // Get a structure
435 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
436 if (Version == 0)
0149949b 437 return 0;
f55a958f
AL
438
439 // Fill it in
440 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
f55a958f
AL
441 Ver->NextVer = Next;
442 Ver->ID = Cache.HeaderP->VersionCount++;
443 Ver->VerStr = Map.WriteString(VerStr);
444 if (Ver->VerStr == 0)
0149949b 445 return 0;
f55a958f 446
0149949b 447 return Version;
578bfd0a
AL
448}
449 /*}}}*/
a52f938b
OS
450// CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
451// ---------------------------------------------------------------------
452/* */
453bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
454 ListParser &List)
455{
456 if (CurrentFile == 0)
457 return true;
458
459 // Get a structure
460 unsigned long DescFile = Map.Allocate(sizeof(pkgCache::DescFile));
461 if (DescFile == 0)
c5f44afc 462 return false;
770c32ec 463
a52f938b
OS
464 pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
465 DF->File = CurrentFile - Cache.PkgFileP;
770c32ec 466
a52f938b
OS
467 // Link it to the end of the list
468 map_ptrloc *Last = &Desc->FileList;
eb162ff7 469 for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; D++)
a52f938b 470 Last = &D->NextFile;
770c32ec 471
a52f938b
OS
472 DF->NextFile = *Last;
473 *Last = DF.Index();
474
475 DF->Offset = List.Offset();
476 DF->Size = List.Size();
477 if (Cache.HeaderP->MaxDescFileSize < DF->Size)
478 Cache.HeaderP->MaxDescFileSize = DF->Size;
479 Cache.HeaderP->DescFileCount++;
480
481 return true;
482}
483 /*}}}*/
484// CacheGenerator::NewDescription - Create a new Description /*{{{*/
485// ---------------------------------------------------------------------
486/* This puts a description structure in the linked list */
487map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
c76c44b1 488 const string &Lang,
489 const MD5SumValue &md5sum,
a52f938b
OS
490 map_ptrloc Next)
491{
492 // Get a structure
493 map_ptrloc Description = Map.Allocate(sizeof(pkgCache::Description));
494 if (Description == 0)
495 return 0;
496
497 // Fill it in
498 Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
499 Desc->NextDesc = Next;
500 Desc->ID = Cache.HeaderP->DescriptionCount++;
501 Desc->language_code = Map.WriteString(Lang);
502 Desc->md5sum = Map.WriteString(md5sum.Value());
c5f44afc
DK
503 if (Desc->language_code == 0 || Desc->md5sum == 0)
504 return 0;
a52f938b
OS
505
506 return Description;
507}
508 /*}}}*/
dcb79bae
AL
509// ListParser::NewDepends - Create a dependency element /*{{{*/
510// ---------------------------------------------------------------------
511/* This creates a dependency element in the tree. It is linked to the
512 version and to the package that it is pointing to. */
513bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
171c75f1 514 const string &PackageName,
5bf15716 515 const string &Arch,
171c75f1 516 const string &Version,
dcb79bae
AL
517 unsigned int Op,
518 unsigned int Type)
519{
520 pkgCache &Cache = Owner->Cache;
521
522 // Get a structure
5bf15716
DK
523 unsigned long const Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
524 if (unlikely(Dependency == 0))
dcb79bae
AL
525 return false;
526
527 // Fill it in
528 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
529 Dep->ParentVer = Ver.Index();
530 Dep->Type = Type;
531 Dep->CompareOp = Op;
532 Dep->ID = Cache.HeaderP->DependsCount++;
533
5bf15716
DK
534 pkgCache::GrpIterator Grp;
535 if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
8efa2a3b 536 return false;
5bf15716
DK
537
538 // Locate the target package
539 pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
540 if (Pkg.end() == true) {
541 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
542 return false;
543 }
544
dcb79bae
AL
545 // Probe the reverse dependency list for a version string that matches
546 if (Version.empty() == false)
547 {
b2e465d6 548/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
dcb79bae 549 if (I->Version != 0 && I.TargetVer() == Version)
f9eec0e7 550 Dep->Version = I->Version;*/
dcb79bae 551 if (Dep->Version == 0)
5bf15716 552 if (unlikely((Dep->Version = WriteString(Version)) == 0))
dcb79bae
AL
553 return false;
554 }
c1a22377 555
dcb79bae
AL
556 // Link it to the package
557 Dep->Package = Pkg.Index();
558 Dep->NextRevDepends = Pkg->RevDepends;
559 Pkg->RevDepends = Dep.Index();
560
c1a22377
AL
561 /* Link it to the version (at the end of the list)
562 Caching the old end point speeds up generation substantially */
f9eec0e7 563 if (OldDepVer != Ver)
c1a22377 564 {
f9eec0e7 565 OldDepLast = &Ver->DependsList;
eb162ff7 566 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
f9eec0e7
AL
567 OldDepLast = &D->NextDepends;
568 OldDepVer = Ver;
c1a22377 569 }
45415543
AL
570
571 // Is it a file dependency?
5bf15716 572 if (unlikely(PackageName[0] == '/'))
45415543 573 FoundFileDeps = true;
dcb79bae 574
f9eec0e7
AL
575 Dep->NextDepends = *OldDepLast;
576 *OldDepLast = Dep.Index();
577 OldDepLast = &Dep->NextDepends;
c1a22377 578
dcb79bae
AL
579 return true;
580}
581 /*}}}*/
582// ListParser::NewProvides - Create a Provides element /*{{{*/
583// ---------------------------------------------------------------------
584/* */
585bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
171c75f1
MV
586 const string &PackageName,
587 const string &Version)
dcb79bae
AL
588{
589 pkgCache &Cache = Owner->Cache;
8efa2a3b
AL
590
591 // We do not add self referencing provides
5bf15716 592 if (unlikely(Ver.ParentPkg().Name() == PackageName))
8efa2a3b 593 return true;
dcb79bae
AL
594
595 // Get a structure
5bf15716
DK
596 unsigned long const Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
597 if (unlikely(Provides == 0))
dcb79bae 598 return false;
a7e66b17 599 Cache.HeaderP->ProvidesCount++;
dcb79bae
AL
600
601 // Fill it in
602 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
603 Prv->Version = Ver.Index();
604 Prv->NextPkgProv = Ver->ProvidesList;
605 Ver->ProvidesList = Prv.Index();
5bf15716 606 if (Version.empty() == false && unlikely((Prv->ProvideVersion = WriteString(Version)) == 0))
dcb79bae
AL
607 return false;
608
609 // Locate the target package
8efa2a3b 610 pkgCache::PkgIterator Pkg;
5bf15716 611 if (unlikely(Owner->NewPackage(Pkg,PackageName,string(Ver.Arch())) == false))
8efa2a3b 612 return false;
dcb79bae
AL
613
614 // Link it to the package
615 Prv->ParentPkg = Pkg.Index();
616 Prv->NextProvides = Pkg->ProvidesList;
617 Pkg->ProvidesList = Prv.Index();
618
619 return true;
620}
621 /*}}}*/
578bfd0a
AL
622// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
623// ---------------------------------------------------------------------
624/* This is used to select which file is to be associated with all newly
b2e465d6 625 added versions. The caller is responsible for setting the IMS fields. */
171c75f1 626bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
b2e465d6
AL
627 const pkgIndexFile &Index,
628 unsigned long Flags)
578bfd0a 629{
578bfd0a
AL
630 // Get some space for the structure
631 CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
632 if (CurrentFile == Cache.PkgFileP)
633 return false;
634
635 // Fill it in
636 CurrentFile->FileName = Map.WriteString(File);
b2e465d6 637 CurrentFile->Site = WriteUniqString(Site);
578bfd0a
AL
638 CurrentFile->NextFile = Cache.HeaderP->FileList;
639 CurrentFile->Flags = Flags;
e1b74f61 640 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
b2e465d6 641 CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label);
578bfd0a 642 PkgFileName = File;
ad00ae81 643 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
b35d2f5f 644 Cache.HeaderP->PackageFileCount++;
b2e465d6 645
578bfd0a
AL
646 if (CurrentFile->FileName == 0)
647 return false;
404ec98e 648
ddc1d8d0 649 if (Progress != 0)
b2e465d6 650 Progress->SubProgress(Index.Size());
8efa2a3b 651 return true;
578bfd0a
AL
652}
653 /*}}}*/
f55a958f
AL
654// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
655// ---------------------------------------------------------------------
656/* This is used to create handles to strings. Given the same text it
657 always returns the same number */
658unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
659 unsigned int Size)
660{
f9eec0e7
AL
661 /* We use a very small transient hash table here, this speeds up generation
662 by a fair amount on slower machines */
663 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
664 if (Bucket != 0 &&
665 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
666 return Bucket->String;
667
f55a958f
AL
668 // Search for an insertion point
669 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
670 int Res = 1;
349cd3b8 671 map_ptrloc *Last = &Cache.HeaderP->StringList;
f55a958f
AL
672 for (; I != Cache.StringItemP; Last = &I->NextItem,
673 I = Cache.StringItemP + I->NextItem)
674 {
9c14e3d6 675 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
f55a958f
AL
676 if (Res >= 0)
677 break;
678 }
679
680 // Match
681 if (Res == 0)
f9eec0e7
AL
682 {
683 Bucket = I;
0149949b 684 return I->String;
f9eec0e7 685 }
f55a958f
AL
686
687 // Get a structure
688 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
689 if (Item == 0)
0149949b
AL
690 return 0;
691
f55a958f
AL
692 // Fill in the structure
693 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
694 ItemP->NextItem = I - Cache.StringItemP;
695 *Last = Item;
696 ItemP->String = Map.WriteString(S,Size);
697 if (ItemP->String == 0)
0149949b 698 return 0;
f55a958f 699
f9eec0e7 700 Bucket = ItemP;
0149949b 701 return ItemP->String;
f55a958f
AL
702}
703 /*}}}*/
b2e465d6 704// CheckValidity - Check that a cache is up-to-date /*{{{*/
b35d2f5f 705// ---------------------------------------------------------------------
b2e465d6
AL
706/* This just verifies that each file in the list of index files exists,
707 has matching attributes with the cache and the cache does not have
708 any extra files. */
171c75f1 709static bool CheckValidity(const string &CacheFile, FileIterator Start,
e7b470ee 710 FileIterator End,MMap **OutMap = 0)
b35d2f5f 711{
b2e465d6
AL
712 // No file, certainly invalid
713 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
b35d2f5f
AL
714 return false;
715
b2e465d6 716 // Map it
b35d2f5f 717 FileFd CacheF(CacheFile,FileFd::ReadOnly);
eb162ff7 718 SPtr<MMap> Map = new MMap(CacheF,0);
b35d2f5f 719 pkgCache Cache(Map);
b2e465d6 720 if (_error->PendingError() == true || Map->Size() == 0)
b35d2f5f
AL
721 {
722 _error->Discard();
723 return false;
724 }
b35d2f5f 725
b2e465d6
AL
726 /* Now we check every index file, see if it is in the cache,
727 verify the IMS data and check that it is on the disk too.. */
728 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
729 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
730 for (; Start != End; Start++)
a77ad7c3 731 {
b2e465d6
AL
732 if ((*Start)->HasPackages() == false)
733 continue;
a77ad7c3 734
b2e465d6 735 if ((*Start)->Exists() == false)
b35d2f5f 736 {
a791a450 737#if 0 // mvo: we no longer give a message here (Default Sources spec)
b2e465d6
AL
738 _error->WarningE("stat",_("Couldn't stat source package list %s"),
739 (*Start)->Describe().c_str());
a791a450 740#endif
b2e465d6 741 continue;
b35d2f5f 742 }
b2e465d6
AL
743
744 // FindInCache is also expected to do an IMS check.
745 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
746 if (File.end() == true)
b35d2f5f 747 return false;
a52f938b 748
b2e465d6 749 Visited[File->ID] = true;
b35d2f5f
AL
750 }
751
b2e465d6
AL
752 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
753 if (Visited[I] == false)
754 return false;
b35d2f5f 755
b35d2f5f
AL
756 if (_error->PendingError() == true)
757 {
758 _error->Discard();
759 return false;
760 }
b35d2f5f 761
b2e465d6
AL
762 if (OutMap != 0)
763 *OutMap = Map.UnGuard();
b35d2f5f
AL
764 return true;
765}
766 /*}}}*/
b2e465d6 767// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 768// ---------------------------------------------------------------------
b2e465d6
AL
769/* Size is kind of an abstract notion that is only used for the progress
770 meter */
e7b470ee 771static unsigned long ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 772{
b2e465d6
AL
773 unsigned long TotalSize = 0;
774 for (; Start != End; Start++)
b35d2f5f 775 {
b2e465d6
AL
776 if ((*Start)->HasPackages() == false)
777 continue;
778 TotalSize += (*Start)->Size();
b35d2f5f 779 }
b2e465d6 780 return TotalSize;
2d11135a
AL
781}
782 /*}}}*/
b2e465d6 783// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 784// ---------------------------------------------------------------------
b2e465d6
AL
785/* */
786static bool BuildCache(pkgCacheGenerator &Gen,
787 OpProgress &Progress,
788 unsigned long &CurrentSize,unsigned long TotalSize,
e7b470ee 789 FileIterator Start, FileIterator End)
2d11135a 790{
45415543
AL
791 FileIterator I;
792 for (I = Start; I != End; I++)
2d11135a 793 {
45415543 794 if ((*I)->HasPackages() == false)
2d11135a
AL
795 continue;
796
45415543 797 if ((*I)->Exists() == false)
2d11135a 798 continue;
b2e465d6 799
45415543 800 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
a77ad7c3
AL
801 {
802 _error->Warning("Duplicate sources.list entry %s",
45415543 803 (*I)->Describe().c_str());
a77ad7c3
AL
804 continue;
805 }
806
45415543 807 unsigned long Size = (*I)->Size();
db0db9fe 808 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
b2e465d6 809 CurrentSize += Size;
2d11135a 810
45415543 811 if ((*I)->Merge(Gen,Progress) == false)
b2e465d6
AL
812 return false;
813 }
45415543
AL
814
815 if (Gen.HasFileDeps() == true)
816 {
817 Progress.Done();
818 TotalSize = ComputeSize(Start, End);
819 CurrentSize = 0;
820 for (I = Start; I != End; I++)
821 {
822 unsigned long Size = (*I)->Size();
823 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
824 CurrentSize += Size;
825 if ((*I)->MergeFileProvides(Gen,Progress) == false)
826 return false;
827 }
828 }
2d11135a 829
b35d2f5f
AL
830 return true;
831}
832 /*}}}*/
b2e465d6 833// MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 834// ---------------------------------------------------------------------
b2e465d6
AL
835/* This makes sure that the status cache (the cache that has all
836 index files from the sources list and all local ones) is ready
837 to be mmaped. If OutMap is not zero then a MMap object representing
838 the cache will be stored there. This is pretty much mandetory if you
839 are using AllowMem. AllowMem lets the function be run as non-root
840 where it builds the cache 'fast' into a memory buffer. */
841bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
842 MMap **OutMap,bool AllowMem)
b35d2f5f 843{
5177f802 844 unsigned long MapSize = _config->FindI("APT::Cache-Limit",24*1024*1024);
67db871e 845
7db98ffc
MZ
846 vector<pkgIndexFile *> Files;
847 for (vector<metaIndex *>::const_iterator i = List.begin();
848 i != List.end();
849 i++)
850 {
851 vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
852 for (vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
853 j != Indexes->end();
854 j++)
855 Files.push_back (*j);
856 }
857
b2e465d6
AL
858 unsigned long EndOfSource = Files.size();
859 if (_system->AddStatusFiles(Files) == false)
860 return false;
c5f44afc 861
b2e465d6 862 // Decide if we can write to the files..
3b5421b4 863 string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
b2e465d6
AL
864 string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
865
866 // Decide if we can write to the cache
867 bool Writeable = false;
868 if (CacheFile.empty() == false)
869 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
870 else
871 if (SrcCacheFile.empty() == false)
872 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
873
874 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
875 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
876
db0db9fe 877 Progress.OverallProgress(0,1,1,_("Reading package lists"));
b2e465d6
AL
878
879 // Cache is OK, Fin.
880 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
881 {
db0db9fe 882 Progress.OverallProgress(1,1,1,_("Reading package lists"));
b2e465d6
AL
883 return true;
884 }
885
886 /* At this point we know we need to reconstruct the package cache,
887 begin. */
888 SPtr<FileFd> CacheF;
889 SPtr<DynamicMMap> Map;
890 if (Writeable == true && CacheFile.empty() == false)
891 {
892 unlink(CacheFile.c_str());
893 CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
7a3c2ab0 894 fchmod(CacheF->Fd(),0644);
b2e465d6 895 Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
b35d2f5f
AL
896 if (_error->PendingError() == true)
897 return false;
b35d2f5f 898 }
b2e465d6 899 else
8ce4327b 900 {
b2e465d6 901 // Just build it in memory..
eb162ff7 902 Map = new DynamicMMap(0,MapSize);
8ce4327b 903 }
b35d2f5f 904
b2e465d6 905 // Lets try the source cache.
b35d2f5f 906 unsigned long CurrentSize = 0;
b2e465d6
AL
907 unsigned long TotalSize = 0;
908 if (CheckValidity(SrcCacheFile,Files.begin(),
909 Files.begin()+EndOfSource) == true)
2d11135a 910 {
b2e465d6
AL
911 // Preload the map with the source cache
912 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
c5f44afc 913 unsigned long alloc = Map->RawAllocate(SCacheF.Size());
eb162ff7
DK
914 if ((alloc == 0 && _error->PendingError())
915 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
916 SCacheF.Size()) == false)
b2e465d6
AL
917 return false;
918
919 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
2d11135a 920
b2e465d6
AL
921 // Build the status cache
922 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 923 if (_error->PendingError() == true)
b2e465d6
AL
924 return false;
925 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
926 Files.begin()+EndOfSource,Files.end()) == false)
927 return false;
928 }
929 else
2d11135a 930 {
b2e465d6 931 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 932
b2e465d6
AL
933 // Build the source cache
934 pkgCacheGenerator Gen(Map.Get(),&Progress);
935 if (_error->PendingError() == true)
936 return false;
937 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
938 Files.begin(),Files.begin()+EndOfSource) == false)
939 return false;
2d11135a 940
b2e465d6
AL
941 // Write it back
942 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 943 {
b2e465d6
AL
944 FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
945 if (_error->PendingError() == true)
946 return false;
7a3c2ab0
AL
947
948 fchmod(SCacheF.Fd(),0644);
949
b2e465d6
AL
950 // Write out the main data
951 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
952 return _error->Error(_("IO Error saving source cache"));
953 SCacheF.Sync();
954
955 // Write out the proper header
956 Gen.GetCache().HeaderP->Dirty = false;
957 if (SCacheF.Seek(0) == false ||
958 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
959 return _error->Error(_("IO Error saving source cache"));
b2e465d6 960 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 961 SCacheF.Sync();
2d11135a
AL
962 }
963
b2e465d6
AL
964 // Build the status cache
965 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
966 Files.begin()+EndOfSource,Files.end()) == false)
967 return false;
2d11135a
AL
968 }
969
b2e465d6
AL
970 if (_error->PendingError() == true)
971 return false;
972 if (OutMap != 0)
2d11135a 973 {
b2e465d6 974 if (CacheF != 0)
2d11135a 975 {
b2e465d6 976 delete Map.UnGuard();
eb162ff7 977 *OutMap = new MMap(*CacheF,0);
2d11135a 978 }
b2e465d6
AL
979 else
980 {
981 *OutMap = Map.UnGuard();
982 }
2d11135a
AL
983 }
984
b2e465d6
AL
985 return true;
986}
987 /*}}}*/
988// MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
989// ---------------------------------------------------------------------
990/* */
991bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
992{
5177f802 993 unsigned long MapSize = _config->FindI("APT::Cache-Limit",20*1024*1024);
b2e465d6
AL
994 vector<pkgIndexFile *> Files;
995 unsigned long EndOfSource = Files.size();
996 if (_system->AddStatusFiles(Files) == false)
997 return false;
998
eb162ff7 999 SPtr<DynamicMMap> Map = new DynamicMMap(0,MapSize);
b2e465d6
AL
1000 unsigned long CurrentSize = 0;
1001 unsigned long TotalSize = 0;
1002
1003 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1004
1005 // Build the status cache
db0db9fe 1006 Progress.OverallProgress(0,1,1,_("Reading package lists"));
b2e465d6 1007 pkgCacheGenerator Gen(Map.Get(),&Progress);
2d11135a 1008 if (_error->PendingError() == true)
b2e465d6
AL
1009 return false;
1010 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1011 Files.begin()+EndOfSource,Files.end()) == false)
1012 return false;
2d11135a 1013
b2e465d6
AL
1014 if (_error->PendingError() == true)
1015 return false;
1016 *OutMap = Map.UnGuard();
2d11135a 1017
b2e465d6 1018 return true;
2d11135a
AL
1019}
1020 /*}}}*/