]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.49 2001/05/27 05:55:27 jgg Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
12 // Include Files /*{{{*/
14 #pragma implementation "apt-pkg/pkgcachegen.h"
17 #define APT_COMPATIBILITY 986
19 #include <apt-pkg/pkgcachegen.h>
20 #include <apt-pkg/error.h>
21 #include <apt-pkg/version.h>
22 #include <apt-pkg/progress.h>
23 #include <apt-pkg/sourcelist.h>
24 #include <apt-pkg/configuration.h>
25 #include <apt-pkg/strutl.h>
26 #include <apt-pkg/sptr.h>
27 #include <apt-pkg/pkgsystem.h>
39 typedef vector
<pkgIndexFile
*>::iterator FileIterator
;
41 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
42 // ---------------------------------------------------------------------
43 /* We set the diry flag and make sure that is written to the disk */
44 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
45 Map(*pMap
), Cache(pMap
,false), Progress(Prog
)
48 memset(UniqHash
,0,sizeof(UniqHash
));
50 if (_error
->PendingError() == true)
55 // Setup the map interface..
56 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
57 Map
.RawAllocate(sizeof(pkgCache::Header
));
58 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
61 *Cache
.HeaderP
= pkgCache::Header();
62 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
63 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
68 // Map directly from the existing file
70 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
71 if (Cache
.VS
!= _system
->VS
)
73 _error
->Error(_("Cache has an incompatible versioning system"));
78 Cache
.HeaderP
->Dirty
= true;
79 Map
.Sync(0,sizeof(pkgCache::Header
));
82 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
83 // ---------------------------------------------------------------------
84 /* We sync the data then unset the dirty flag in two steps so as to
85 advoid a problem during a crash */
86 pkgCacheGenerator::~pkgCacheGenerator()
88 if (_error
->PendingError() == true)
90 if (Map
.Sync() == false)
93 Cache
.HeaderP
->Dirty
= false;
94 Map
.Sync(0,sizeof(pkgCache::Header
));
97 // CacheGenerator::MergeList - Merge the package list /*{{{*/
98 // ---------------------------------------------------------------------
99 /* This provides the generation of the entries in the cache. Each loop
100 goes through a single package record from the underlying parse engine. */
101 bool pkgCacheGenerator::MergeList(ListParser
&List
,
102 pkgCache::VerIterator
*OutVer
)
106 unsigned int Counter
= 0;
107 while (List
.Step() == true)
109 // Get a pointer to the package structure
110 string PackageName
= List
.Package();
111 if (PackageName
.empty() == true)
114 pkgCache::PkgIterator Pkg
;
115 if (NewPackage(Pkg
,PackageName
) == false)
116 return _error
->Error(_("Error occured while processing %s (NewPackage)"),PackageName
.c_str());
118 if (Counter
% 100 == 0 && Progress
!= 0)
119 Progress
->Progress(List
.Offset());
121 /* Get a pointer to the version structure. We know the list is sorted
122 so we use that fact in the search. Insertion of new versions is
123 done with correct sorting */
124 string Version
= List
.Version();
125 if (Version
.empty() == true)
127 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
128 return _error
->Error(_("Error occured while processing %s (UsePackage1)"),PackageName
.c_str());
132 pkgCache::VerIterator Ver
= Pkg
.VersionList();
133 map_ptrloc
*Last
= &Pkg
->VersionList
;
135 for (; Ver
.end() == false; Last
= &Ver
->NextVer
, Ver
++)
137 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
142 /* We already have a version for this item, record that we
144 unsigned long Hash
= List
.VersionHash();
145 if (Res
== 0 && Ver
->Hash
== Hash
)
147 if (List
.UsePackage(Pkg
,Ver
) == false)
148 return _error
->Error(_("Error occured while processing %s (UsePackage2)"),PackageName
.c_str());
150 if (NewFileVer(Ver
,List
) == false)
151 return _error
->Error(_("Error occured while processing %s (NewFileVer1)"),PackageName
.c_str());
153 // Read only a single record and return
163 // Skip to the end of the same version set.
166 for (; Ver
.end() == false; Last
= &Ver
->NextVer
, Ver
++)
168 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
175 *Last
= NewVersion(Ver
,Version
,*Last
);
176 Ver
->ParentPkg
= Pkg
.Index();
178 if (List
.NewVersion(Ver
) == false)
179 return _error
->Error(_("Error occured while processing %s (NewVersion1)"),PackageName
.c_str());
181 if (List
.UsePackage(Pkg
,Ver
) == false)
182 return _error
->Error(_("Error occured while processing %s (UsePackage3)"),PackageName
.c_str());
184 if (NewFileVer(Ver
,List
) == false)
185 return _error
->Error(_("Error occured while processing %s (NewVersion2)"),PackageName
.c_str());
187 // Read only a single record and return
198 // CacheGenerator::NewPackage - Add a new package /*{{{*/
199 // ---------------------------------------------------------------------
200 /* This creates a new package structure and adds it to the hash table */
201 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,string Name
)
203 Pkg
= Cache
.FindPkg(Name
);
204 if (Pkg
.end() == false)
208 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
212 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
214 // Insert it into the hash table
215 unsigned long Hash
= Cache
.Hash(Name
);
216 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
217 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
219 // Set the name and the ID
220 Pkg
->Name
= Map
.WriteString(Name
);
223 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
228 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
229 // ---------------------------------------------------------------------
231 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
234 if (CurrentFile
== 0)
238 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
242 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
243 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
245 // Link it to the end of the list
246 map_ptrloc
*Last
= &Ver
->FileList
;
247 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
249 VF
->NextFile
= *Last
;
252 VF
->Offset
= List
.Offset();
253 VF
->Size
= List
.Size();
254 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
255 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
256 Cache
.HeaderP
->VerFileCount
++;
261 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
262 // ---------------------------------------------------------------------
263 /* This puts a version structure in the linked list */
264 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
269 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
274 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
276 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
277 Ver
->VerStr
= Map
.WriteString(VerStr
);
278 if (Ver
->VerStr
== 0)
284 // ListParser::NewDepends - Create a dependency element /*{{{*/
285 // ---------------------------------------------------------------------
286 /* This creates a dependency element in the tree. It is linked to the
287 version and to the package that it is pointing to. */
288 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
294 pkgCache
&Cache
= Owner
->Cache
;
297 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
302 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
303 Dep
->ParentVer
= Ver
.Index();
306 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
308 // Locate the target package
309 pkgCache::PkgIterator Pkg
;
310 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
313 // Probe the reverse dependency list for a version string that matches
314 if (Version
.empty() == false)
316 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
317 if (I->Version != 0 && I.TargetVer() == Version)
318 Dep->Version = I->Version;*/
319 if (Dep
->Version
== 0)
320 if ((Dep
->Version
= WriteString(Version
)) == 0)
324 // Link it to the package
325 Dep
->Package
= Pkg
.Index();
326 Dep
->NextRevDepends
= Pkg
->RevDepends
;
327 Pkg
->RevDepends
= Dep
.Index();
329 /* Link it to the version (at the end of the list)
330 Caching the old end point speeds up generation substantially */
331 if (OldDepVer
!= Ver
)
333 OldDepLast
= &Ver
->DependsList
;
334 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
335 OldDepLast
= &D
->NextDepends
;
339 Dep
->NextDepends
= *OldDepLast
;
340 *OldDepLast
= Dep
.Index();
341 OldDepLast
= &Dep
->NextDepends
;
346 // ListParser::NewProvides - Create a Provides element /*{{{*/
347 // ---------------------------------------------------------------------
349 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
353 pkgCache
&Cache
= Owner
->Cache
;
355 // We do not add self referencing provides
356 if (Ver
.ParentPkg().Name() == PackageName
)
360 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
363 Cache
.HeaderP
->ProvidesCount
++;
366 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
367 Prv
->Version
= Ver
.Index();
368 Prv
->NextPkgProv
= Ver
->ProvidesList
;
369 Ver
->ProvidesList
= Prv
.Index();
370 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
373 // Locate the target package
374 pkgCache::PkgIterator Pkg
;
375 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
378 // Link it to the package
379 Prv
->ParentPkg
= Pkg
.Index();
380 Prv
->NextProvides
= Pkg
->ProvidesList
;
381 Pkg
->ProvidesList
= Prv
.Index();
386 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
387 // ---------------------------------------------------------------------
388 /* This is used to select which file is to be associated with all newly
389 added versions. The caller is responsible for setting the IMS fields. */
390 bool pkgCacheGenerator::SelectFile(string File
,string Site
,
391 const pkgIndexFile
&Index
,
394 // Get some space for the structure
395 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
396 if (CurrentFile
== Cache
.PkgFileP
)
400 CurrentFile
->FileName
= Map
.WriteString(File
);
401 CurrentFile
->Site
= WriteUniqString(Site
);
402 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
403 CurrentFile
->Flags
= Flags
;
404 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
405 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
407 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
408 Cache
.HeaderP
->PackageFileCount
++;
410 if (CurrentFile
->FileName
== 0)
414 Progress
->SubProgress(Index
.Size());
418 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
419 // ---------------------------------------------------------------------
420 /* This is used to create handles to strings. Given the same text it
421 always returns the same number */
422 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
425 /* We use a very small transient hash table here, this speeds up generation
426 by a fair amount on slower machines */
427 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
429 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
430 return Bucket
->String
;
432 // Search for an insertion point
433 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
435 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
436 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
437 I
= Cache
.StringItemP
+ I
->NextItem
)
439 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
452 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
456 // Fill in the structure
457 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
458 ItemP
->NextItem
= I
- Cache
.StringItemP
;
460 ItemP
->String
= Map
.WriteString(S
,Size
);
461 if (ItemP
->String
== 0)
465 return ItemP
->String
;
469 // CheckValidity - Check that a cache is up-to-date /*{{{*/
470 // ---------------------------------------------------------------------
471 /* This just verifies that each file in the list of index files exists,
472 has matching attributes with the cache and the cache does not have
474 static bool CheckValidity(string CacheFile
, FileIterator Start
,
475 FileIterator End
,MMap
**OutMap
= 0)
477 // No file, certainly invalid
478 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
482 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
483 SPtr
<MMap
> Map
= new MMap(CacheF
,MMap::Public
| MMap::ReadOnly
);
485 if (_error
->PendingError() == true || Map
->Size() == 0)
491 /* Now we check every index file, see if it is in the cache,
492 verify the IMS data and check that it is on the disk too.. */
493 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
494 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
495 for (; Start
!= End
; Start
++)
497 if ((*Start
)->HasPackages() == false)
500 if ((*Start
)->Exists() == false)
502 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
503 (*Start
)->Describe().c_str());
507 // FindInCache is also expected to do an IMS check.
508 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
509 if (File
.end() == true)
512 Visited
[File
->ID
] = true;
515 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
516 if (Visited
[I
] == false)
519 if (_error
->PendingError() == true)
526 *OutMap
= Map
.UnGuard();
530 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
531 // ---------------------------------------------------------------------
532 /* Size is kind of an abstract notion that is only used for the progress
534 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
536 unsigned long TotalSize
= 0;
537 for (; Start
!= End
; Start
++)
539 if ((*Start
)->HasPackages() == false)
541 TotalSize
+= (*Start
)->Size();
546 // BuildCache - Merge the list of index files into the cache /*{{{*/
547 // ---------------------------------------------------------------------
549 static bool BuildCache(pkgCacheGenerator
&Gen
,
550 OpProgress
&Progress
,
551 unsigned long &CurrentSize
,unsigned long TotalSize
,
552 FileIterator Start
, FileIterator End
)
554 for (; Start
!= End
; Start
++)
556 if ((*Start
)->HasPackages() == false)
559 if ((*Start
)->Exists() == false)
562 if ((*Start
)->FindInCache(Gen
.GetCache()).end() == false)
564 _error
->Warning("Duplicate sources.list entry %s",
565 (*Start
)->Describe().c_str());
569 unsigned long Size
= (*Start
)->Size();
570 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading Package Lists"));
573 if ((*Start
)->Merge(Gen
,Progress
) == false)
580 // MakeStatusCache - Construct the status cache /*{{{*/
581 // ---------------------------------------------------------------------
582 /* This makes sure that the status cache (the cache that has all
583 index files from the sources list and all local ones) is ready
584 to be mmaped. If OutMap is not zero then a MMap object representing
585 the cache will be stored there. This is pretty much mandetory if you
586 are using AllowMem. AllowMem lets the function be run as non-root
587 where it builds the cache 'fast' into a memory buffer. */
588 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
589 MMap
**OutMap
,bool AllowMem
)
591 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",6*1024*1024);
593 vector
<pkgIndexFile
*> Files(List
.begin(),List
.end());
594 unsigned long EndOfSource
= Files
.size();
595 if (_system
->AddStatusFiles(Files
) == false)
598 // Decide if we can write to the files..
599 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
600 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
602 // Decide if we can write to the cache
603 bool Writeable
= false;
604 if (CacheFile
.empty() == false)
605 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
607 if (SrcCacheFile
.empty() == false)
608 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
610 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
611 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
613 Progress
.OverallProgress(0,1,1,_("Reading Package Lists"));
616 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
618 Progress
.OverallProgress(1,1,1,_("Reading Package Lists"));
622 /* At this point we know we need to reconstruct the package cache,
625 SPtr
<DynamicMMap
> Map
;
626 if (Writeable
== true && CacheFile
.empty() == false)
628 unlink(CacheFile
.c_str());
629 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
630 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
631 if (_error
->PendingError() == true)
636 // Just build it in memory..
637 Map
= new DynamicMMap(MMap::Public
,MapSize
);
640 // Lets try the source cache.
641 unsigned long CurrentSize
= 0;
642 unsigned long TotalSize
= 0;
643 if (CheckValidity(SrcCacheFile
,Files
.begin(),
644 Files
.begin()+EndOfSource
) == true)
646 // Preload the map with the source cache
647 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
648 if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()),
649 SCacheF
.Size()) == false)
652 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
654 // Build the status cache
655 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
656 if (_error
->PendingError() == true)
658 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
659 Files
.begin()+EndOfSource
,Files
.end()) == false)
664 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
666 // Build the source cache
667 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
668 if (_error
->PendingError() == true)
670 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
671 Files
.begin(),Files
.begin()+EndOfSource
) == false)
675 if (Writeable
== true && SrcCacheFile
.empty() == false)
677 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
678 if (_error
->PendingError() == true)
680 // Write out the main data
681 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
682 return _error
->Error(_("IO Error saving source cache"));
685 // Write out the proper header
686 Gen
.GetCache().HeaderP
->Dirty
= false;
687 if (SCacheF
.Seek(0) == false ||
688 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
689 return _error
->Error(_("IO Error saving source cache"));
691 Gen
.GetCache().HeaderP
->Dirty
= true;
694 // Build the status cache
695 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
696 Files
.begin()+EndOfSource
,Files
.end()) == false)
700 if (_error
->PendingError() == true)
706 delete Map
.UnGuard();
707 *OutMap
= new MMap(*CacheF
,MMap::Public
| MMap::ReadOnly
);
711 *OutMap
= Map
.UnGuard();
718 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
719 // ---------------------------------------------------------------------
721 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
723 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",4*1024*1024);
724 vector
<pkgIndexFile
*> Files
;
725 unsigned long EndOfSource
= Files
.size();
726 if (_system
->AddStatusFiles(Files
) == false)
729 SPtr
<DynamicMMap
> Map
;
730 Map
= new DynamicMMap(MMap::Public
,MapSize
);
731 unsigned long CurrentSize
= 0;
732 unsigned long TotalSize
= 0;
734 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
736 // Build the status cache
737 Progress
.OverallProgress(0,1,1,_("Reading Package Lists"));
738 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
739 if (_error
->PendingError() == true)
741 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
742 Files
.begin()+EndOfSource
,Files
.end()) == false)
745 if (_error
->PendingError() == true)
747 *OutMap
= Map
.UnGuard();