]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
2a4a30349a49535a5c57d0d2c730933e2e9146ae
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/aptconfiguration.h>
22 #include <apt-pkg/strutl.h>
23 #include <apt-pkg/sptr.h>
24 #include <apt-pkg/pkgsystem.h>
26 #include <apt-pkg/tagfile.h>
38 typedef vector
<pkgIndexFile
*>::iterator FileIterator
;
40 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
41 // ---------------------------------------------------------------------
42 /* We set the dirty flag and make sure that is written to the disk */
43 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
44 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
48 memset(UniqHash
,0,sizeof(UniqHash
));
50 if (_error
->PendingError() == true)
55 // Setup the map interface..
56 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
57 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
60 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
63 *Cache
.HeaderP
= pkgCache::Header();
64 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
65 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
70 // Map directly from the existing file
72 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
73 if (Cache
.VS
!= _system
->VS
)
75 _error
->Error(_("Cache has an incompatible versioning system"));
80 Cache
.HeaderP
->Dirty
= true;
81 Map
.Sync(0,sizeof(pkgCache::Header
));
84 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
85 // ---------------------------------------------------------------------
86 /* We sync the data then unset the dirty flag in two steps so as to
87 advoid a problem during a crash */
88 pkgCacheGenerator::~pkgCacheGenerator()
90 if (_error
->PendingError() == true)
92 if (Map
.Sync() == false)
95 Cache
.HeaderP
->Dirty
= false;
96 Map
.Sync(0,sizeof(pkgCache::Header
));
99 // CacheGenerator::MergeList - Merge the package list /*{{{*/
100 // ---------------------------------------------------------------------
101 /* This provides the generation of the entries in the cache. Each loop
102 goes through a single package record from the underlying parse engine. */
103 bool pkgCacheGenerator::MergeList(ListParser
&List
,
104 pkgCache::VerIterator
*OutVer
)
108 unsigned int Counter
= 0;
109 while (List
.Step() == true)
111 // Get a pointer to the package structure
112 string
const PackageName
= List
.Package();
113 if (PackageName
.empty() == true)
116 pkgCache::PkgIterator Pkg
;
117 if (NewPackage(Pkg
, PackageName
, List
.Architecture()) == false)
118 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str());
120 if (Counter
% 100 == 0 && Progress
!= 0)
121 Progress
->Progress(List
.Offset());
123 /* Get a pointer to the version structure. We know the list is sorted
124 so we use that fact in the search. Insertion of new versions is
125 done with correct sorting */
126 string Version
= List
.Version();
127 if (Version
.empty() == true)
129 // we first process the package, then the descriptions
130 // (this has the bonus that we get MMap error when we run out
132 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
133 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
134 PackageName
.c_str());
136 // Find the right version to write the description
137 MD5SumValue CurMd5
= List
.Description_md5();
138 pkgCache::VerIterator Ver
= Pkg
.VersionList();
139 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
141 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
143 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
144 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
145 bool duplicate
=false;
147 // don't add a new description if we have one for the given
149 for ( ; Desc
.end() == false; Desc
++)
150 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
151 Desc
.LanguageCode() == List
.DescriptionLanguage())
156 for (Desc
= Ver
.DescriptionList();
158 LastDesc
= &Desc
->NextDesc
, Desc
++)
160 if (MD5SumValue(Desc
.md5()) == CurMd5
)
162 // Add new description
163 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
164 Desc
->ParentPkg
= Pkg
.Index();
166 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
167 return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName
.c_str());
176 pkgCache::VerIterator Ver
= Pkg
.VersionList();
177 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
179 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
181 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
186 /* We already have a version for this item, record that we
188 unsigned long Hash
= List
.VersionHash();
189 if (Res
== 0 && Ver
->Hash
== Hash
)
191 if (List
.UsePackage(Pkg
,Ver
) == false)
192 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
193 PackageName
.c_str());
195 if (NewFileVer(Ver
,List
) == false)
196 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
197 PackageName
.c_str());
199 // Read only a single record and return
203 FoundFileDeps
|= List
.HasFileDeps();
210 // Skip to the end of the same version set.
213 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
215 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
222 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
223 Ver
->ParentPkg
= Pkg
.Index();
226 if ((*LastVer
== 0 && _error
->PendingError()) || List
.NewVersion(Ver
) == false)
227 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
228 PackageName
.c_str());
230 if (List
.UsePackage(Pkg
,Ver
) == false)
231 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
232 PackageName
.c_str());
234 if (NewFileVer(Ver
,List
) == false)
235 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
236 PackageName
.c_str());
238 // Read only a single record and return
242 FoundFileDeps
|= List
.HasFileDeps();
246 /* Record the Description data. Description data always exist in
247 Packages and Translation-* files. */
248 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
249 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
251 // Skip to the end of description set
252 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
254 // Add new description
255 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
256 Desc
->ParentPkg
= Pkg
.Index();
258 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
259 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str());
262 FoundFileDeps
|= List
.HasFileDeps();
264 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
265 return _error
->Error(_("Wow, you exceeded the number of package "
266 "names this APT is capable of."));
267 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
268 return _error
->Error(_("Wow, you exceeded the number of versions "
269 "this APT is capable of."));
270 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
271 return _error
->Error(_("Wow, you exceeded the number of descriptions "
272 "this APT is capable of."));
273 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
274 return _error
->Error(_("Wow, you exceeded the number of dependencies "
275 "this APT is capable of."));
279 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
280 // ---------------------------------------------------------------------
281 /* If we found any file depends while parsing the main list we need to
282 resolve them. Since it is undesired to load the entire list of files
283 into the cache as virtual packages we do a two stage effort. MergeList
284 identifies the file depends and this creates Provdies for them by
285 re-parsing all the indexs. */
286 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
290 unsigned int Counter
= 0;
291 while (List
.Step() == true)
293 string PackageName
= List
.Package();
294 if (PackageName
.empty() == true)
296 string Version
= List
.Version();
297 if (Version
.empty() == true)
300 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
301 if (Pkg
.end() == true)
302 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
303 PackageName
.c_str());
305 if (Counter
% 100 == 0 && Progress
!= 0)
306 Progress
->Progress(List
.Offset());
308 unsigned long Hash
= List
.VersionHash();
309 pkgCache::VerIterator Ver
= Pkg
.VersionList();
310 for (; Ver
.end() == false; Ver
++)
312 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
314 if (List
.CollectFileProvides(Cache
,Ver
) == false)
315 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
320 if (Ver
.end() == true)
321 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
327 // CacheGenerator::NewGroup - Add a new group /*{{{*/
328 // ---------------------------------------------------------------------
329 /* This creates a new group structure and adds it to the hash table */
330 bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator
&Grp
, const string
&Name
) {
331 Grp
= Cache
.FindGrp(Name
);
332 if (Grp
.end() == false)
336 unsigned long const Group
= Map
.Allocate(sizeof(pkgCache::Group
));
337 if (unlikely(Group
== 0))
340 Grp
= pkgCache::GrpIterator(Cache
, Cache
.GrpP
+ Group
);
341 Grp
->Name
= Map
.WriteString(Name
);
342 if (unlikely(Grp
->Name
== 0))
345 // Insert it into the hash table
346 unsigned long const Hash
= Cache
.Hash(Name
);
347 Grp
->Next
= Cache
.HeaderP
->GrpHashTable
[Hash
];
348 Cache
.HeaderP
->GrpHashTable
[Hash
] = Group
;
350 Cache
.HeaderP
->GroupCount
++;
355 // CacheGenerator::NewPackage - Add a new package /*{{{*/
356 // ---------------------------------------------------------------------
357 /* This creates a new package structure and adds it to the hash table */
358 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
,
359 const string
&Arch
) {
360 pkgCache::GrpIterator Grp
;
361 if (unlikely(NewGroup(Grp
, Name
) == false))
364 Pkg
= Grp
.FindPkg(Arch
);
365 if (Pkg
.end() == false)
369 unsigned long const Package
= Map
.Allocate(sizeof(pkgCache::Package
));
370 if (unlikely(Package
== 0))
372 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
374 // Insert it into the hash table
375 unsigned long const Hash
= Cache
.Hash(Name
);
376 Pkg
->NextPackage
= Cache
.HeaderP
->PkgHashTable
[Hash
];
377 Cache
.HeaderP
->PkgHashTable
[Hash
] = Package
;
379 // remember the packages in the group
380 Grp
->FirstPackage
= Package
;
381 if (Grp
->LastPackage
== 0)
382 Grp
->LastPackage
= Package
;
384 // Set the name, arch and the ID
385 Pkg
->Name
= Grp
->Name
;
386 Pkg
->Group
= Grp
.Index();
387 Pkg
->Arch
= WriteUniqString(Arch
.c_str());
388 if (unlikely(Pkg
->Arch
== 0))
390 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
395 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
396 // ---------------------------------------------------------------------
398 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
401 if (CurrentFile
== 0)
405 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
409 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
410 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
412 // Link it to the end of the list
413 map_ptrloc
*Last
= &Ver
->FileList
;
414 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
416 VF
->NextFile
= *Last
;
419 VF
->Offset
= List
.Offset();
420 VF
->Size
= List
.Size();
421 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
422 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
423 Cache
.HeaderP
->VerFileCount
++;
428 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
429 // ---------------------------------------------------------------------
430 /* This puts a version structure in the linked list */
431 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
432 const string
&VerStr
,
436 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
441 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
443 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
444 Ver
->VerStr
= Map
.WriteString(VerStr
);
445 if (Ver
->VerStr
== 0)
451 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
452 // ---------------------------------------------------------------------
454 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
457 if (CurrentFile
== 0)
461 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
465 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
466 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
468 // Link it to the end of the list
469 map_ptrloc
*Last
= &Desc
->FileList
;
470 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
473 DF
->NextFile
= *Last
;
476 DF
->Offset
= List
.Offset();
477 DF
->Size
= List
.Size();
478 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
479 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
480 Cache
.HeaderP
->DescFileCount
++;
485 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
486 // ---------------------------------------------------------------------
487 /* This puts a description structure in the linked list */
488 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
490 const MD5SumValue
&md5sum
,
494 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
495 if (Description
== 0)
499 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
500 Desc
->NextDesc
= Next
;
501 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
502 Desc
->language_code
= Map
.WriteString(Lang
);
503 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
504 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
510 // CacheGenerator::FinishCache - do various finish operations /*{{{*/
511 // ---------------------------------------------------------------------
512 /* This prepares the Cache for delivery */
513 bool pkgCacheGenerator::FinishCache(OpProgress
&Progress
) {
514 // FIXME: add progress reporting for this operation
515 // Do we have different architectures in your groups ?
516 vector
<string
> archs
= APT::Configuration::getArchitectures();
517 if (archs
.size() > 1) {
518 // Create Conflicts in between the group
519 for (pkgCache::GrpIterator G
= GetCache().GrpBegin(); G
.end() != true; G
++) {
520 string
const PkgName
= G
.Name();
521 for (pkgCache::PkgIterator P
= G
.PackageList(); P
.end() != true; P
= G
.NextPkg(P
)) {
522 for (pkgCache::VerIterator V
= P
.VersionList(); V
.end() != true; V
++) {
523 // Arch all packages are "co-installable"
524 if (V
->MultiArch
== pkgCache::Version::All
)
526 string
const Arch
= V
.Arch();
527 map_ptrloc
*OldDepLast
= NULL
;
528 for (vector
<string
>::const_iterator A
= archs
.begin(); A
!= archs
.end(); ++A
) {
531 /* We allow only one installed arch at the time
532 per group, therefore each group member conflicts
533 with all other group members */
534 pkgCache::PkgIterator D
= G
.FindPkg(*A
);
537 // Conflicts: ${self}:other
539 pkgCache::Dep::NoOp
, pkgCache::Dep::Conflicts
,
549 // CacheGenerator::NewDepends - Create a dependency element /*{{{*/
550 // ---------------------------------------------------------------------
551 /* This creates a dependency element in the tree. It is linked to the
552 version and to the package that it is pointing to. */
553 bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator
&Pkg
,
554 pkgCache::VerIterator
&Ver
,
555 string
const &Version
,
556 unsigned int const &Op
,
557 unsigned int const &Type
,
558 map_ptrloc
*OldDepLast
)
561 unsigned long const Dependency
= Map
.Allocate(sizeof(pkgCache::Dependency
));
562 if (unlikely(Dependency
== 0))
566 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
567 Dep
->ParentVer
= Ver
.Index();
570 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
572 // Probe the reverse dependency list for a version string that matches
573 if (Version
.empty() == false)
575 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
576 if (I->Version != 0 && I.TargetVer() == Version)
577 Dep->Version = I->Version;*/
578 if (Dep
->Version
== 0)
579 if (unlikely((Dep
->Version
= Map
.WriteString(Version
)) == 0))
583 // Link it to the package
584 Dep
->Package
= Pkg
.Index();
585 Dep
->NextRevDepends
= Pkg
->RevDepends
;
586 Pkg
->RevDepends
= Dep
.Index();
588 // Do we know where to link the Dependency to?
589 if (OldDepLast
== NULL
)
591 OldDepLast
= &Ver
->DependsList
;
592 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
593 OldDepLast
= &D
->NextDepends
;
596 Dep
->NextDepends
= *OldDepLast
;
597 *OldDepLast
= Dep
.Index();
598 OldDepLast
= &Dep
->NextDepends
;
603 // ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
604 // ---------------------------------------------------------------------
605 /* This creates a Group and the Package to link this dependency to if
606 needed and handles also the caching of the old endpoint */
607 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
608 const string
&PackageName
,
610 const string
&Version
,
614 pkgCache::GrpIterator Grp
;
615 if (unlikely(Owner
->NewGroup(Grp
, PackageName
) == false))
618 // Locate the target package
619 pkgCache::PkgIterator Pkg
= Grp
.FindPkg(Arch
);
620 if (Pkg
.end() == true) {
621 if (unlikely(Owner
->NewPackage(Pkg
, PackageName
, Arch
) == false))
625 // Is it a file dependency?
626 if (unlikely(PackageName
[0] == '/'))
627 FoundFileDeps
= true;
629 /* Caching the old end point speeds up generation substantially */
630 if (OldDepVer
!= Ver
) {
635 return Owner
->NewDepends(Pkg
, Ver
, Version
, Op
, Type
, OldDepLast
);
638 // ListParser::NewProvides - Create a Provides element /*{{{*/
639 // ---------------------------------------------------------------------
641 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
642 const string
&PackageName
,
643 const string
&Version
)
645 pkgCache
&Cache
= Owner
->Cache
;
647 // We do not add self referencing provides
648 if (unlikely(Ver
.ParentPkg().Name() == PackageName
))
652 unsigned long const Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
653 if (unlikely(Provides
== 0))
655 Cache
.HeaderP
->ProvidesCount
++;
658 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
659 Prv
->Version
= Ver
.Index();
660 Prv
->NextPkgProv
= Ver
->ProvidesList
;
661 Ver
->ProvidesList
= Prv
.Index();
662 if (Version
.empty() == false && unlikely((Prv
->ProvideVersion
= WriteString(Version
)) == 0))
665 // Locate the target package
666 pkgCache::PkgIterator Pkg
;
667 if (unlikely(Owner
->NewPackage(Pkg
,PackageName
,string(Ver
.Arch())) == false))
670 // Link it to the package
671 Prv
->ParentPkg
= Pkg
.Index();
672 Prv
->NextProvides
= Pkg
->ProvidesList
;
673 Pkg
->ProvidesList
= Prv
.Index();
678 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
679 // ---------------------------------------------------------------------
680 /* This is used to select which file is to be associated with all newly
681 added versions. The caller is responsible for setting the IMS fields. */
682 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
683 const pkgIndexFile
&Index
,
686 // Get some space for the structure
687 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
688 if (CurrentFile
== Cache
.PkgFileP
)
692 CurrentFile
->FileName
= Map
.WriteString(File
);
693 CurrentFile
->Site
= WriteUniqString(Site
);
694 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
695 CurrentFile
->Flags
= Flags
;
696 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
697 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
699 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
700 Cache
.HeaderP
->PackageFileCount
++;
702 if (CurrentFile
->FileName
== 0)
706 Progress
->SubProgress(Index
.Size());
710 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
711 // ---------------------------------------------------------------------
712 /* This is used to create handles to strings. Given the same text it
713 always returns the same number */
714 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
717 /* We use a very small transient hash table here, this speeds up generation
718 by a fair amount on slower machines */
719 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
721 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
722 return Bucket
->String
;
724 // Search for an insertion point
725 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
727 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
728 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
729 I
= Cache
.StringItemP
+ I
->NextItem
)
731 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
744 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
748 // Fill in the structure
749 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
750 ItemP
->NextItem
= I
- Cache
.StringItemP
;
752 ItemP
->String
= Map
.WriteString(S
,Size
);
753 if (ItemP
->String
== 0)
757 return ItemP
->String
;
760 // CheckValidity - Check that a cache is up-to-date /*{{{*/
761 // ---------------------------------------------------------------------
762 /* This just verifies that each file in the list of index files exists,
763 has matching attributes with the cache and the cache does not have
765 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
766 FileIterator End
,MMap
**OutMap
= 0)
768 // No file, certainly invalid
769 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
773 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
774 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
776 if (_error
->PendingError() == true || Map
->Size() == 0)
782 /* Now we check every index file, see if it is in the cache,
783 verify the IMS data and check that it is on the disk too.. */
784 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
785 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
786 for (; Start
!= End
; Start
++)
788 if ((*Start
)->HasPackages() == false)
791 if ((*Start
)->Exists() == false)
793 #if 0 // mvo: we no longer give a message here (Default Sources spec)
794 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
795 (*Start
)->Describe().c_str());
800 // FindInCache is also expected to do an IMS check.
801 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
802 if (File
.end() == true)
805 Visited
[File
->ID
] = true;
808 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
809 if (Visited
[I
] == false)
812 if (_error
->PendingError() == true)
819 *OutMap
= Map
.UnGuard();
823 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
824 // ---------------------------------------------------------------------
825 /* Size is kind of an abstract notion that is only used for the progress
827 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
829 unsigned long TotalSize
= 0;
830 for (; Start
!= End
; Start
++)
832 if ((*Start
)->HasPackages() == false)
834 TotalSize
+= (*Start
)->Size();
839 // BuildCache - Merge the list of index files into the cache /*{{{*/
840 // ---------------------------------------------------------------------
842 static bool BuildCache(pkgCacheGenerator
&Gen
,
843 OpProgress
&Progress
,
844 unsigned long &CurrentSize
,unsigned long TotalSize
,
845 FileIterator Start
, FileIterator End
)
848 for (I
= Start
; I
!= End
; I
++)
850 if ((*I
)->HasPackages() == false)
853 if ((*I
)->Exists() == false)
856 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
858 _error
->Warning("Duplicate sources.list entry %s",
859 (*I
)->Describe().c_str());
863 unsigned long Size
= (*I
)->Size();
864 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
867 if ((*I
)->Merge(Gen
,Progress
) == false)
871 if (Gen
.HasFileDeps() == true)
874 TotalSize
= ComputeSize(Start
, End
);
876 for (I
= Start
; I
!= End
; I
++)
878 unsigned long Size
= (*I
)->Size();
879 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
881 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
889 // MakeStatusCache - Construct the status cache /*{{{*/
890 // ---------------------------------------------------------------------
891 /* This makes sure that the status cache (the cache that has all
892 index files from the sources list and all local ones) is ready
893 to be mmaped. If OutMap is not zero then a MMap object representing
894 the cache will be stored there. This is pretty much mandetory if you
895 are using AllowMem. AllowMem lets the function be run as non-root
896 where it builds the cache 'fast' into a memory buffer. */
897 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
898 MMap
**OutMap
,bool AllowMem
)
900 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
902 vector
<pkgIndexFile
*> Files
;
903 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
907 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
908 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
911 Files
.push_back (*j
);
914 unsigned long EndOfSource
= Files
.size();
915 if (_system
->AddStatusFiles(Files
) == false)
918 // Decide if we can write to the files..
919 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
920 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
922 // Decide if we can write to the cache
923 bool Writeable
= false;
924 if (CacheFile
.empty() == false)
925 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
927 if (SrcCacheFile
.empty() == false)
928 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
930 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
931 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
933 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
936 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
938 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
942 /* At this point we know we need to reconstruct the package cache,
945 SPtr
<DynamicMMap
> Map
;
946 if (Writeable
== true && CacheFile
.empty() == false)
948 unlink(CacheFile
.c_str());
949 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
950 fchmod(CacheF
->Fd(),0644);
951 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
952 if (_error
->PendingError() == true)
957 // Just build it in memory..
958 Map
= new DynamicMMap(0,MapSize
);
961 // Lets try the source cache.
962 unsigned long CurrentSize
= 0;
963 unsigned long TotalSize
= 0;
964 if (CheckValidity(SrcCacheFile
,Files
.begin(),
965 Files
.begin()+EndOfSource
) == true)
967 // Preload the map with the source cache
968 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
969 unsigned long alloc
= Map
->RawAllocate(SCacheF
.Size());
970 if ((alloc
== 0 && _error
->PendingError())
971 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
972 SCacheF
.Size()) == false)
975 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
977 // Build the status cache
978 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
979 if (_error
->PendingError() == true)
981 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
982 Files
.begin()+EndOfSource
,Files
.end()) == false)
985 // FIXME: move me to a better place
986 Gen
.FinishCache(Progress
);
990 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
992 // Build the source cache
993 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
994 if (_error
->PendingError() == true)
996 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
997 Files
.begin(),Files
.begin()+EndOfSource
) == false)
1001 if (Writeable
== true && SrcCacheFile
.empty() == false)
1003 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
1004 if (_error
->PendingError() == true)
1007 fchmod(SCacheF
.Fd(),0644);
1009 // Write out the main data
1010 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
1011 return _error
->Error(_("IO Error saving source cache"));
1014 // Write out the proper header
1015 Gen
.GetCache().HeaderP
->Dirty
= false;
1016 if (SCacheF
.Seek(0) == false ||
1017 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
1018 return _error
->Error(_("IO Error saving source cache"));
1019 Gen
.GetCache().HeaderP
->Dirty
= true;
1023 // Build the status cache
1024 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1025 Files
.begin()+EndOfSource
,Files
.end()) == false)
1028 // FIXME: move me to a better place
1029 Gen
.FinishCache(Progress
);
1032 if (_error
->PendingError() == true)
1038 delete Map
.UnGuard();
1039 *OutMap
= new MMap(*CacheF
,0);
1043 *OutMap
= Map
.UnGuard();
1050 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
1051 // ---------------------------------------------------------------------
1053 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1055 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
1056 vector
<pkgIndexFile
*> Files
;
1057 unsigned long EndOfSource
= Files
.size();
1058 if (_system
->AddStatusFiles(Files
) == false)
1061 SPtr
<DynamicMMap
> Map
= new DynamicMMap(0,MapSize
);
1062 unsigned long CurrentSize
= 0;
1063 unsigned long TotalSize
= 0;
1065 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1067 // Build the status cache
1068 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
1069 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1070 if (_error
->PendingError() == true)
1072 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1073 Files
.begin()+EndOfSource
,Files
.end()) == false)
1076 // FIXME: move me to a better place
1077 Gen
.FinishCache(Progress
);
1079 if (_error
->PendingError() == true)
1081 *OutMap
= Map
.UnGuard();