]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz 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 /*{{{*/
13 #define APT_COMPATIBILITY 986
15 #include <apt-pkg/pkgcachegen.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/version.h>
18 #include <apt-pkg/progress.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/sptr.h>
23 #include <apt-pkg/pkgsystem.h>
25 #include <apt-pkg/tagfile.h>
37 typedef vector
<pkgIndexFile
*>::iterator FileIterator
;
39 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
40 // ---------------------------------------------------------------------
41 /* We set the diry flag and make sure that is written to the disk */
42 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
43 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
47 memset(UniqHash
,0,sizeof(UniqHash
));
49 if (_error
->PendingError() == true)
54 // Setup the map interface..
55 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
56 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
59 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
62 *Cache
.HeaderP
= pkgCache::Header();
63 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
64 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
69 // Map directly from the existing file
71 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
72 if (Cache
.VS
!= _system
->VS
)
74 _error
->Error(_("Cache has an incompatible versioning system"));
79 Cache
.HeaderP
->Dirty
= true;
80 Map
.Sync(0,sizeof(pkgCache::Header
));
83 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
84 // ---------------------------------------------------------------------
85 /* We sync the data then unset the dirty flag in two steps so as to
86 advoid a problem during a crash */
87 pkgCacheGenerator::~pkgCacheGenerator()
89 if (_error
->PendingError() == true)
91 if (Map
.Sync() == false)
94 Cache
.HeaderP
->Dirty
= false;
95 Map
.Sync(0,sizeof(pkgCache::Header
));
98 // CacheGenerator::MergeList - Merge the package list /*{{{*/
99 // ---------------------------------------------------------------------
100 /* This provides the generation of the entries in the cache. Each loop
101 goes through a single package record from the underlying parse engine. */
102 bool pkgCacheGenerator::MergeList(ListParser
&List
,
103 pkgCache::VerIterator
*OutVer
)
107 unsigned int Counter
= 0;
108 while (List
.Step() == true)
110 // Get a pointer to the package structure
111 string
const PackageName
= List
.Package();
112 if (PackageName
.empty() == true)
115 pkgCache::PkgIterator Pkg
;
116 if (NewPackage(Pkg
, PackageName
, List
.Architecture()) == false)
117 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str());
119 if (Counter
% 100 == 0 && Progress
!= 0)
120 Progress
->Progress(List
.Offset());
122 /* Get a pointer to the version structure. We know the list is sorted
123 so we use that fact in the search. Insertion of new versions is
124 done with correct sorting */
125 string Version
= List
.Version();
126 if (Version
.empty() == true)
128 // we first process the package, then the descriptions
129 // (this has the bonus that we get MMap error when we run out
131 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
132 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
133 PackageName
.c_str());
135 // Find the right version to write the description
136 MD5SumValue CurMd5
= List
.Description_md5();
137 pkgCache::VerIterator Ver
= Pkg
.VersionList();
138 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
140 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
142 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
143 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
144 bool duplicate
=false;
146 // don't add a new description if we have one for the given
148 for ( ; Desc
.end() == false; Desc
++)
149 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
150 Desc
.LanguageCode() == List
.DescriptionLanguage())
155 for (Desc
= Ver
.DescriptionList();
157 LastDesc
= &Desc
->NextDesc
, Desc
++)
159 if (MD5SumValue(Desc
.md5()) == CurMd5
)
161 // Add new description
162 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
163 Desc
->ParentPkg
= Pkg
.Index();
165 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
166 return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName
.c_str());
175 pkgCache::VerIterator Ver
= Pkg
.VersionList();
176 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
178 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
180 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
185 /* We already have a version for this item, record that we
187 unsigned long Hash
= List
.VersionHash();
188 if (Res
== 0 && Ver
->Hash
== Hash
)
190 if (List
.UsePackage(Pkg
,Ver
) == false)
191 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
192 PackageName
.c_str());
194 if (NewFileVer(Ver
,List
) == false)
195 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
196 PackageName
.c_str());
198 // Read only a single record and return
202 FoundFileDeps
|= List
.HasFileDeps();
209 // Skip to the end of the same version set.
212 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
214 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
221 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
222 Ver
->ParentPkg
= Pkg
.Index();
225 if ((*LastVer
== 0 && _error
->PendingError()) || List
.NewVersion(Ver
) == false)
226 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
227 PackageName
.c_str());
229 if (List
.UsePackage(Pkg
,Ver
) == false)
230 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
231 PackageName
.c_str());
233 if (NewFileVer(Ver
,List
) == false)
234 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
235 PackageName
.c_str());
237 // Read only a single record and return
241 FoundFileDeps
|= List
.HasFileDeps();
245 /* Record the Description data. Description data always exist in
246 Packages and Translation-* files. */
247 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
248 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
250 // Skip to the end of description set
251 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
253 // Add new description
254 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
255 Desc
->ParentPkg
= Pkg
.Index();
257 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
258 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str());
261 FoundFileDeps
|= List
.HasFileDeps();
263 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
264 return _error
->Error(_("Wow, you exceeded the number of package "
265 "names this APT is capable of."));
266 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
267 return _error
->Error(_("Wow, you exceeded the number of versions "
268 "this APT is capable of."));
269 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
270 return _error
->Error(_("Wow, you exceeded the number of descriptions "
271 "this APT is capable of."));
272 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
273 return _error
->Error(_("Wow, you exceeded the number of dependencies "
274 "this APT is capable of."));
278 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
279 // ---------------------------------------------------------------------
280 /* If we found any file depends while parsing the main list we need to
281 resolve them. Since it is undesired to load the entire list of files
282 into the cache as virtual packages we do a two stage effort. MergeList
283 identifies the file depends and this creates Provdies for them by
284 re-parsing all the indexs. */
285 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
289 unsigned int Counter
= 0;
290 while (List
.Step() == true)
292 string PackageName
= List
.Package();
293 if (PackageName
.empty() == true)
295 string Version
= List
.Version();
296 if (Version
.empty() == true)
299 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
300 if (Pkg
.end() == true)
301 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
302 PackageName
.c_str());
304 if (Counter
% 100 == 0 && Progress
!= 0)
305 Progress
->Progress(List
.Offset());
307 unsigned long Hash
= List
.VersionHash();
308 pkgCache::VerIterator Ver
= Pkg
.VersionList();
309 for (; Ver
.end() == false; Ver
++)
311 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
313 if (List
.CollectFileProvides(Cache
,Ver
) == false)
314 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
319 if (Ver
.end() == true)
320 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
326 // CacheGenerator::NewGroup - Add a new group /*{{{*/
327 // ---------------------------------------------------------------------
328 /* This creates a new group structure and adds it to the hash table */
329 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
) {
330 Grp
= Cache
.FindGrp(Name
);
331 if (Grp
.end() == false)
335 unsigned long const Group
= Map
.Allocate(sizeof(pkgCache::Group
));
336 if (unlikely(Group
== 0))
339 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
340 Grp
->Name
= Map
.WriteString(Name
);
341 if (unlikely(Grp
->Name
== 0))
344 // Insert it into the hash table
345 unsigned long const Hash
= Cache
.Hash(Name
);
346 Grp
->Next
= Cache
.HeaderP
->GrpHashTable
[Hash
];
347 Cache
.HeaderP
->GrpHashTable
[Hash
] = Group
;
349 Cache
.HeaderP
->GroupCount
++;
354 // CacheGenerator::NewPackage - Add a new package /*{{{*/
355 // ---------------------------------------------------------------------
356 /* This creates a new package structure and adds it to the hash table */
357 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
358 const string
&Arch
) {
359 pkgCache::GrpIterator Grp
;
360 if (unlikely(NewGroup(Grp
, Name
) == false))
363 Pkg
= Grp
.FindPkg(Arch
);
364 if (Pkg
.end() == false)
368 unsigned long const Package
= Map
.Allocate(sizeof(pkgCache::Package
));
369 if (unlikely(Package
== 0))
371 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
373 // Insert it into the hash table
374 unsigned long const Hash
= Cache
.Hash(Name
);
375 Pkg
->NextPackage
= Cache
.HeaderP
->PkgHashTable
[Hash
];
376 Cache
.HeaderP
->PkgHashTable
[Hash
] = Package
;
378 // remember the packages in the group
379 Grp
->FirstPackage
= Package
;
380 if (Grp
->LastPackage
== 0)
381 Grp
->LastPackage
= Package
;
383 // Set the name, arch and the ID
384 Pkg
->Name
= Grp
->Name
;
385 Pkg
->Group
= Grp
.Index();
386 Pkg
->Arch
= WriteUniqString(Arch
.c_str());
387 if (unlikely(Pkg
->Arch
== 0))
389 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
394 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
395 // ---------------------------------------------------------------------
397 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
400 if (CurrentFile
== 0)
404 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
408 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
409 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
411 // Link it to the end of the list
412 map_ptrloc
*Last
= &Ver
->FileList
;
413 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
415 VF
->NextFile
= *Last
;
418 VF
->Offset
= List
.Offset();
419 VF
->Size
= List
.Size();
420 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
421 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
422 Cache
.HeaderP
->VerFileCount
++;
427 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
428 // ---------------------------------------------------------------------
429 /* This puts a version structure in the linked list */
430 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
431 const string
&VerStr
,
435 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
440 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
442 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
443 Ver
->VerStr
= Map
.WriteString(VerStr
);
444 if (Ver
->VerStr
== 0)
450 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
451 // ---------------------------------------------------------------------
453 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
456 if (CurrentFile
== 0)
460 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
464 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
465 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
467 // Link it to the end of the list
468 map_ptrloc
*Last
= &Desc
->FileList
;
469 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
472 DF
->NextFile
= *Last
;
475 DF
->Offset
= List
.Offset();
476 DF
->Size
= List
.Size();
477 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
478 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
479 Cache
.HeaderP
->DescFileCount
++;
484 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
485 // ---------------------------------------------------------------------
486 /* This puts a description structure in the linked list */
487 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
489 const MD5SumValue
&md5sum
,
493 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
494 if (Description
== 0)
498 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
499 Desc
->NextDesc
= Next
;
500 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
501 Desc
->language_code
= Map
.WriteString(Lang
);
502 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
503 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
509 // ListParser::NewDepends - Create a dependency element /*{{{*/
510 // ---------------------------------------------------------------------
511 /* This creates a dependency element in the tree. It is linked to the
512 version and to the package that it is pointing to. */
513 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
514 const string
&PackageName
,
516 const string
&Version
,
520 pkgCache
&Cache
= Owner
->Cache
;
523 unsigned long const Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
524 if (unlikely(Dependency
== 0))
528 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
529 Dep
->ParentVer
= Ver
.Index();
532 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
534 pkgCache::GrpIterator Grp
;
535 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
538 // Locate the target package
539 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(Arch
);
540 if (Pkg
.end() == true) {
541 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
545 // Probe the reverse dependency list for a version string that matches
546 if (Version
.empty() == false)
548 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
549 if (I->Version != 0 && I.TargetVer() == Version)
550 Dep->Version = I->Version;*/
551 if (Dep
->Version
== 0)
552 if (unlikely((Dep
->Version
= WriteString(Version
)) == 0))
556 // Link it to the package
557 Dep
->Package
= Pkg
.Index();
558 Dep
->NextRevDepends
= Pkg
->RevDepends
;
559 Pkg
->RevDepends
= Dep
.Index();
561 /* Link it to the version (at the end of the list)
562 Caching the old end point speeds up generation substantially */
563 if (OldDepVer
!= Ver
)
565 OldDepLast
= &Ver
->DependsList
;
566 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
567 OldDepLast
= &D
->NextDepends
;
571 // Is it a file dependency?
572 if (unlikely(PackageName
[0] == '/'))
573 FoundFileDeps
= true;
575 Dep
->NextDepends
= *OldDepLast
;
576 *OldDepLast
= Dep
.Index();
577 OldDepLast
= &Dep
->NextDepends
;
582 // ListParser::NewProvides - Create a Provides element /*{{{*/
583 // ---------------------------------------------------------------------
585 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
586 const string
&PackageName
,
587 const string
&Version
)
589 pkgCache
&Cache
= Owner
->Cache
;
591 // We do not add self referencing provides
592 if (unlikely(Ver
.ParentPkg().Name() == PackageName
))
596 unsigned long const Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
597 if (unlikely(Provides
== 0))
599 Cache
.HeaderP
->ProvidesCount
++;
602 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
603 Prv
->Version
= Ver
.Index();
604 Prv
->NextPkgProv
= Ver
->ProvidesList
;
605 Ver
->ProvidesList
= Prv
.Index();
606 if (Version
.empty() == false && unlikely((Prv
->ProvideVersion
= WriteString(Version
)) == 0))
609 // Locate the target package
610 pkgCache::PkgIterator Pkg
;
611 if (unlikely(Owner
->NewPackage(Pkg
,PackageName
,string(Ver
.Arch())) == false))
614 // Link it to the package
615 Prv
->ParentPkg
= Pkg
.Index();
616 Prv
->NextProvides
= Pkg
->ProvidesList
;
617 Pkg
->ProvidesList
= Prv
.Index();
622 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
623 // ---------------------------------------------------------------------
624 /* This is used to select which file is to be associated with all newly
625 added versions. The caller is responsible for setting the IMS fields. */
626 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
627 const pkgIndexFile
&Index
,
630 // Get some space for the structure
631 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
632 if (CurrentFile
== Cache
.PkgFileP
)
636 CurrentFile
->FileName
= Map
.WriteString(File
);
637 CurrentFile
->Site
= WriteUniqString(Site
);
638 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
639 CurrentFile
->Flags
= Flags
;
640 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
641 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
643 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
644 Cache
.HeaderP
->PackageFileCount
++;
646 if (CurrentFile
->FileName
== 0)
650 Progress
->SubProgress(Index
.Size());
654 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
655 // ---------------------------------------------------------------------
656 /* This is used to create handles to strings. Given the same text it
657 always returns the same number */
658 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
661 /* We use a very small transient hash table here, this speeds up generation
662 by a fair amount on slower machines */
663 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
665 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
666 return Bucket
->String
;
668 // Search for an insertion point
669 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
671 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
672 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
673 I
= Cache
.StringItemP
+ I
->NextItem
)
675 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
688 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
692 // Fill in the structure
693 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
694 ItemP
->NextItem
= I
- Cache
.StringItemP
;
696 ItemP
->String
= Map
.WriteString(S
,Size
);
697 if (ItemP
->String
== 0)
701 return ItemP
->String
;
704 // CheckValidity - Check that a cache is up-to-date /*{{{*/
705 // ---------------------------------------------------------------------
706 /* This just verifies that each file in the list of index files exists,
707 has matching attributes with the cache and the cache does not have
709 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
710 FileIterator End
,MMap
**OutMap
= 0)
712 // No file, certainly invalid
713 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
717 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
718 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
720 if (_error
->PendingError() == true || Map
->Size() == 0)
726 /* Now we check every index file, see if it is in the cache,
727 verify the IMS data and check that it is on the disk too.. */
728 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
729 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
730 for (; Start
!= End
; Start
++)
732 if ((*Start
)->HasPackages() == false)
735 if ((*Start
)->Exists() == false)
737 #if 0 // mvo: we no longer give a message here (Default Sources spec)
738 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
739 (*Start
)->Describe().c_str());
744 // FindInCache is also expected to do an IMS check.
745 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
746 if (File
.end() == true)
749 Visited
[File
->ID
] = true;
752 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
753 if (Visited
[I
] == false)
756 if (_error
->PendingError() == true)
763 *OutMap
= Map
.UnGuard();
767 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
768 // ---------------------------------------------------------------------
769 /* Size is kind of an abstract notion that is only used for the progress
771 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
773 unsigned long TotalSize
= 0;
774 for (; Start
!= End
; Start
++)
776 if ((*Start
)->HasPackages() == false)
778 TotalSize
+= (*Start
)->Size();
783 // BuildCache - Merge the list of index files into the cache /*{{{*/
784 // ---------------------------------------------------------------------
786 static bool BuildCache(pkgCacheGenerator
&Gen
,
787 OpProgress
&Progress
,
788 unsigned long &CurrentSize
,unsigned long TotalSize
,
789 FileIterator Start
, FileIterator End
)
792 for (I
= Start
; I
!= End
; I
++)
794 if ((*I
)->HasPackages() == false)
797 if ((*I
)->Exists() == false)
800 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
802 _error
->Warning("Duplicate sources.list entry %s",
803 (*I
)->Describe().c_str());
807 unsigned long Size
= (*I
)->Size();
808 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
811 if ((*I
)->Merge(Gen
,Progress
) == false)
815 if (Gen
.HasFileDeps() == true)
818 TotalSize
= ComputeSize(Start
, End
);
820 for (I
= Start
; I
!= End
; I
++)
822 unsigned long Size
= (*I
)->Size();
823 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
825 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
833 // MakeStatusCache - Construct the status cache /*{{{*/
834 // ---------------------------------------------------------------------
835 /* This makes sure that the status cache (the cache that has all
836 index files from the sources list and all local ones) is ready
837 to be mmaped. If OutMap is not zero then a MMap object representing
838 the cache will be stored there. This is pretty much mandetory if you
839 are using AllowMem. AllowMem lets the function be run as non-root
840 where it builds the cache 'fast' into a memory buffer. */
841 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
842 MMap
**OutMap
,bool AllowMem
)
844 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
846 vector
<pkgIndexFile
*> Files
;
847 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
851 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
852 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
855 Files
.push_back (*j
);
858 unsigned long EndOfSource
= Files
.size();
859 if (_system
->AddStatusFiles(Files
) == false)
862 // Decide if we can write to the files..
863 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
864 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
866 // Decide if we can write to the cache
867 bool Writeable
= false;
868 if (CacheFile
.empty() == false)
869 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
871 if (SrcCacheFile
.empty() == false)
872 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
874 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
875 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
877 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
880 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
882 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
886 /* At this point we know we need to reconstruct the package cache,
889 SPtr
<DynamicMMap
> Map
;
890 if (Writeable
== true && CacheFile
.empty() == false)
892 unlink(CacheFile
.c_str());
893 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
894 fchmod(CacheF
->Fd(),0644);
895 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
896 if (_error
->PendingError() == true)
901 // Just build it in memory..
902 Map
= new DynamicMMap(0,MapSize
);
905 // Lets try the source cache.
906 unsigned long CurrentSize
= 0;
907 unsigned long TotalSize
= 0;
908 if (CheckValidity(SrcCacheFile
,Files
.begin(),
909 Files
.begin()+EndOfSource
) == true)
911 // Preload the map with the source cache
912 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
913 unsigned long alloc
= Map
->RawAllocate(SCacheF
.Size());
914 if ((alloc
== 0 && _error
->PendingError())
915 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
916 SCacheF
.Size()) == false)
919 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
921 // Build the status cache
922 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
923 if (_error
->PendingError() == true)
925 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
926 Files
.begin()+EndOfSource
,Files
.end()) == false)
931 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
933 // Build the source cache
934 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
935 if (_error
->PendingError() == true)
937 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
938 Files
.begin(),Files
.begin()+EndOfSource
) == false)
942 if (Writeable
== true && SrcCacheFile
.empty() == false)
944 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
945 if (_error
->PendingError() == true)
948 fchmod(SCacheF
.Fd(),0644);
950 // Write out the main data
951 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
952 return _error
->Error(_("IO Error saving source cache"));
955 // Write out the proper header
956 Gen
.GetCache().HeaderP
->Dirty
= false;
957 if (SCacheF
.Seek(0) == false ||
958 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
959 return _error
->Error(_("IO Error saving source cache"));
960 Gen
.GetCache().HeaderP
->Dirty
= true;
964 // Build the status cache
965 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
966 Files
.begin()+EndOfSource
,Files
.end()) == false)
970 if (_error
->PendingError() == true)
976 delete Map
.UnGuard();
977 *OutMap
= new MMap(*CacheF
,0);
981 *OutMap
= Map
.UnGuard();
988 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
989 // ---------------------------------------------------------------------
991 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
993 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
994 vector
<pkgIndexFile
*> Files
;
995 unsigned long EndOfSource
= Files
.size();
996 if (_system
->AddStatusFiles(Files
) == false)
999 SPtr
<DynamicMMap
> Map
= new DynamicMMap(0,MapSize
);
1000 unsigned long CurrentSize
= 0;
1001 unsigned long TotalSize
= 0;
1003 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1005 // Build the status cache
1006 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
1007 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1008 if (_error
->PendingError() == true)
1010 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1011 Files
.begin()+EndOfSource
,Files
.end()) == false)
1014 if (_error
->PendingError() == true)
1016 *OutMap
= Map
.UnGuard();