]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.33 1999/03/08 07:18:11 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 #include <apt-pkg/pkgcachegen.h>
18 #include <apt-pkg/error.h>
19 #include <apt-pkg/version.h>
20 #include <apt-pkg/progress.h>
21 #include <apt-pkg/sourcelist.h>
22 #include <apt-pkg/configuration.h>
23 #include <apt-pkg/deblistparser.h>
24 #include <apt-pkg/strutl.h>
31 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
32 // ---------------------------------------------------------------------
33 /* We set the diry flag and make sure that is written to the disk */
34 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
&Map
,OpProgress
&Prog
) :
35 Map(Map
), Cache(Map
), Progress(Prog
)
37 if (_error
->PendingError() == true)
42 Map
.RawAllocate(sizeof(pkgCache::Header
));
43 *Cache
.HeaderP
= pkgCache::Header();
45 Cache
.HeaderP
->Dirty
= true;
46 Map
.Sync(0,sizeof(pkgCache::Header
));
47 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
48 memset(UniqHash
,0,sizeof(UniqHash
));
51 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
52 // ---------------------------------------------------------------------
53 /* We sync the data then unset the dirty flag in two steps so as to
54 advoid a problem during a crash */
55 pkgCacheGenerator::~pkgCacheGenerator()
57 if (_error
->PendingError() == true)
59 if (Map
.Sync() == false)
62 Cache
.HeaderP
->Dirty
= false;
63 Map
.Sync(0,sizeof(pkgCache::Header
));
66 // CacheGenerator::MergeList - Merge the package list /*{{{*/
67 // ---------------------------------------------------------------------
68 /* This provides the generation of the entries in the cache. Each loop
69 goes through a single package record from the underlying parse engine. */
70 bool pkgCacheGenerator::MergeList(ListParser
&List
)
74 unsigned int Counter
= 0;
75 while (List
.Step() == true)
77 // Get a pointer to the package structure
78 string PackageName
= List
.Package();
79 if (PackageName
.empty() == true)
82 pkgCache::PkgIterator Pkg
;
83 if (NewPackage(Pkg
,PackageName
) == false)
84 return _error
->Error("Error occured while processing %s (NewPackage)",PackageName
.c_str());
86 if (Counter
% 100 == 0)
87 Progress
.Progress(List
.Offset());
89 /* Get a pointer to the version structure. We know the list is sorted
90 so we use that fact in the search. Insertion of new versions is
91 done with correct sorting */
92 string Version
= List
.Version();
93 if (Version
.empty() == true)
95 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
96 return _error
->Error("Error occured while processing %s (UsePackage1)",PackageName
.c_str());
100 pkgCache::VerIterator Ver
= Pkg
.VersionList();
101 __apt_ptrloc
*Last
= &Pkg
->VersionList
;
103 for (; Ver
.end() == false; Last
= &Ver
->NextVer
, Ver
++)
105 Res
= pkgVersionCompare(Version
.begin(),Version
.end(),Ver
.VerStr(),
106 Ver
.VerStr() + strlen(Ver
.VerStr()));
111 /* We already have a version for this item, record that we
115 if (List
.UsePackage(Pkg
,Ver
) == false)
116 return _error
->Error("Error occured while processing %s (UsePackage2)",PackageName
.c_str());
118 if (NewFileVer(Ver
,List
) == false)
119 return _error
->Error("Error occured while processing %s (NewFileVer1)",PackageName
.c_str());
125 *Last
= NewVersion(Ver
,Version
,*Last
);
126 Ver
->ParentPkg
= Pkg
.Index();
127 if (List
.NewVersion(Ver
) == false)
128 return _error
->Error("Error occured while processing %s (NewVersion1)",PackageName
.c_str());
130 if (List
.UsePackage(Pkg
,Ver
) == false)
131 return _error
->Error("Error occured while processing %s (UsePackage3)",PackageName
.c_str());
133 if (NewFileVer(Ver
,List
) == false)
134 return _error
->Error("Error occured while processing %s (NewVersion2)",PackageName
.c_str());
140 // CacheGenerator::NewPackage - Add a new package /*{{{*/
141 // ---------------------------------------------------------------------
142 /* This creates a new package structure and adds it to the hash table */
143 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,string Name
)
145 Pkg
= Cache
.FindPkg(Name
);
146 if (Pkg
.end() == false)
150 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
154 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
156 // Insert it into the hash table
157 unsigned long Hash
= Cache
.Hash(Name
);
158 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
159 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
161 // Set the name and the ID
162 Pkg
->Name
= Map
.WriteString(Name
);
165 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
170 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
171 // ---------------------------------------------------------------------
173 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
177 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
181 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
182 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
184 // Link it to the end of the list
185 __apt_ptrloc
*Last
= &Ver
->FileList
;
186 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
188 VF
->NextFile
= *Last
;
191 VF
->Offset
= List
.Offset();
192 VF
->Size
= List
.Size();
193 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
194 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
195 Cache
.HeaderP
->VerFileCount
++;
200 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
201 // ---------------------------------------------------------------------
202 /* This puts a version structure in the linked list */
203 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
208 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
213 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
215 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
216 Ver
->VerStr
= Map
.WriteString(VerStr
);
217 if (Ver
->VerStr
== 0)
223 // ListParser::NewDepends - Create a dependency element /*{{{*/
224 // ---------------------------------------------------------------------
225 /* This creates a dependency element in the tree. It is linked to the
226 version and to the package that it is pointing to. */
227 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
233 pkgCache
&Cache
= Owner
->Cache
;
236 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
241 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
242 Dep
->ParentVer
= Ver
.Index();
245 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
247 // Locate the target package
248 pkgCache::PkgIterator Pkg
;
249 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
252 // Probe the reverse dependency list for a version string that matches
253 if (Version
.empty() == false)
255 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++, Hit++)
256 if (I->Version != 0 && I.TargetVer() == Version)
257 Dep->Version = I->Version;*/
258 if (Dep
->Version
== 0)
259 if ((Dep
->Version
= WriteString(Version
)) == 0)
263 // Link it to the package
264 Dep
->Package
= Pkg
.Index();
265 Dep
->NextRevDepends
= Pkg
->RevDepends
;
266 Pkg
->RevDepends
= Dep
.Index();
268 /* Link it to the version (at the end of the list)
269 Caching the old end point speeds up generation substantially */
270 if (OldDepVer
!= Ver
)
272 OldDepLast
= &Ver
->DependsList
;
273 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
274 OldDepLast
= &D
->NextDepends
;
278 Dep
->NextDepends
= *OldDepLast
;
279 *OldDepLast
= Dep
.Index();
280 OldDepLast
= &Dep
->NextDepends
;
285 // ListParser::NewProvides - Create a Provides element /*{{{*/
286 // ---------------------------------------------------------------------
288 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
292 pkgCache
&Cache
= Owner
->Cache
;
294 // We do not add self referencing provides
295 if (Ver
.ParentPkg().Name() == PackageName
)
299 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
302 Cache
.HeaderP
->ProvidesCount
++;
305 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
306 Prv
->Version
= Ver
.Index();
307 Prv
->NextPkgProv
= Ver
->ProvidesList
;
308 Ver
->ProvidesList
= Prv
.Index();
309 if (Version
.empty() == false && (Prv
->Version
= WriteString(Version
)) == 0)
312 // Locate the target package
313 pkgCache::PkgIterator Pkg
;
314 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
317 // Link it to the package
318 Prv
->ParentPkg
= Pkg
.Index();
319 Prv
->NextProvides
= Pkg
->ProvidesList
;
320 Pkg
->ProvidesList
= Prv
.Index();
325 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
326 // ---------------------------------------------------------------------
327 /* This is used to select which file is to be associated with all newly
329 bool pkgCacheGenerator::SelectFile(string File
,unsigned long Flags
)
332 if (stat(File
.c_str(),&Buf
) == -1)
333 return _error
->Errno("stat","Couldn't stat ",File
.c_str());
335 // Get some space for the structure
336 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
337 if (CurrentFile
== Cache
.PkgFileP
)
341 CurrentFile
->FileName
= Map
.WriteString(File
);
342 CurrentFile
->Size
= Buf
.st_size
;
343 CurrentFile
->mtime
= Buf
.st_mtime
;
344 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
345 CurrentFile
->Flags
= Flags
;
346 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
348 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
349 Cache
.HeaderP
->PackageFileCount
++;
351 if (CurrentFile
->FileName
== 0)
354 Progress
.SubProgress(Buf
.st_size
);
358 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
359 // ---------------------------------------------------------------------
360 /* This is used to create handles to strings. Given the same text it
361 always returns the same number */
362 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
365 /* We use a very small transient hash table here, this speeds up generation
366 by a fair amount on slower machines */
367 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
369 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
370 return Bucket
->String
;
372 // Search for an insertion point
373 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
375 __apt_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
376 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
377 I
= Cache
.StringItemP
+ I
->NextItem
)
379 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
392 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
396 // Fill in the structure
397 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
398 ItemP
->NextItem
= I
- Cache
.StringItemP
;
400 ItemP
->String
= Map
.WriteString(S
,Size
);
401 if (ItemP
->String
== 0)
405 return ItemP
->String
;
409 // SrcCacheCheck - Check if the source package cache is uptodate /*{{{*/
410 // ---------------------------------------------------------------------
411 /* The source cache is checked against the source list and the files
412 on disk, any difference results in a false. */
413 bool pkgSrcCacheCheck(pkgSourceList
&List
)
415 if (_error
->PendingError() == true)
418 string CacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
419 string ListDir
= _config
->FindDir("Dir::State::lists");
421 // Count the number of missing files
423 for (pkgSourceList::const_iterator I
= List
.begin(); I
!= List
.end(); I
++)
425 // Only cache deb source types.
426 if (I
->Type
!= pkgSourceList::Item::Deb
)
432 string File
= ListDir
+ URItoFileName(I
->PackagesURI());
434 if (stat(File
.c_str(),&Buf
) != 0)
436 _error
->WarningE("stat","Couldn't stat source package list '%s' (%s)",
437 I
->PackagesInfo().c_str(),File
.c_str());
442 // Open the source package cache
443 if (FileExists(CacheFile
) == false)
446 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
447 if (_error
->PendingError() == true)
453 MMap
Map(CacheF
,MMap::Public
| MMap::ReadOnly
);
454 if (_error
->PendingError() == true || Map
.Size() == 0)
461 if (_error
->PendingError() == true)
467 // They are certianly out of sync
468 if (Cache
.Head().PackageFileCount
!= List
.size() - Missing
)
471 for (pkgCache::PkgFileIterator
F(Cache
); F
.end() == false; F
++)
473 // Search for a match in the source list
475 for (pkgSourceList::const_iterator I
= List
.begin();
476 I
!= List
.end(); I
++)
478 // Only cache deb source types.
479 if (I
->Type
!= pkgSourceList::Item::Deb
)
482 string File
= ListDir
+ URItoFileName(I
->PackagesURI());
483 if (F
.FileName() == File
)
490 // Check if the file matches what was cached
499 // PkgCacheCheck - Check if the package cache is uptodate /*{{{*/
500 // ---------------------------------------------------------------------
501 /* This does a simple check of all files used to compose the cache */
502 bool pkgPkgCacheCheck(string CacheFile
)
504 if (_error
->PendingError() == true)
507 // Open the source package cache
508 if (FileExists(CacheFile
) == false)
511 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
512 if (_error
->PendingError() == true)
518 MMap
Map(CacheF
,MMap::Public
| MMap::ReadOnly
);
519 if (_error
->PendingError() == true || Map
.Size() == 0)
526 if (_error
->PendingError() == true)
532 // Status files that must be in the cache
534 Status
[0] = _config
->FindFile("Dir::State::xstatus");
535 Status
[1]= _config
->FindFile("Dir::State::userstatus");
536 Status
[2] = _config
->FindFile("Dir::State::status");
539 for (pkgCache::PkgFileIterator
F(Cache
); F
.end() == false; F
++)
541 if (F
.IsOk() == false)
544 // See if this is one of the status files
545 for (int I
= 0; I
!= 3; I
++)
546 if (F
.FileName() == Status
[I
])
547 Status
[I
] = string();
550 // Make sure all the status files are loaded.
551 for (int I
= 0; I
!= 3; I
++)
553 if (Status
[I
].empty() == false && FileExists(Status
[I
]) == true)
560 // AddSourcesSize - Add the size of the status files /*{{{*/
561 // ---------------------------------------------------------------------
562 /* This adds the size of all the status files to the size counter */
563 static bool pkgAddSourcesSize(unsigned long &TotalSize
)
565 // Grab the file names
566 string xstatus
= _config
->FindFile("Dir::State::xstatus");
567 string userstatus
= _config
->FindFile("Dir::State::userstatus");
568 string status
= _config
->FindFile("Dir::State::status");
572 if (stat(xstatus
.c_str(),&Buf
) == 0)
573 TotalSize
+= Buf
.st_size
;
574 if (stat(userstatus
.c_str(),&Buf
) == 0)
575 TotalSize
+= Buf
.st_size
;
576 if (stat(status
.c_str(),&Buf
) != 0)
577 return _error
->Errno("stat","Couldn't stat the status file %s",status
.c_str());
578 TotalSize
+= Buf
.st_size
;
583 // MergeStatus - Add the status files to the cache /*{{{*/
584 // ---------------------------------------------------------------------
585 /* This adds the status files to the map */
586 static bool pkgMergeStatus(OpProgress
&Progress
,pkgCacheGenerator
&Gen
,
587 unsigned long &CurrentSize
,unsigned long TotalSize
)
589 // Grab the file names
591 Status
[0] = _config
->FindFile("Dir::State::xstatus");
592 Status
[1]= _config
->FindFile("Dir::State::userstatus");
593 Status
[2] = _config
->FindFile("Dir::State::status");
595 for (int I
= 0; I
!= 3; I
++)
597 // Check if the file exists and it is not the primary status file.
598 string File
= Status
[I
];
599 if (I
!= 2 && FileExists(File
) == false)
602 FileFd
Pkg(File
,FileFd::ReadOnly
);
603 debListParser
Parser(Pkg
);
604 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),"Reading Package Lists");
605 if (_error
->PendingError() == true)
606 return _error
->Error("Problem opening %s",File
.c_str());
607 CurrentSize
+= Pkg
.Size();
609 Progress
.SubProgress(0,"Local Package State - " + flNotDir(File
));
610 if (Gen
.SelectFile(File
,pkgCache::Flag::NotSource
) == false)
611 return _error
->Error("Problem with SelectFile %s",File
.c_str());
613 if (Gen
.MergeList(Parser
) == false)
614 return _error
->Error("Problem with MergeList %s",File
.c_str());
615 Progress
.Progress(Pkg
.Size());
621 // MakeStatusCache - Generates a cache that includes the status files /*{{{*/
622 // ---------------------------------------------------------------------
623 /* This copies the package source cache and then merges the status and
624 xstatus files into it. */
625 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
)
627 Progress
.OverallProgress(0,1,1,"Reading Package Lists");
629 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
630 bool SrcOk
= pkgSrcCacheCheck(List
);
631 bool PkgOk
= SrcOk
&& pkgPkgCacheCheck(CacheFile
);
633 // Rebuild the source and package caches
636 string SCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
637 string ListDir
= _config
->FindDir("Dir::State::lists");
638 FileFd
SCacheF(SCacheFile
,FileFd::WriteEmpty
);
639 FileFd
CacheF(CacheFile
,FileFd::WriteEmpty
);
640 DynamicMMap
Map(CacheF
,MMap::Public
);
641 if (_error
->PendingError() == true)
644 pkgCacheGenerator
Gen(Map
,Progress
);
646 // Prepare the progress indicator
647 unsigned long TotalSize
= 0;
649 for (pkgSourceList::const_iterator I
= List
.begin(); I
!= List
.end(); I
++)
651 string File
= ListDir
+ URItoFileName(I
->PackagesURI());
652 if (stat(File
.c_str(),&Buf
) != 0)
654 TotalSize
+= Buf
.st_size
;
657 if (pkgAddSourcesSize(TotalSize
) == false)
660 // Generate the pkg source cache
661 unsigned long CurrentSize
= 0;
662 for (pkgSourceList::const_iterator I
= List
.begin(); I
!= List
.end(); I
++)
664 string File
= ListDir
+ URItoFileName(I
->PackagesURI());
666 if (FileExists(File
) == false)
669 FileFd
Pkg(File
,FileFd::ReadOnly
);
670 debListParser
Parser(Pkg
);
671 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),"Reading Package Lists");
672 if (_error
->PendingError() == true)
673 return _error
->Error("Problem opening %s",File
.c_str());
674 CurrentSize
+= Pkg
.Size();
676 Progress
.SubProgress(0,I
->PackagesInfo());
677 if (Gen
.SelectFile(File
) == false)
678 return _error
->Error("Problem with SelectFile %s",File
.c_str());
680 if (Gen
.MergeList(Parser
) == false)
681 return _error
->Error("Problem with MergeList %s",File
.c_str());
683 // Check the release file
684 string RFile
= ListDir
+ URItoFileName(I
->ReleaseURI());
685 if (FileExists(RFile
) == true)
687 FileFd
Rel(RFile
,FileFd::ReadOnly
);
688 if (_error
->PendingError() == true)
690 Parser
.LoadReleaseInfo(Gen
.GetCurFile(),Rel
);
694 // Write the src cache
695 Gen
.GetCache().HeaderP
->Dirty
= false;
696 if (SCacheF
.Write(Map
.Data(),Map
.Size()) == false)
697 return _error
->Error("IO Error saving source cache");
698 Gen
.GetCache().HeaderP
->Dirty
= true;
700 // Merge in the source caches
701 return pkgMergeStatus(Progress
,Gen
,CurrentSize
,TotalSize
);
706 Progress
.OverallProgress(1,1,1,"Reading Package Lists");
710 // We use the source cache to generate the package cache
711 string SCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
713 FileFd
SCacheF(SCacheFile
,FileFd::ReadOnly
);
714 FileFd
CacheF(CacheFile
,FileFd::WriteEmpty
);
715 DynamicMMap
Map(CacheF
,MMap::Public
);
716 if (_error
->PendingError() == true)
719 // Preload the map with the source cache
720 if (SCacheF
.Read((unsigned char *)Map
.Data() + Map
.RawAllocate(SCacheF
.Size()),
721 SCacheF
.Size()) == false)
724 pkgCacheGenerator
Gen(Map
,Progress
);
726 // Compute the progress
727 unsigned long TotalSize
= 0;
728 if (pkgAddSourcesSize(TotalSize
) == false)
731 unsigned long CurrentSize
= 0;
732 return pkgMergeStatus(Progress
,Gen
,CurrentSize
,TotalSize
);