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