]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/pkgcachegen.cc
7e67733855443d9f5fe36e05e958efe019dfc114
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;
111 while (List
.Step() == true)
113 // Get a pointer to the package structure
114 srkString PackageName
;
116 PackageName
= debian
->Find("Package");
118 PackageName
= List
.Package();
119 if (PackageName
.empty() == true)
122 pkgCache::PkgIterator Pkg
;
123 if (NewPackage(Pkg
,PackageName
) == false)
124 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),std::string(PackageName
).c_str());
126 if (Counter
% 100 == 0 && Progress
!= 0)
127 Progress
->Progress(List
.Offset());
129 string
language(List
.DescriptionLanguage());
131 /* Get a pointer to the version structure. We know the list is sorted
132 so we use that fact in the search. Insertion of new versions is
133 done with correct sorting */
136 Version
= debian
->Find("Version");
138 Version
= List
.Version();
139 if (Version
.empty() == true)
141 // we first process the package, then the descriptions
142 // (this has the bonus that we get MMap error when we run out
144 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
145 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
146 std::string(PackageName
).c_str());
148 // Find the right version to write the description
149 MD5SumValue CurMd5
= List
.Description_md5();
150 pkgCache::VerIterator Ver
= Pkg
.VersionList();
151 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
153 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
155 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
156 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
157 bool duplicate
=false;
159 // don't add a new description if we have one for the given
161 for ( ; Desc
.end() == false; Desc
++)
162 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
163 Desc
.LanguageCode() == language
)
168 for (Desc
= Ver
.DescriptionList();
170 LastDesc
= &Desc
->NextDesc
, Desc
++)
172 if (MD5SumValue(Desc
.md5()) == CurMd5
)
174 // Add new description
175 *LastDesc
= NewDescription(Desc
, language
, CurMd5
, *LastDesc
);
176 Desc
->ParentPkg
= Pkg
.Index();
178 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
179 return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),std::string(PackageName
).c_str());
188 pkgCache::VerIterator Ver
= Pkg
.VersionList();
189 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
191 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
193 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
198 /* We already have a version for this item, record that we
200 unsigned long Hash
= List
.VersionHash();
201 if (Res
== 0 && Ver
->Hash
== Hash
)
203 if (List
.UsePackage(Pkg
,Ver
) == false)
204 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
205 std::string(PackageName
).c_str());
207 if (NewFileVer(Ver
,List
) == false)
208 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
209 std::string(PackageName
).c_str());
211 // Read only a single record and return
215 FoundFileDeps
|= List
.HasFileDeps();
222 // Skip to the end of the same version set.
225 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
227 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
234 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
235 Ver
->ParentPkg
= Pkg
.Index();
238 if ((*LastVer
== 0 && _error
->PendingError()) || List
.NewVersion(Ver
) == false)
239 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
240 std::string(PackageName
).c_str());
242 if (List
.UsePackage(Pkg
,Ver
) == false)
243 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
244 std::string(PackageName
).c_str());
246 if (NewFileVer(Ver
,List
) == false)
247 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
248 std::string(PackageName
).c_str());
250 // Read only a single record and return
254 FoundFileDeps
|= List
.HasFileDeps();
258 /* Record the Description data. Description data always exist in
259 Packages and Translation-* files. */
260 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
261 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
263 // Skip to the end of description set
264 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
266 // Add new description
267 *LastDesc
= NewDescription(Desc
, language
, List
.Description_md5(), *LastDesc
);
268 Desc
->ParentPkg
= Pkg
.Index();
270 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
271 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),std::string(PackageName
).c_str());
274 FoundFileDeps
|= List
.HasFileDeps();
276 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
277 return _error
->Error(_("Wow, you exceeded the number of package "
278 "names this APT is capable of."));
279 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
280 return _error
->Error(_("Wow, you exceeded the number of versions "
281 "this APT is capable of."));
282 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
283 return _error
->Error(_("Wow, you exceeded the number of descriptions "
284 "this APT is capable of."));
285 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
286 return _error
->Error(_("Wow, you exceeded the number of dependencies "
287 "this APT is capable of."));
291 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
292 // ---------------------------------------------------------------------
293 /* If we found any file depends while parsing the main list we need to
294 resolve them. Since it is undesired to load the entire list of files
295 into the cache as virtual packages we do a two stage effort. MergeList
296 identifies the file depends and this creates Provdies for them by
297 re-parsing all the indexs. */
298 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
302 unsigned int Counter
= 0;
303 while (List
.Step() == true)
305 string PackageName
= List
.Package();
306 if (PackageName
.empty() == true)
308 string Version
= List
.Version();
309 if (Version
.empty() == true)
312 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
313 if (Pkg
.end() == true)
314 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
315 PackageName
.c_str());
317 if (Counter
% 100 == 0 && Progress
!= 0)
318 Progress
->Progress(List
.Offset());
320 unsigned long Hash
= List
.VersionHash();
321 pkgCache::VerIterator Ver
= Pkg
.VersionList();
322 for (; Ver
.end() == false; Ver
++)
324 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
326 if (List
.CollectFileProvides(Cache
,Ver
) == false)
327 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
332 if (Ver
.end() == true)
333 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
339 // CacheGenerator::NewPackage - Add a new package /*{{{*/
340 // ---------------------------------------------------------------------
341 /* This creates a new package structure and adds it to the hash table */
342 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
344 return NewPackage(Pkg
, srkString(Name
));
347 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const srkString
&Name
)
349 Pkg
= Cache
.FindPkg(Name
);
350 if (Pkg
.end() == false)
354 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
358 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
360 // Insert it into the hash table
361 unsigned long Hash
= Cache
.Hash(Name
);
362 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
363 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
365 // Set the name and the ID
366 Pkg
->Name
= Map
.WriteString(Name
.Start
,Name
.Size
);
369 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
374 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
375 // ---------------------------------------------------------------------
377 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
380 if (CurrentFile
== 0)
384 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
388 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
389 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
391 // Link it to the end of the list
392 map_ptrloc
*Last
= &Ver
->FileList
;
393 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
395 VF
->NextFile
= *Last
;
398 VF
->Offset
= List
.Offset();
399 VF
->Size
= List
.Size();
400 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
401 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
402 Cache
.HeaderP
->VerFileCount
++;
407 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
408 // ---------------------------------------------------------------------
409 /* This puts a version structure in the linked list */
410 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
411 const string
&VerStr
,
414 return NewVersion(Ver
, srkString(VerStr
), Next
);
417 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
418 const srkString
&VerStr
,
422 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
427 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
429 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
430 Ver
->VerStr
= Map
.WriteString(VerStr
.Start
, VerStr
.Size
);
431 if (Ver
->VerStr
== 0)
437 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
438 // ---------------------------------------------------------------------
440 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
443 if (CurrentFile
== 0)
447 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
451 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
452 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
454 // Link it to the end of the list
455 map_ptrloc
*Last
= &Desc
->FileList
;
456 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
459 DF
->NextFile
= *Last
;
462 DF
->Offset
= List
.Offset();
463 DF
->Size
= List
.Size();
464 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
465 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
466 Cache
.HeaderP
->DescFileCount
++;
471 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
472 // ---------------------------------------------------------------------
473 /* This puts a description structure in the linked list */
474 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
476 const MD5SumValue
&md5sum
,
480 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
481 if (Description
== 0)
485 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
486 Desc
->NextDesc
= Next
;
487 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
488 Desc
->language_code
= Map
.WriteString(Lang
);
489 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
490 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
496 // ListParser::NewDepends - Create a dependency element /*{{{*/
497 // ---------------------------------------------------------------------
498 /* This creates a dependency element in the tree. It is linked to the
499 version and to the package that it is pointing to. */
500 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
501 const string
&PackageName
,
502 const string
&Version
,
506 return NewDepends(Ver
, srkString(PackageName
), srkString(Version
), Op
, Type
);
509 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
510 const srkString
&PackageName
,
511 const srkString
&Version
,
515 pkgCache
&Cache
= Owner
->Cache
;
518 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
523 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
524 Dep
->ParentVer
= Ver
.Index();
527 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
529 // Locate the target package
530 pkgCache::PkgIterator Pkg
;
531 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
534 // Probe the reverse dependency list for a version string that matches
535 if (Version
.empty() == false)
537 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
538 if (I->Version != 0 && I.TargetVer() == Version)
539 Dep->Version = I->Version;*/
540 if (Dep
->Version
== 0)
541 if ((Dep
->Version
= WriteString(Version
)) == 0)
545 // Link it to the package
546 Dep
->Package
= Pkg
.Index();
547 Dep
->NextRevDepends
= Pkg
->RevDepends
;
548 Pkg
->RevDepends
= Dep
.Index();
550 /* Link it to the version (at the end of the list)
551 Caching the old end point speeds up generation substantially */
552 if (OldDepVer
!= Ver
)
554 OldDepLast
= &Ver
->DependsList
;
555 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
556 OldDepLast
= &D
->NextDepends
;
560 // Is it a file dependency?
561 if (PackageName
[0] == '/')
562 FoundFileDeps
= true;
564 Dep
->NextDepends
= *OldDepLast
;
565 *OldDepLast
= Dep
.Index();
566 OldDepLast
= &Dep
->NextDepends
;
571 // ListParser::NewProvides - Create a Provides element /*{{{*/
572 // ---------------------------------------------------------------------
574 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
575 const string
&PackageName
,
576 const string
&Version
)
578 return NewProvides(Ver
, srkString(PackageName
), srkString(Version
));
581 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
582 const srkString
&PackageName
,
583 const srkString
&Version
)
585 pkgCache
&Cache
= Owner
->Cache
;
587 // We do not add self referencing provides
588 if (Ver
.ParentPkg().Name() == PackageName
)
592 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
595 Cache
.HeaderP
->ProvidesCount
++;
598 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
599 Prv
->Version
= Ver
.Index();
600 Prv
->NextPkgProv
= Ver
->ProvidesList
;
601 Ver
->ProvidesList
= Prv
.Index();
602 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
605 // Locate the target package
606 pkgCache::PkgIterator Pkg
;
607 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
610 // Link it to the package
611 Prv
->ParentPkg
= Pkg
.Index();
612 Prv
->NextProvides
= Pkg
->ProvidesList
;
613 Pkg
->ProvidesList
= Prv
.Index();
618 // ListParser::NewTag - Create a Tag element /*{{{*/
619 // ---------------------------------------------------------------------
621 bool pkgCacheGenerator::ListParser::NewTag(pkgCache::PkgIterator Pkg
,
622 const char *NameStart
,
623 unsigned int NameSize
)
625 pkgCache
&Cache
= Owner
->Cache
;
628 unsigned long Tagg
= Owner
->Map
.Allocate(sizeof(pkgCache::Tag
));
631 Cache
.HeaderP
->TagCount
++;
634 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ Tagg
);
635 Tg
->Name
= WriteString(NameStart
,NameSize
);
638 Tg
->NextTag
= Pkg
->TagList
;
639 Pkg
->TagList
= Tg
.Index();
644 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
645 // ---------------------------------------------------------------------
646 /* This is used to select which file is to be associated with all newly
647 added versions. The caller is responsible for setting the IMS fields. */
648 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
649 const pkgIndexFile
&Index
,
652 // Get some space for the structure
653 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
654 if (CurrentFile
== Cache
.PkgFileP
)
658 CurrentFile
->FileName
= Map
.WriteString(File
);
659 CurrentFile
->Site
= WriteUniqString(Site
);
660 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
661 CurrentFile
->Flags
= Flags
;
662 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
663 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
665 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
666 Cache
.HeaderP
->PackageFileCount
++;
668 if (CurrentFile
->FileName
== 0)
672 Progress
->SubProgress(Index
.Size());
676 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
677 // ---------------------------------------------------------------------
678 /* This is used to create handles to strings. Given the same text it
679 always returns the same number */
680 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
683 return WriteString(srkString(S
, Size
), srkSeriouslyUnique
);
686 unsigned long pkgCacheGenerator::WriteString(const srkString
&S
,
689 if (level
== srkRunOfTheMillNormal
)
690 return Map
.WriteString(S
.Start
,S
.Size
);
692 /* We use a very small transient hash table here, this speeds up generation
693 by a fair amount on slower machines */
694 pkgCache::StringItem
*&Bucket(level
== srkReasonablySpecial
? SpecHash
[(S
[0]*5 + S
[1]) % _count(SpecHash
)] : UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)]);
696 stringcmp(S
,Cache
.StrP
+ Bucket
->String
) == 0)
697 return Bucket
->String
;
699 pkgCache::StringItem
*I
;
702 if (level
!= srkSeriouslyUnique
) {
707 // Search for an insertion point
708 I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
710 Last
= &Cache
.HeaderP
->StringList
;
711 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
712 I
= Cache
.StringItemP
+ I
->NextItem
)
714 Res
= stringcmp(S
,Cache
.StrP
+ I
->String
);
729 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
733 // Fill in the structure
734 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
735 ItemP
->NextItem
= I
- Cache
.StringItemP
;
738 ItemP
->String
= Map
.WriteString(S
.Start
,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();