]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/pkgcachegen.cc
f20c3e579c0bc602cbb7eb5e00d293e4c4af0cb8
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
->ID
)*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 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
450 Ver
->VerStr
= Map
.WriteString(VerStr
.Start
, VerStr
.Size
);
451 if (Ver
->VerStr
== 0)
457 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
458 // ---------------------------------------------------------------------
460 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
463 if (CurrentFile
== 0)
467 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
471 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
472 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
474 // Link it to the end of the list
475 map_ptrloc
*Last
= &Desc
->FileList
;
476 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
479 DF
->NextFile
= *Last
;
482 DF
->Offset
= List
.Offset();
483 DF
->Size
= List
.Size();
484 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
485 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
486 Cache
.HeaderP
->DescFileCount
++;
491 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
492 // ---------------------------------------------------------------------
493 /* This puts a description structure in the linked list */
494 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
496 const MD5SumValue
&md5sum
,
500 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
501 if (Description
== 0)
505 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
506 Desc
->NextDesc
= Next
;
507 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
508 Desc
->language_code
= Map
.WriteString(Lang
);
509 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
510 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
516 // ListParser::NewDepends - Create a dependency element /*{{{*/
517 // ---------------------------------------------------------------------
518 /* This creates a dependency element in the tree. It is linked to the
519 version and to the package that it is pointing to. */
520 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
521 const string
&PackageName
,
522 const string
&Version
,
526 return NewDepends(Ver
, srkString(PackageName
), srkString(Version
), Op
, Type
);
529 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
530 const srkString
&PackageName
,
531 const srkString
&Version
,
535 pkgCache
&Cache
= Owner
->Cache
;
538 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
543 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
544 Dep
->ParentVer
= Ver
.Index();
547 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
549 // Locate the target package
550 pkgCache::PkgIterator Pkg
;
551 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
554 // Probe the reverse dependency list for a version string that matches
555 if (Version
.empty() == false)
557 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
558 if (I->Version != 0 && I.TargetVer() == Version)
559 Dep->Version = I->Version;*/
560 if (Dep
->Version
== 0)
561 if ((Dep
->Version
= WriteString(Version
)) == 0)
565 // Link it to the package
566 Dep
->Package
= Pkg
.Index();
567 Dep
->NextRevDepends
= Pkg
->RevDepends
;
568 Pkg
->RevDepends
= Dep
.Index();
570 /* Link it to the version (at the end of the list)
571 Caching the old end point speeds up generation substantially */
572 if (OldDepVer
!= Ver
)
574 OldDepLast
= &Ver
->DependsList
;
575 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
576 OldDepLast
= &D
->NextDepends
;
580 // Is it a file dependency?
581 if (PackageName
[0] == '/')
582 FoundFileDeps
= true;
584 Dep
->NextDepends
= *OldDepLast
;
585 *OldDepLast
= Dep
.Index();
586 OldDepLast
= &Dep
->NextDepends
;
591 // ListParser::NewProvides - Create a Provides element /*{{{*/
592 // ---------------------------------------------------------------------
594 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
595 const string
&PackageName
,
596 const string
&Version
)
598 return NewProvides(Ver
, srkString(PackageName
), srkString(Version
));
601 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
602 const srkString
&PackageName
,
603 const srkString
&Version
)
605 pkgCache
&Cache
= Owner
->Cache
;
607 // We do not add self referencing provides
608 if (Ver
.ParentPkg().Name() == PackageName
)
612 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
615 Cache
.HeaderP
->ProvidesCount
++;
618 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
619 Prv
->Version
= Ver
.Index();
620 Prv
->NextPkgProv
= Ver
->ProvidesList
;
621 Ver
->ProvidesList
= Prv
.Index();
622 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
625 // Locate the target package
626 pkgCache::PkgIterator Pkg
;
627 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
630 // Link it to the package
631 Prv
->ParentPkg
= Pkg
.Index();
632 Prv
->NextProvides
= Pkg
->ProvidesList
;
633 Pkg
->ProvidesList
= Prv
.Index();
638 // ListParser::NewTag - Create a Tag element /*{{{*/
639 // ---------------------------------------------------------------------
641 bool pkgCacheGenerator::ListParser::NewTag(pkgCache::PkgIterator Pkg
,
642 const char *NameStart
,
643 unsigned int NameSize
)
645 pkgCache
&Cache
= Owner
->Cache
;
648 unsigned long Tagg
= Owner
->Map
.Allocate(sizeof(pkgCache::Tag
));
651 Cache
.HeaderP
->TagCount
++;
654 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ Tagg
);
655 Tg
->Name
= WriteString(NameStart
,NameSize
);
658 Tg
->NextTag
= Pkg
->TagList
;
659 Pkg
->TagList
= Tg
.Index();
664 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
665 // ---------------------------------------------------------------------
666 /* This is used to select which file is to be associated with all newly
667 added versions. The caller is responsible for setting the IMS fields. */
668 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
669 const pkgIndexFile
&Index
,
672 // Get some space for the structure
673 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
674 if (CurrentFile
== Cache
.PkgFileP
)
678 CurrentFile
->FileName
= Map
.WriteString(File
);
679 CurrentFile
->Site
= WriteUniqString(Site
);
680 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
681 CurrentFile
->Flags
= Flags
;
682 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
683 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
685 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
686 Cache
.HeaderP
->PackageFileCount
++;
688 if (CurrentFile
->FileName
== 0)
692 Progress
->SubProgress(Index
.Size());
696 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
697 // ---------------------------------------------------------------------
698 /* This is used to create handles to strings. Given the same text it
699 always returns the same number */
700 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
703 /* We use a very small transient hash table here, this speeds up generation
704 by a fair amount on slower machines */
705 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
707 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
708 return Bucket
->String
;
710 // Search for an insertion point
711 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
713 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
714 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
715 I
= Cache
.StringItemP
+ I
->NextItem
)
717 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
730 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
734 // Fill in the structure
735 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
736 ItemP
->NextItem
= I
- Cache
.StringItemP
;
738 ItemP
->String
= Map
.WriteString(S
,Size
);
739 if (ItemP
->String
== 0)
743 return ItemP
->String
;
746 // CheckValidity - Check that a cache is up-to-date /*{{{*/
747 // ---------------------------------------------------------------------
748 /* This just verifies that each file in the list of index files exists,
749 has matching attributes with the cache and the cache does not have
751 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
752 FileIterator End
,MMap
**OutMap
= 0)
754 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
755 // No file, certainly invalid
756 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
759 std::clog
<< "CacheFile doesn't exist" << std::endl
;
764 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
765 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
767 if (_error
->PendingError() == true || Map
->Size() == 0)
770 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
775 /* Now we check every index file, see if it is in the cache,
776 verify the IMS data and check that it is on the disk too.. */
777 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
778 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
779 for (; Start
!= End
; Start
++)
782 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
783 if ((*Start
)->HasPackages() == false)
786 std::clog
<< "Has NO packages" << std::endl
;
790 if ((*Start
)->Exists() == false)
792 #if 0 // mvo: we no longer give a message here (Default Sources spec)
793 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
794 (*Start
)->Describe().c_str());
797 std::clog
<< "file doesn't exist" << std::endl
;
801 // FindInCache is also expected to do an IMS check.
802 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
803 if (File
.end() == true)
806 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
810 Visited
[File
->ID
] = true;
812 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
815 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
816 if (Visited
[I
] == false)
819 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
823 if (_error
->PendingError() == true)
827 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
828 _error
->DumpErrors();
835 *OutMap
= Map
.UnGuard();
839 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
840 // ---------------------------------------------------------------------
841 /* Size is kind of an abstract notion that is only used for the progress
843 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
845 unsigned long TotalSize
= 0;
846 for (; Start
!= End
; Start
++)
848 if ((*Start
)->HasPackages() == false)
850 TotalSize
+= (*Start
)->Size();
855 // BuildCache - Merge the list of index files into the cache /*{{{*/
856 // ---------------------------------------------------------------------
858 static bool BuildCache(pkgCacheGenerator
&Gen
,
859 OpProgress
&Progress
,
860 unsigned long &CurrentSize
,unsigned long TotalSize
,
861 FileIterator Start
, FileIterator End
)
864 for (I
= Start
; I
!= End
; I
++)
866 if ((*I
)->HasPackages() == false)
869 if ((*I
)->Exists() == false)
872 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
874 _error
->Warning("Duplicate sources.list entry %s",
875 (*I
)->Describe().c_str());
879 unsigned long Size
= (*I
)->Size();
880 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
883 if ((*I
)->Merge(Gen
,Progress
) == false)
887 if (Gen
.HasFileDeps() == true)
890 TotalSize
= ComputeSize(Start
, End
);
892 for (I
= Start
; I
!= End
; I
++)
894 unsigned long Size
= (*I
)->Size();
895 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
897 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
905 // MakeStatusCache - Construct the status cache /*{{{*/
906 // ---------------------------------------------------------------------
907 /* This makes sure that the status cache (the cache that has all
908 index files from the sources list and all local ones) is ready
909 to be mmaped. If OutMap is not zero then a MMap object representing
910 the cache will be stored there. This is pretty much mandetory if you
911 are using AllowMem. AllowMem lets the function be run as non-root
912 where it builds the cache 'fast' into a memory buffer. */
913 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
914 MMap
**OutMap
,bool AllowMem
)
916 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
917 unsigned long const MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
919 vector
<pkgIndexFile
*> Files
;
920 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
924 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
925 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
928 Files
.push_back (*j
);
931 unsigned long const EndOfSource
= Files
.size();
932 if (_system
->AddStatusFiles(Files
) == false)
935 // Decide if we can write to the files..
936 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
937 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
939 // Decide if we can write to the cache
940 bool Writeable
= false;
941 if (CacheFile
.empty() == false)
942 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
944 if (SrcCacheFile
.empty() == false)
945 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
947 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
949 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
950 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
952 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
955 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
957 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
959 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
962 else if (Debug
== true)
963 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
965 /* At this point we know we need to reconstruct the package cache,
968 SPtr
<DynamicMMap
> Map
;
969 if (Writeable
== true && CacheFile
.empty() == false)
971 unlink(CacheFile
.c_str());
972 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
973 fchmod(CacheF
->Fd(),0644);
974 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
975 if (_error
->PendingError() == true)
978 std::clog
<< "Open filebased MMap" << std::endl
;
982 // Just build it in memory..
983 Map
= new DynamicMMap(0,MapSize
);
985 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
988 // Lets try the source cache.
989 unsigned long CurrentSize
= 0;
990 unsigned long TotalSize
= 0;
991 if (CheckValidity(SrcCacheFile
,Files
.begin(),
992 Files
.begin()+EndOfSource
) == true)
995 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
996 // Preload the map with the source cache
997 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
998 unsigned long const alloc
= Map
->RawAllocate(SCacheF
.Size());
999 if ((alloc
== 0 && _error
->PendingError())
1000 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
1001 SCacheF
.Size()) == false)
1004 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1006 // Build the status cache
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)
1017 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
1018 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
1020 // Build the source cache
1021 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1022 if (_error
->PendingError() == true)
1024 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1025 Files
.begin(),Files
.begin()+EndOfSource
) == false)
1029 if (Writeable
== true && SrcCacheFile
.empty() == false)
1031 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
1032 if (_error
->PendingError() == true)
1035 fchmod(SCacheF
.Fd(),0644);
1037 // Write out the main data
1038 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1039 return _error
->Error(_("IO Error saving source cache"));
1042 // Write out the proper header
1043 Gen
.GetCache().HeaderP
->Dirty
= false;
1044 if (SCacheF
.Seek(0) == false ||
1045 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1046 return _error
->Error(_("IO Error saving source cache"));
1047 Gen
.GetCache().HeaderP
->Dirty
= true;
1051 // Build the status cache
1052 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1053 Files
.begin()+EndOfSource
,Files
.end()) == false)
1057 std::clog
<< "Caches are ready for shipping" << std::endl
;
1059 if (_error
->PendingError() == true)
1065 delete Map
.UnGuard();
1066 *OutMap
= new MMap(*CacheF
,0);
1070 *OutMap
= Map
.UnGuard();
1077 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
1078 // ---------------------------------------------------------------------
1080 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1082 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
1083 vector
<pkgIndexFile
*> Files
;
1084 unsigned long EndOfSource
= Files
.size();
1085 if (_system
->AddStatusFiles(Files
) == false)
1088 SPtr
<DynamicMMap
> Map
= new DynamicMMap(0,MapSize
);
1089 unsigned long CurrentSize
= 0;
1090 unsigned long TotalSize
= 0;
1092 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1094 // Build the status cache
1095 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
1096 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1097 if (_error
->PendingError() == true)
1099 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1100 Files
.begin()+EndOfSource
,Files
.end()) == false)
1103 if (_error
->PendingError() == true)
1105 *OutMap
= Map
.UnGuard();