]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
825af40c0ac1fc21e4cc84bfccb7426bc8e13201
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.15 1998/09/07 05:28:37 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>
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]));
50 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
51 // ---------------------------------------------------------------------
52 /* We sync the data then unset the dirty flag in two steps so as to
53 advoid a problem during a crash */
54 pkgCacheGenerator::~pkgCacheGenerator()
56 if (_error
->PendingError() == true)
58 if (Map
.Sync() == false)
61 Cache
.HeaderP
->Dirty
= false;
62 Map
.Sync(0,sizeof(pkgCache::Header
));
65 // CacheGenerator::MergeList - Merge the package list /*{{{*/
66 // ---------------------------------------------------------------------
67 /* This provides the generation of the entries in the cache. Each loop
68 goes through a single package record from the underlying parse engine. */
69 bool pkgCacheGenerator::MergeList(ListParser
&List
)
74 while (List
.Step() == true)
76 // Get a pointer to the package structure
77 string PackageName
= List
.Package();
78 pkgCache::PkgIterator Pkg
;
79 if (NewPackage(Pkg
,PackageName
) == false)
80 return _error
->Error("Error occured while processing %s (NewPackage)",PackageName
.c_str());
82 if (Counter
% 100 == 0)
83 Progress
.Progress(List
.Offset());
85 /* Get a pointer to the version structure. We know the list is sorted
86 so we use that fact in the search. Insertion of new versions is
87 done with correct sorting */
88 string Version
= List
.Version();
89 if (Version
.empty() == true)
91 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
92 return _error
->Error("Error occured while processing %s (UsePackage1)",PackageName
.c_str());
96 pkgCache::VerIterator Ver
= Pkg
.VersionList();
97 unsigned long *Last
= &Pkg
->VersionList
;
99 for (; Ver
.end() == false; Last
= &Ver
->NextVer
, Ver
++)
101 Res
= pkgVersionCompare(Version
.begin(),Version
.end(),Ver
.VerStr(),
102 Ver
.VerStr() + strlen(Ver
.VerStr()));
107 /* We already have a version for this item, record that we
111 if (List
.UsePackage(Pkg
,Ver
) == false)
112 return _error
->Error("Error occured while processing %s (UsePackage2)",PackageName
.c_str());
114 if (NewFileVer(Ver
,List
) == false)
115 return _error
->Error("Error occured while processing %s (NewFileVer1)",PackageName
.c_str());
121 *Last
= NewVersion(Ver
,Version
,*Last
);
122 Ver
->ParentPkg
= Pkg
.Index();
123 if (List
.NewVersion(Ver
) == false)
124 return _error
->Error("Error occured while processing %s (NewVersion1)",PackageName
.c_str());
126 if (List
.UsePackage(Pkg
,Ver
) == false)
127 return _error
->Error("Error occured while processing %s (UsePackage3)",PackageName
.c_str());
129 if (NewFileVer(Ver
,List
) == false)
130 return _error
->Error("Error occured while processing %s (NewVersion2)",PackageName
.c_str());
136 // CacheGenerator::NewPackage - Add a new package /*{{{*/
137 // ---------------------------------------------------------------------
138 /* This creates a new package structure and adds it to the hash table */
139 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,string Name
)
141 Pkg
= Cache
.FindPkg(Name
);
142 if (Pkg
.end() == false)
146 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
150 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
152 // Insert it into the hash table
153 unsigned long Hash
= Cache
.Hash(Name
);
154 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
155 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
157 // Set the name and the ID
158 Pkg
->Name
= Map
.WriteString(Name
);
161 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
166 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
167 // ---------------------------------------------------------------------
169 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
173 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
177 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
178 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
179 VF
->NextFile
= Ver
->FileList
;
180 Ver
->FileList
= VF
.Index();
181 VF
->Offset
= List
.Offset();
182 VF
->Size
= List
.Size();
183 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
184 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
188 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
189 // ---------------------------------------------------------------------
190 /* This puts a version structure in the linked list */
191 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
196 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
201 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
203 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
204 Ver
->VerStr
= Map
.WriteString(VerStr
);
205 if (Ver
->VerStr
== 0)
211 // ListParser::NewDepends - Create a dependency element /*{{{*/
212 // ---------------------------------------------------------------------
213 /* This creates a dependency element in the tree. It is linked to the
214 version and to the package that it is pointing to. */
215 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
221 pkgCache
&Cache
= Owner
->Cache
;
224 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
229 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
230 Dep
->ParentVer
= Ver
.Index();
233 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
235 // Locate the target package
236 pkgCache::PkgIterator Pkg
;
237 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
240 // Probe the reverse dependency list for a version string that matches
241 if (Version
.empty() == false)
243 for (pkgCache::DepIterator I
= Pkg
.RevDependsList(); I
.end() == false; I
++)
244 if (I
->Version
!= 0 && I
.TargetVer() == Version
)
245 Dep
->Version
= I
->Version
;
246 if (Dep
->Version
== 0)
247 if ((Dep
->Version
= WriteString(Version
)) == 0)
251 // Link it to the package
252 Dep
->Package
= Pkg
.Index();
253 Dep
->NextRevDepends
= Pkg
->RevDepends
;
254 Pkg
->RevDepends
= Dep
.Index();
256 // Link it to the version (at the end of the list)
257 unsigned long *Last
= &Ver
->DependsList
;
258 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
259 Last
= &D
->NextDepends
;
260 Dep
->NextDepends
= *Last
;
266 // ListParser::NewProvides - Create a Provides element /*{{{*/
267 // ---------------------------------------------------------------------
269 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
273 pkgCache
&Cache
= Owner
->Cache
;
275 // We do not add self referencing provides
276 if (Ver
.ParentPkg().Name() == PackageName
)
280 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
285 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
286 Prv
->Version
= Ver
.Index();
287 Prv
->NextPkgProv
= Ver
->ProvidesList
;
288 Ver
->ProvidesList
= Prv
.Index();
289 if (Version
.empty() == false && (Prv
->Version
= WriteString(Version
)) == 0)
292 // Locate the target package
293 pkgCache::PkgIterator Pkg
;
294 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
297 // Link it to the package
298 Prv
->ParentPkg
= Pkg
.Index();
299 Prv
->NextProvides
= Pkg
->ProvidesList
;
300 Pkg
->ProvidesList
= Prv
.Index();
305 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
306 // ---------------------------------------------------------------------
307 /* This is used to select which file is to be associated with all newly
309 bool pkgCacheGenerator::SelectFile(string File
,unsigned long Flags
)
312 if (stat(File
.c_str(),&Buf
) == -1)
313 return _error
->Errno("stat","Couldn't stat ",File
.c_str());
315 // Get some space for the structure
316 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
317 if (CurrentFile
== Cache
.PkgFileP
)
321 CurrentFile
->FileName
= Map
.WriteString(File
);
322 CurrentFile
->Size
= Buf
.st_size
;
323 CurrentFile
->mtime
= Buf
.st_mtime
;
324 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
325 CurrentFile
->Flags
= Flags
;
327 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
328 Cache
.HeaderP
->PackageFileCount
++;
330 if (CurrentFile
->FileName
== 0)
333 Progress
.SubProgress(Buf
.st_size
);
337 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
338 // ---------------------------------------------------------------------
339 /* This is used to create handles to strings. Given the same text it
340 always returns the same number */
341 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
344 // Search for an insertion point
345 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
347 unsigned long *Last
= &Cache
.HeaderP
->StringList
;
348 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
349 I
= Cache
.StringItemP
+ I
->NextItem
)
351 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
361 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
365 // Fill in the structure
366 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
367 ItemP
->NextItem
= I
- Cache
.StringItemP
;
369 ItemP
->String
= Map
.WriteString(S
,Size
);
370 if (ItemP
->String
== 0)
373 return ItemP
->String
;
377 // SrcCacheCheck - Check if the source package cache is uptodate /*{{{*/
378 // ---------------------------------------------------------------------
379 /* The source cache is checked against the source list and the files
380 on disk, any difference results in a false. */
381 bool pkgSrcCacheCheck(pkgSourceList
&List
)
383 if (_error
->PendingError() == true)
386 // Open the source package cache
387 string CacheFile
= _config
->FindDir("Dir::Cache::srcpkgcache");
388 string ListDir
= _config
->FindDir("Dir::State::lists");
389 if (FileExists(CacheFile
) == false)
392 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
393 if (_error
->PendingError() == true)
399 MMap
Map(CacheF
,MMap::Public
| MMap::ReadOnly
);
400 if (_error
->PendingError() == true)
407 if (_error
->PendingError() == true)
413 // They are certianly out of sync
414 if (Cache
.Head().PackageFileCount
!= List
.size())
417 for (pkgCache::PkgFileIterator
F(Cache
); F
.end() == false; F
++)
419 // Search for a match in the source list
421 for (pkgSourceList::const_iterator I
= List
.begin();
422 I
!= List
.end(); I
++)
424 string File
= ListDir
+ URItoFileName(I
->PackagesURI());
425 if (F
.FileName() == File
)
432 // Check if the file matches what was cached
441 // PkgCacheCheck - Check if the package cache is uptodate /*{{{*/
442 // ---------------------------------------------------------------------
443 /* This does a simple check of all files used to compose the cache */
444 bool pkgPkgCacheCheck(string CacheFile
)
446 if (_error
->PendingError() == true)
449 // Open the source package cache
450 if (FileExists(CacheFile
) == false)
453 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
454 if (_error
->PendingError() == true)
460 MMap
Map(CacheF
,MMap::Public
| MMap::ReadOnly
);
461 if (_error
->PendingError() == true)
468 if (_error
->PendingError() == true)
475 for (pkgCache::PkgFileIterator
F(Cache
); F
.end() == false; F
++)
476 if (F
.IsOk() == false)
481 // AddSourcesSize - Add the size of the status files /*{{{*/
482 // ---------------------------------------------------------------------
483 /* This adds the size of all the status files to the size counter */
484 static bool pkgAddSourcesSize(unsigned long &TotalSize
)
486 // Grab the file names
487 string xstatus
= _config
->FindDir("Dir::State::xstatus");
488 string userstatus
= _config
->FindDir("Dir::State::userstatus");
489 string status
= _config
->FindDir("Dir::State::status");
493 if (stat(xstatus
.c_str(),&Buf
) == 0)
494 TotalSize
+= Buf
.st_size
;
495 if (stat(userstatus
.c_str(),&Buf
) == 0)
496 TotalSize
+= Buf
.st_size
;
497 if (stat(status
.c_str(),&Buf
) != 0)
498 return _error
->Errno("stat","Couldn't stat the status file %s",status
.c_str());
499 TotalSize
+= Buf
.st_size
;
504 // MergeStatus - Add the status files to the cache /*{{{*/
505 // ---------------------------------------------------------------------
506 /* This adds the status files to the map */
507 static bool pkgMergeStatus(OpProgress
&Progress
,pkgCacheGenerator
&Gen
,
508 unsigned long &CurrentSize
,unsigned long TotalSize
)
510 // Grab the file names
512 Status
[0] = _config
->FindDir("Dir::State::xstatus");
513 Status
[1]= _config
->FindDir("Dir::State::userstatus");
514 Status
[2] = _config
->FindDir("Dir::State::status");
516 for (int I
= 0; I
!= 3; I
++)
518 // Check if the file exists and it is not the primary status file.
519 string File
= Status
[I
];
520 if (I
!= 2 && FileExists(File
) == false)
523 FileFd
Pkg(File
,FileFd::ReadOnly
);
524 debListParser
Parser(Pkg
);
525 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),"Reading Package Lists");
526 if (_error
->PendingError() == true)
527 return _error
->Error("Problem opening %s",File
.c_str());
528 CurrentSize
+= Pkg
.Size();
530 Progress
.SubProgress(0,"Local Package State - " + flNotDir(File
));
531 if (Gen
.SelectFile(File
,pkgCache::Flag::NotSource
) == false)
532 return _error
->Error("Problem with SelectFile %s",File
.c_str());
534 if (Gen
.MergeList(Parser
) == false)
535 return _error
->Error("Problem with MergeList %s",File
.c_str());
536 Progress
.Progress(Pkg
.Size());
542 // MakeStatusCache - Generates a cache that includes the status files /*{{{*/
543 // ---------------------------------------------------------------------
544 /* This copies the package source cache and then merges the status and
545 xstatus files into it. */
546 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
)
548 Progress
.OverallProgress(0,1,1,"Reading Package Lists");
550 string CacheFile
= _config
->FindDir("Dir::Cache::pkgcache");
551 bool SrcOk
= pkgSrcCacheCheck(List
);
552 bool PkgOk
= pkgPkgCacheCheck(CacheFile
);
554 // Rebuild the source and package caches
557 string SCacheFile
= _config
->FindDir("Dir::Cache::srcpkgcache");
558 string ListDir
= _config
->FindDir("Dir::State::lists");
560 FileFd
SCacheF(SCacheFile
,FileFd::WriteEmpty
);
561 FileFd
CacheF(CacheFile
,FileFd::WriteEmpty
);
562 DynamicMMap
Map(CacheF
,MMap::Public
);
563 if (_error
->PendingError() == true)
566 pkgCacheGenerator
Gen(Map
,Progress
);
568 // Prepare the progress indicator
569 unsigned long TotalSize
= 0;
571 for (pkgSourceList::const_iterator I
= List
.begin(); I
!= List
.end(); I
++)
573 string File
= ListDir
+ URItoFileName(I
->PackagesURI());
574 if (stat(File
.c_str(),&Buf
) != 0)
575 return _error
->Errno("stat","Couldn't stat source package list %s",File
.c_str());
576 TotalSize
+= Buf
.st_size
;
579 if (pkgAddSourcesSize(TotalSize
) == false)
582 // Generate the pkg source cache
583 unsigned long CurrentSize
= 0;
584 for (pkgSourceList::const_iterator I
= List
.begin(); I
!= List
.end(); I
++)
586 string File
= ListDir
+ URItoFileName(I
->PackagesURI());
587 FileFd
Pkg(File
,FileFd::ReadOnly
);
588 debListParser
Parser(Pkg
);
589 Progress
.OverallProgress(CurrentSize
,TotalSize
,Pkg
.Size(),"Reading Package Lists");
590 if (_error
->PendingError() == true)
591 return _error
->Error("Problem opening %s",File
.c_str());
592 CurrentSize
+= Pkg
.Size();
594 Progress
.SubProgress(0,I
->PackagesInfo());
595 if (Gen
.SelectFile(File
) == false)
596 return _error
->Error("Problem with SelectFile %s",File
.c_str());
598 if (Gen
.MergeList(Parser
) == false)
599 return _error
->Error("Problem with MergeList %s",File
.c_str());
602 // Write the src cache
603 Gen
.GetCache().HeaderP
->Dirty
= false;
604 if (SCacheF
.Write(Map
.Data(),Map
.Size()) == false)
605 return _error
->Error("IO Error saving source cache");
606 Gen
.GetCache().HeaderP
->Dirty
= true;
608 // Merge in the source caches
609 return pkgMergeStatus(Progress
,Gen
,CurrentSize
,TotalSize
);
614 Progress
.OverallProgress(1,1,1,"Reading Package Lists");
618 // We use the source cache to generate the package cache
619 string SCacheFile
= _config
->FindDir("Dir::Cache::srcpkgcache");
621 FileFd
SCacheF(SCacheFile
,FileFd::ReadOnly
);
622 FileFd
CacheF(CacheFile
,FileFd::WriteEmpty
);
623 DynamicMMap
Map(CacheF
,MMap::Public
);
624 if (_error
->PendingError() == true)
627 // Preload the map with the source cache
628 if (SCacheF
.Read((unsigned char *)Map
.Data() + Map
.RawAllocate(SCacheF
.Size()),
629 SCacheF
.Size()) == false)
632 pkgCacheGenerator
Gen(Map
,Progress
);
634 // Compute the progress
635 unsigned long TotalSize
= 0;
636 if (pkgAddSourcesSize(TotalSize
) == false)
639 unsigned long CurrentSize
= 0;
640 return pkgMergeStatus(Progress
,Gen
,CurrentSize
,TotalSize
);