]>
git.saurik.com Git - apt-legacy.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>
24 #include <apt-pkg/macros.h>
26 #include <apt-pkg/tagfile.h>
37 #include <apt-pkg/deblistparser.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
),
49 memset(UniqHash
,0,sizeof(UniqHash
));
51 if (_error
->PendingError() == true)
56 // Setup the map interface..
57 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
58 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
61 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
64 *Cache
.HeaderP
= pkgCache::Header();
65 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
66 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
71 // Map directly from the existing file
73 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
74 if (Cache
.VS
!= _system
->VS
)
76 _error
->Error(_("Cache has an incompatible versioning system"));
81 Cache
.HeaderP
->Dirty
= true;
82 Map
.Sync(0,sizeof(pkgCache::Header
));
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 */
89 pkgCacheGenerator::~pkgCacheGenerator()
91 if (_error
->PendingError() == true)
93 if (Map
.Sync() == false)
96 Cache
.HeaderP
->Dirty
= false;
97 Map
.Sync(0,sizeof(pkgCache::Header
));
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. */
104 bool pkgCacheGenerator::MergeList(ListParser
&List
,
105 pkgCache::VerIterator
*OutVer
)
108 debListParser
*debian(dynamic_cast<debListParser
*>(&List
));
110 unsigned int Counter
= 0;
112 while (List
.Step() == true)
114 // Get a pointer to the package structure
115 srkString PackageName
;
117 PackageName
= debian
->Find("Package");
119 PackageName
= List
.Package();
120 if (PackageName
.empty() == true)
123 pkgCache::PkgIterator Pkg
;
124 if (NewPackage(Pkg
,PackageName
) == false) {
125 _error
->Warning(_("Error occurred while processing %s (NewPackage)"),std::string(PackageName
).c_str());
130 if (Counter
% 100 == 0 && Progress
!= 0)
131 Progress
->Progress(List
.Offset());
133 string
language(List
.DescriptionLanguage());
135 /* Get a pointer to the version structure. We know the list is sorted
136 so we use that fact in the search. Insertion of new versions is
137 done with correct sorting */
140 Version
= debian
->Find("Version");
142 Version
= List
.Version();
143 if (Version
.empty() == true)
145 // we first process the package, then the descriptions
146 // (this has the bonus that we get MMap error when we run out
148 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false) {
149 _error
->Warning(_("Error occurred while processing %s (UsePackage1)"),
150 std::string(PackageName
).c_str());
154 // Find the right version to write the description
155 MD5SumValue CurMd5
= List
.Description_md5();
156 pkgCache::VerIterator Ver
= Pkg
.VersionList();
157 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
159 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
161 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
162 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
163 bool duplicate
=false;
165 // don't add a new description if we have one for the given
167 for ( ; Desc
.end() == false; Desc
++)
168 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
169 Desc
.LanguageCode() == language
)
174 for (Desc
= Ver
.DescriptionList();
176 LastDesc
= &Desc
->NextDesc
, Desc
++)
178 if (MD5SumValue(Desc
.md5()) == CurMd5
)
180 // Add new description
181 *LastDesc
= NewDescription(Desc
, language
, CurMd5
, *LastDesc
);
182 Desc
->ParentPkg
= Pkg
.Index();
184 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false) {
185 _error
->Warning(_("Error occurred while processing %s (NewFileDesc1)"),std::string(PackageName
).c_str());
196 pkgCache::VerIterator Ver
= Pkg
.VersionList();
197 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
199 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
201 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
206 /* We already have a version for this item, record that we
208 unsigned long Hash
= List
.VersionHash();
209 if (Res
== 0 && Ver
->Hash
== Hash
)
211 if (List
.UsePackage(Pkg
,Ver
) == false) {
212 _error
->Warning(_("Error occurred while processing %s (UsePackage2)"),
213 std::string(PackageName
).c_str());
217 if (NewFileVer(Ver
,List
) == false) {
218 _error
->Warning(_("Error occurred while processing %s (NewFileVer1)"),
219 std::string(PackageName
).c_str());
223 // Read only a single record and return
227 FoundFileDeps
|= List
.HasFileDeps();
234 // Skip to the end of the same version set.
237 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
239 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
246 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
247 Ver
->ParentPkg
= Pkg
.Index();
250 if ((*LastVer
== 0 && _error
->PendingError()) || List
.NewVersion(Ver
) == false) {
251 _error
->Warning(_("Error occurred while processing %s (NewVersion1)"),
252 std::string(PackageName
).c_str());
256 if (List
.UsePackage(Pkg
,Ver
) == false) {
257 _error
->Warning(_("Error occurred while processing %s (UsePackage3)"),
258 std::string(PackageName
).c_str());
262 if (NewFileVer(Ver
,List
) == false) {
263 _error
->Warning(_("Error occurred while processing %s (NewVersion2)"),
264 std::string(PackageName
).c_str());
268 // Read only a single record and return
272 FoundFileDeps
|= List
.HasFileDeps();
276 /* Record the Description data. Description data always exist in
277 Packages and Translation-* files. */
278 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
279 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
281 // Skip to the end of description set
282 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
284 // Add new description
285 *LastDesc
= NewDescription(Desc
, language
, List
.Description_md5(), *LastDesc
);
286 Desc
->ParentPkg
= Pkg
.Index();
288 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false) {
289 _error
->Warning(_("Error occurred while processing %s (NewFileDesc2)"),std::string(PackageName
).c_str());
294 FoundFileDeps
|= List
.HasFileDeps();
296 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
297 return _error
->Error(_("Wow, you exceeded the number of package "
298 "names this APT is capable of."));
299 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID1
)*8+sizeof(Cache
.VerP
->ID2
)*8))-1)
300 return _error
->Error(_("Wow, you exceeded the number of versions "
301 "this APT is capable of."));
302 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
303 return _error
->Error(_("Wow, you exceeded the number of descriptions "
304 "this APT is capable of."));
305 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
306 return _error
->Error(_("Wow, you exceeded the number of dependencies "
307 "this APT is capable of."));
311 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
312 // ---------------------------------------------------------------------
313 /* If we found any file depends while parsing the main list we need to
314 resolve them. Since it is undesired to load the entire list of files
315 into the cache as virtual packages we do a two stage effort. MergeList
316 identifies the file depends and this creates Provdies for them by
317 re-parsing all the indexs. */
318 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
322 unsigned int Counter
= 0;
323 while (List
.Step() == true)
325 string PackageName
= List
.Package();
326 if (PackageName
.empty() == true)
328 string Version
= List
.Version();
329 if (Version
.empty() == true)
332 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
333 if (Pkg
.end() == true)
334 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
335 PackageName
.c_str());
337 if (Counter
% 100 == 0 && Progress
!= 0)
338 Progress
->Progress(List
.Offset());
340 unsigned long Hash
= List
.VersionHash();
341 pkgCache::VerIterator Ver
= Pkg
.VersionList();
342 for (; Ver
.end() == false; Ver
++)
344 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
346 if (List
.CollectFileProvides(Cache
,Ver
) == false)
347 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
352 if (Ver
.end() == true)
353 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
359 // CacheGenerator::NewPackage - Add a new package /*{{{*/
360 // ---------------------------------------------------------------------
361 /* This creates a new package structure and adds it to the hash table */
362 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
364 return NewPackage(Pkg
, srkString(Name
));
367 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const srkString
&Name
)
369 Pkg
= Cache
.FindPkg(Name
);
370 if (Pkg
.end() == false)
374 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
378 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
380 // Insert it into the hash table
381 unsigned long Hash
= Cache
.Hash(Name
);
382 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
383 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
385 // Set the name and the ID
386 Pkg
->Name
= Map
.WriteString(Name
.Start
,Name
.Size
);
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
,
434 return NewVersion(Ver
, srkString(VerStr
), Next
);
437 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
438 const srkString
&VerStr
,
442 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
447 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
449 unsigned int ID
= Cache
.HeaderP
->VersionCount
++;
450 Ver
->ID1
= ID
& 0xffff;
452 Ver
->VerStr
= Map
.WriteString(VerStr
.Start
, VerStr
.Size
);
453 if (Ver
->VerStr
== 0)
459 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
460 // ---------------------------------------------------------------------
462 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
465 if (CurrentFile
== 0)
469 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
473 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
474 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
476 // Link it to the end of the list
477 map_ptrloc
*Last
= &Desc
->FileList
;
478 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
481 DF
->NextFile
= *Last
;
484 DF
->Offset
= List
.Offset();
485 DF
->Size
= List
.Size();
486 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
487 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
488 Cache
.HeaderP
->DescFileCount
++;
493 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
494 // ---------------------------------------------------------------------
495 /* This puts a description structure in the linked list */
496 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
498 const MD5SumValue
&md5sum
,
502 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
503 if (Description
== 0)
507 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
508 Desc
->NextDesc
= Next
;
509 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
510 Desc
->language_code
= Map
.WriteString(Lang
);
511 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
512 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
518 // ListParser::NewDepends - Create a dependency element /*{{{*/
519 // ---------------------------------------------------------------------
520 /* This creates a dependency element in the tree. It is linked to the
521 version and to the package that it is pointing to. */
522 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
523 const string
&PackageName
,
524 const string
&Version
,
528 return NewDepends(Ver
, srkString(PackageName
), srkString(Version
), Op
, Type
);
531 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
532 const srkString
&PackageName
,
533 const srkString
&Version
,
537 pkgCache
&Cache
= Owner
->Cache
;
540 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
545 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
546 Dep
->ParentVer
= Ver
.Index();
549 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
551 // Locate the target package
552 pkgCache::PkgIterator Pkg
;
553 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
556 // Probe the reverse dependency list for a version string that matches
557 if (Version
.empty() == false)
559 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
560 if (I->Version != 0 && I.TargetVer() == Version)
561 Dep->Version = I->Version;*/
562 if (Dep
->Version
== 0)
563 if ((Dep
->Version
= WriteString(Version
)) == 0)
567 // Link it to the package
568 Dep
->Package
= Pkg
.Index();
569 Dep
->NextRevDepends
= Pkg
->RevDepends
;
570 Pkg
->RevDepends
= Dep
.Index();
572 /* Link it to the version (at the end of the list)
573 Caching the old end point speeds up generation substantially */
574 if (OldDepVer
!= Ver
)
576 OldDepLast
= &Ver
->DependsList
;
577 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
578 OldDepLast
= &D
->NextDepends
;
582 // Is it a file dependency?
583 if (PackageName
[0] == '/')
584 FoundFileDeps
= true;
586 Dep
->NextDepends
= *OldDepLast
;
587 *OldDepLast
= Dep
.Index();
588 OldDepLast
= &Dep
->NextDepends
;
593 // ListParser::NewProvides - Create a Provides element /*{{{*/
594 // ---------------------------------------------------------------------
596 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
597 const string
&PackageName
,
598 const string
&Version
)
600 return NewProvides(Ver
, srkString(PackageName
), srkString(Version
));
603 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
604 const srkString
&PackageName
,
605 const srkString
&Version
)
607 pkgCache
&Cache
= Owner
->Cache
;
609 // We do not add self referencing provides
610 if (Ver
.ParentPkg().Name() == PackageName
)
614 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
617 Cache
.HeaderP
->ProvidesCount
++;
620 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
621 Prv
->Version
= Ver
.Index();
622 Prv
->NextPkgProv
= Ver
->ProvidesList
;
623 Ver
->ProvidesList
= Prv
.Index();
624 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
627 // Locate the target package
628 pkgCache::PkgIterator Pkg
;
629 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
632 // Link it to the package
633 Prv
->ParentPkg
= Pkg
.Index();
634 Prv
->NextProvides
= Pkg
->ProvidesList
;
635 Pkg
->ProvidesList
= Prv
.Index();
640 // ListParser::NewTag - Create a Tag element /*{{{*/
641 // ---------------------------------------------------------------------
643 bool pkgCacheGenerator::ListParser::NewTag(pkgCache::PkgIterator Pkg
,
644 const char *NameStart
,
645 unsigned int NameSize
)
647 pkgCache
&Cache
= Owner
->Cache
;
650 unsigned long Tagg
= Owner
->Map
.Allocate(sizeof(pkgCache::Tag
));
653 Cache
.HeaderP
->TagCount
++;
656 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ Tagg
);
657 Tg
->Name
= WriteString(NameStart
,NameSize
);
660 Tg
->NextTag
= Pkg
->TagList
;
661 Pkg
->TagList
= Tg
.Index();
666 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
667 // ---------------------------------------------------------------------
668 /* This is used to select which file is to be associated with all newly
669 added versions. The caller is responsible for setting the IMS fields. */
670 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
671 const pkgIndexFile
&Index
,
674 // Get some space for the structure
675 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
676 if (CurrentFile
== Cache
.PkgFileP
)
680 CurrentFile
->FileName
= Map
.WriteString(File
);
681 CurrentFile
->Site
= WriteUniqString(Site
);
682 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
683 CurrentFile
->Flags
= Flags
;
684 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
685 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
687 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
688 Cache
.HeaderP
->PackageFileCount
++;
690 if (CurrentFile
->FileName
== 0)
694 Progress
->SubProgress(Index
.Size());
698 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
699 // ---------------------------------------------------------------------
700 /* This is used to create handles to strings. Given the same text it
701 always returns the same number */
702 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
705 /* We use a very small transient hash table here, this speeds up generation
706 by a fair amount on slower machines */
707 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
709 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
710 return Bucket
->String
;
712 // Search for an insertion point
713 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
715 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
716 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
717 I
= Cache
.StringItemP
+ I
->NextItem
)
719 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
732 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
736 // Fill in the structure
737 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
738 ItemP
->NextItem
= I
- Cache
.StringItemP
;
740 ItemP
->String
= Map
.WriteString(S
,Size
);
741 if (ItemP
->String
== 0)
745 return ItemP
->String
;
748 // CheckValidity - Check that a cache is up-to-date /*{{{*/
749 // ---------------------------------------------------------------------
750 /* This just verifies that each file in the list of index files exists,
751 has matching attributes with the cache and the cache does not have
753 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
754 FileIterator End
,MMap
**OutMap
= 0)
756 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
757 // No file, certainly invalid
758 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
761 std::clog
<< "CacheFile doesn't exist" << std::endl
;
766 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
767 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
769 if (_error
->PendingError() == true || Map
->Size() == 0)
772 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
777 /* Now we check every index file, see if it is in the cache,
778 verify the IMS data and check that it is on the disk too.. */
779 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
780 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
781 for (; Start
!= End
; Start
++)
784 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
785 if ((*Start
)->HasPackages() == false)
788 std::clog
<< "Has NO packages" << std::endl
;
792 if ((*Start
)->Exists() == false)
794 #if 0 // mvo: we no longer give a message here (Default Sources spec)
795 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
796 (*Start
)->Describe().c_str());
799 std::clog
<< "file doesn't exist" << std::endl
;
803 // FindInCache is also expected to do an IMS check.
804 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
805 if (File
.end() == true)
808 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
812 Visited
[File
->ID
] = true;
814 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
817 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
818 if (Visited
[I
] == false)
821 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
825 if (_error
->PendingError() == true)
829 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
830 _error
->DumpErrors();
837 *OutMap
= Map
.UnGuard();
841 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
842 // ---------------------------------------------------------------------
843 /* Size is kind of an abstract notion that is only used for the progress
845 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
847 unsigned long TotalSize
= 0;
848 for (; Start
!= End
; Start
++)
850 if ((*Start
)->HasPackages() == false)
852 TotalSize
+= (*Start
)->Size();
857 // BuildCache - Merge the list of index files into the cache /*{{{*/
858 // ---------------------------------------------------------------------
860 static bool BuildCache(pkgCacheGenerator
&Gen
,
861 OpProgress
&Progress
,
862 unsigned long &CurrentSize
,unsigned long TotalSize
,
863 FileIterator Start
, FileIterator End
)
866 for (I
= Start
; I
!= End
; I
++)
868 if ((*I
)->HasPackages() == false)
871 if ((*I
)->Exists() == false)
874 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
876 _error
->Warning("Duplicate sources.list entry %s",
877 (*I
)->Describe().c_str());
881 unsigned long Size
= (*I
)->Size();
882 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
885 if ((*I
)->Merge(Gen
,Progress
) == false)
889 if (Gen
.HasFileDeps() == true)
892 TotalSize
= ComputeSize(Start
, End
);
894 for (I
= Start
; I
!= End
; I
++)
896 unsigned long Size
= (*I
)->Size();
897 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
899 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
907 // MakeStatusCache - Construct the status cache /*{{{*/
908 // ---------------------------------------------------------------------
909 /* This makes sure that the status cache (the cache that has all
910 index files from the sources list and all local ones) is ready
911 to be mmaped. If OutMap is not zero then a MMap object representing
912 the cache will be stored there. This is pretty much mandetory if you
913 are using AllowMem. AllowMem lets the function be run as non-root
914 where it builds the cache 'fast' into a memory buffer. */
915 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
916 MMap
**OutMap
,bool AllowMem
)
918 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
919 unsigned long const MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
921 vector
<pkgIndexFile
*> Files
;
922 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
926 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
927 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
930 Files
.push_back (*j
);
933 unsigned long const EndOfSource
= Files
.size();
934 if (_system
->AddStatusFiles(Files
) == false)
937 // Decide if we can write to the files..
938 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
939 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
941 // Decide if we can write to the cache
942 bool Writeable
= false;
943 if (CacheFile
.empty() == false)
944 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
946 if (SrcCacheFile
.empty() == false)
947 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
949 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
951 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
952 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
954 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
957 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
959 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
961 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
964 else if (Debug
== true)
965 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
967 /* At this point we know we need to reconstruct the package cache,
970 SPtr
<DynamicMMap
> Map
;
971 if (Writeable
== true && CacheFile
.empty() == false)
973 unlink(CacheFile
.c_str());
974 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
975 fchmod(CacheF
->Fd(),0644);
976 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
977 if (_error
->PendingError() == true)
980 std::clog
<< "Open filebased MMap" << std::endl
;
984 // Just build it in memory..
985 Map
= new DynamicMMap(0,MapSize
);
987 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
990 // Lets try the source cache.
991 unsigned long CurrentSize
= 0;
992 unsigned long TotalSize
= 0;
993 if (CheckValidity(SrcCacheFile
,Files
.begin(),
994 Files
.begin()+EndOfSource
) == true)
997 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
998 // Preload the map with the source cache
999 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
1000 unsigned long const alloc
= Map
->RawAllocate(SCacheF
.Size());
1001 if ((alloc
== 0 && _error
->PendingError())
1002 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1003 SCacheF
.Size()) == false)
1006 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1008 // Build the status cache
1009 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1010 if (_error
->PendingError() == true)
1012 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1013 Files
.begin()+EndOfSource
,Files
.end()) == false)
1019 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1020 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
1022 // Build the source cache
1023 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1024 if (_error
->PendingError() == true)
1026 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1027 Files
.begin(),Files
.begin()+EndOfSource
) == false)
1031 if (Writeable
== true && SrcCacheFile
.empty() == false)
1033 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
1034 if (_error
->PendingError() == true)
1037 fchmod(SCacheF
.Fd(),0644);
1039 // Write out the main data
1040 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1041 return _error
->Error(_("IO Error saving source cache"));
1044 // Write out the proper header
1045 Gen
.GetCache().HeaderP
->Dirty
= false;
1046 if (SCacheF
.Seek(0) == false ||
1047 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1048 return _error
->Error(_("IO Error saving source cache"));
1049 Gen
.GetCache().HeaderP
->Dirty
= true;
1053 // Build the status cache
1054 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1055 Files
.begin()+EndOfSource
,Files
.end()) == false)
1059 std::clog
<< "Caches are ready for shipping" << std::endl
;
1061 if (_error
->PendingError() == true)
1067 delete Map
.UnGuard();
1068 *OutMap
= new MMap(*CacheF
,0);
1072 *OutMap
= Map
.UnGuard();
1079 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
1080 // ---------------------------------------------------------------------
1082 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1084 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
1085 vector
<pkgIndexFile
*> Files
;
1086 unsigned long EndOfSource
= Files
.size();
1087 if (_system
->AddStatusFiles(Files
) == false)
1090 SPtr
<DynamicMMap
> Map
= new DynamicMMap(0,MapSize
);
1091 unsigned long CurrentSize
= 0;
1092 unsigned long TotalSize
= 0;
1094 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1096 // Build the status cache
1097 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
1098 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1099 if (_error
->PendingError() == true)
1101 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1102 Files
.begin()+EndOfSource
,Files
.end()) == false)
1105 if (_error
->PendingError() == true)
1107 *OutMap
= Map
.UnGuard();