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