]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
12 // Include Files /*{{{*/
13 #define APT_COMPATIBILITY 986
15 #include <apt-pkg/pkgcachegen.h>
16 #include <apt-pkg/error.h>
17 #include <apt-pkg/version.h>
18 #include <apt-pkg/progress.h>
19 #include <apt-pkg/sourcelist.h>
20 #include <apt-pkg/configuration.h>
21 #include <apt-pkg/strutl.h>
22 #include <apt-pkg/sptr.h>
23 #include <apt-pkg/pkgsystem.h>
25 #include <apt-pkg/tagfile.h>
37 typedef vector
<pkgIndexFile
*>::iterator FileIterator
;
38 uint32_t hashlittle( const void *key
, size_t length
, uint32_t initval
);
40 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
41 // ---------------------------------------------------------------------
42 /* We set the diry 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 Map
.RawAllocate(sizeof(pkgCache::Header
));
58 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
61 *Cache
.HeaderP
= pkgCache::Header();
62 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
63 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
68 // Map directly from the existing file
70 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
71 if (Cache
.VS
!= _system
->VS
)
73 _error
->Error(_("Cache has an incompatible versioning system"));
78 Cache
.HeaderP
->Dirty
= true;
79 Map
.Sync(0,sizeof(pkgCache::Header
));
82 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
83 // ---------------------------------------------------------------------
84 /* We sync the data then unset the dirty flag in two steps so as to
85 advoid a problem during a crash */
86 pkgCacheGenerator::~pkgCacheGenerator()
88 if (_error
->PendingError() == true)
90 if (Map
.Sync() == false)
93 Cache
.HeaderP
->Dirty
= false;
94 Map
.Sync(0,sizeof(pkgCache::Header
));
97 // CacheGenerator::MergeList - Merge the package list /*{{{*/
98 // ---------------------------------------------------------------------
99 /* This provides the generation of the entries in the cache. Each loop
100 goes through a single package record from the underlying parse engine. */
101 bool pkgCacheGenerator::MergeList(ListParser
&List
,
102 pkgCache::VerIterator
*OutVer
)
106 unsigned int Counter
= 0;
107 while (List
.Step() == true)
109 // Get a pointer to the package structure
110 string PackageName
= List
.Package();
111 if (PackageName
.empty() == true)
114 pkgCache::PkgIterator Pkg
;
115 if (NewPackage(Pkg
,PackageName
) == false)
116 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str());
118 if (Counter
% 100 == 0 && Progress
!= 0)
119 Progress
->Progress(List
.Offset());
121 /* Get a pointer to the version structure. We know the list is sorted
122 so we use that fact in the search. Insertion of new versions is
123 done with correct sorting */
124 string Version
= List
.Version();
125 if (Version
.empty() == true)
127 // we first process the package, then the descriptions
128 // (this has the bonus that we get MMap error when we run out
130 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
131 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
132 PackageName
.c_str());
134 // Find the right version to write the description
135 MD5SumValue CurMd5
= List
.Description_md5();
136 pkgCache::VerIterator Ver
= Pkg
.VersionList();
137 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
139 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
141 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
142 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
143 bool duplicate
=false;
145 // don't add a new description if we have one for the given
147 for ( ; Desc
.end() == false; Desc
++)
148 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
149 Desc
.LanguageCode() == List
.DescriptionLanguage())
154 for (Desc
= Ver
.DescriptionList();
156 LastDesc
= &Desc
->NextDesc
, Desc
++)
158 if (MD5SumValue(Desc
.md5()) == CurMd5
)
160 // Add new description
161 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
162 Desc
->ParentPkg
= Pkg
.Index();
164 if (NewFileDesc(Desc
,List
) == false)
165 return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName
.c_str());
174 pkgCache::VerIterator Ver
= Pkg
.VersionList();
175 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
177 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
179 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
184 /* We already have a version for this item, record that we
186 unsigned long Hash
= List
.VersionHash();
187 if (Res
== 0 && Ver
->Hash
== Hash
)
189 if (List
.UsePackage(Pkg
,Ver
) == false)
190 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
191 PackageName
.c_str());
193 if (NewFileVer(Ver
,List
) == false)
194 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
195 PackageName
.c_str());
197 // Read only a single record and return
201 FoundFileDeps
|= List
.HasFileDeps();
208 // Skip to the end of the same version set.
211 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
213 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
220 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
221 Ver
->ParentPkg
= Pkg
.Index();
224 if (List
.NewVersion(Ver
) == false)
225 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
226 PackageName
.c_str());
228 if (List
.UsePackage(Pkg
,Ver
) == false)
229 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
230 PackageName
.c_str());
232 if (NewFileVer(Ver
,List
) == false)
233 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
234 PackageName
.c_str());
236 // Read only a single record and return
240 FoundFileDeps
|= List
.HasFileDeps();
244 /* Record the Description data. Description data always exist in
245 Packages and Translation-* files. */
246 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
247 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
249 // Skip to the end of description set
250 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
252 // Add new description
253 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
254 Desc
->ParentPkg
= Pkg
.Index();
256 if (NewFileDesc(Desc
,List
) == false)
257 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str());
260 FoundFileDeps
|= List
.HasFileDeps();
262 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
263 return _error
->Error(_("Wow, you exceeded the number of package "
264 "names this APT is capable of."));
265 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
266 return _error
->Error(_("Wow, you exceeded the number of versions "
267 "this APT is capable of."));
268 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
269 return _error
->Error(_("Wow, you exceeded the number of descriptions "
270 "this APT is capable of."));
271 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
272 return _error
->Error(_("Wow, you exceeded the number of dependencies "
273 "this APT is capable of."));
277 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
278 // ---------------------------------------------------------------------
279 /* If we found any file depends while parsing the main list we need to
280 resolve them. Since it is undesired to load the entire list of files
281 into the cache as virtual packages we do a two stage effort. MergeList
282 identifies the file depends and this creates Provdies for them by
283 re-parsing all the indexs. */
284 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
288 unsigned int Counter
= 0;
289 while (List
.Step() == true)
291 string PackageName
= List
.Package();
292 if (PackageName
.empty() == true)
294 string Version
= List
.Version();
295 if (Version
.empty() == true)
298 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
299 if (Pkg
.end() == true)
300 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
301 PackageName
.c_str());
303 if (Counter
% 100 == 0 && Progress
!= 0)
304 Progress
->Progress(List
.Offset());
306 unsigned long Hash
= List
.VersionHash();
307 pkgCache::VerIterator Ver
= Pkg
.VersionList();
308 for (; Ver
.end() == false; Ver
++)
310 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
312 if (List
.CollectFileProvides(Cache
,Ver
) == false)
313 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
318 if (Ver
.end() == true)
319 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
325 // CacheGenerator::NewPackage - Add a new package /*{{{*/
326 // ---------------------------------------------------------------------
327 /* This creates a new package structure and adds it to the hash table */
328 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
330 Pkg
= Cache
.FindPkg(Name
);
331 if (Pkg
.end() == false)
335 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
339 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
341 // Insert it into the hash table
342 unsigned long Hash
= Cache
.Hash(Name
);
343 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
344 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
346 // Set the name and the ID
347 Pkg
->Name
= Map
.WriteString(Name
);
350 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
355 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
356 // ---------------------------------------------------------------------
358 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
361 if (CurrentFile
== 0)
365 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
369 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
370 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
372 // Link it to the end of the list
373 map_ptrloc
*Last
= &Ver
->FileList
;
374 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
376 VF
->NextFile
= *Last
;
379 VF
->Offset
= List
.Offset();
380 VF
->Size
= List
.Size();
381 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
382 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
383 Cache
.HeaderP
->VerFileCount
++;
388 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
389 // ---------------------------------------------------------------------
390 /* This puts a version structure in the linked list */
391 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
392 const string
&VerStr
,
396 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
401 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
403 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
404 Ver
->VerStr
= Map
.WriteString(VerStr
);
405 if (Ver
->VerStr
== 0)
411 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
412 // ---------------------------------------------------------------------
414 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
417 if (CurrentFile
== 0)
421 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
425 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
426 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
428 // Link it to the end of the list
429 map_ptrloc
*Last
= &Desc
->FileList
;
430 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
433 DF
->NextFile
= *Last
;
436 DF
->Offset
= List
.Offset();
437 DF
->Size
= List
.Size();
438 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
439 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
440 Cache
.HeaderP
->DescFileCount
++;
445 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
446 // ---------------------------------------------------------------------
447 /* This puts a description structure in the linked list */
448 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
450 const MD5SumValue
&md5sum
,
454 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
455 if (Description
== 0)
459 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
460 Desc
->NextDesc
= Next
;
461 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
462 Desc
->language_code
= Map
.WriteString(Lang
);
463 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
468 // ListParser::NewDepends - Create a dependency element /*{{{*/
469 // ---------------------------------------------------------------------
470 /* This creates a dependency element in the tree. It is linked to the
471 version and to the package that it is pointing to. */
472 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
473 const string
&PackageName
,
474 const string
&Version
,
478 pkgCache
&Cache
= Owner
->Cache
;
481 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
486 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
487 Dep
->ParentVer
= Ver
.Index();
490 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
492 // Locate the target package
493 pkgCache::PkgIterator Pkg
;
494 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
497 // Probe the reverse dependency list for a version string that matches
498 if (Version
.empty() == false)
500 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
501 if (I->Version != 0 && I.TargetVer() == Version)
502 Dep->Version = I->Version;*/
503 if (Dep
->Version
== 0)
504 if ((Dep
->Version
= WriteString(Version
)) == 0)
508 // Link it to the package
509 Dep
->Package
= Pkg
.Index();
510 Dep
->NextRevDepends
= Pkg
->RevDepends
;
511 Pkg
->RevDepends
= Dep
.Index();
513 /* Link it to the version (at the end of the list)
514 Caching the old end point speeds up generation substantially */
515 if (OldDepVer
!= Ver
)
517 OldDepLast
= &Ver
->DependsList
;
518 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
519 OldDepLast
= &D
->NextDepends
;
523 // Is it a file dependency?
524 if (PackageName
[0] == '/')
525 FoundFileDeps
= true;
527 Dep
->NextDepends
= *OldDepLast
;
528 *OldDepLast
= Dep
.Index();
529 OldDepLast
= &Dep
->NextDepends
;
534 // ListParser::NewProvides - Create a Provides element /*{{{*/
535 // ---------------------------------------------------------------------
537 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
538 const string
&PackageName
,
539 const string
&Version
)
541 pkgCache
&Cache
= Owner
->Cache
;
543 // We do not add self referencing provides
544 if (Ver
.ParentPkg().Name() == PackageName
)
548 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
551 Cache
.HeaderP
->ProvidesCount
++;
554 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
555 Prv
->Version
= Ver
.Index();
556 Prv
->NextPkgProv
= Ver
->ProvidesList
;
557 Ver
->ProvidesList
= Prv
.Index();
558 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
561 // Locate the target package
562 pkgCache::PkgIterator Pkg
;
563 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
566 // Link it to the package
567 Prv
->ParentPkg
= Pkg
.Index();
568 Prv
->NextProvides
= Pkg
->ProvidesList
;
569 Pkg
->ProvidesList
= Prv
.Index();
574 // ListParser::NewTag - Create a Tag element /*{{{*/
575 // ---------------------------------------------------------------------
577 bool pkgCacheGenerator::ListParser::NewTag(pkgCache::PkgIterator Pkg
,
578 const char *NameStart
,
579 unsigned int NameSize
)
581 pkgCache
&Cache
= Owner
->Cache
;
584 unsigned long Tagg
= Owner
->Map
.Allocate(sizeof(pkgCache::Tag
));
587 Cache
.HeaderP
->TagCount
++;
590 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ Tagg
);
591 Tg
->Name
= WriteString(NameStart
,NameSize
);
594 Tg
->NextTag
= Pkg
->TagList
;
595 Pkg
->TagList
= Tg
.Index();
600 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
601 // ---------------------------------------------------------------------
602 /* This is used to select which file is to be associated with all newly
603 added versions. The caller is responsible for setting the IMS fields. */
604 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
605 const pkgIndexFile
&Index
,
608 // Get some space for the structure
609 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
610 if (CurrentFile
== Cache
.PkgFileP
)
614 CurrentFile
->FileName
= Map
.WriteString(File
);
615 CurrentFile
->Site
= WriteUniqString(Site
);
616 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
617 CurrentFile
->Flags
= Flags
;
618 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
619 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
621 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
622 Cache
.HeaderP
->PackageFileCount
++;
624 if (CurrentFile
->FileName
== 0)
628 Progress
->SubProgress(Index
.Size());
632 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
633 // ---------------------------------------------------------------------
634 /* This is used to create handles to strings. Given the same text it
635 always returns the same number */
636 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
639 uint32_t hash
= hashlittle(S
, Size
, 0xdeadbeef);
641 /* We use a VERY LARGE INTRANSIENT hash table here, this speeds up generation
642 by AN INSANE amount on ALL machines */
643 pkgCache::StringItem
**Bucket2
;
645 Bucket2
= &UniqHash
[hash
% _count(UniqHash
)];
646 if (*Bucket2
== NULL
)
648 if (stringcmp(S
,S
+Size
,Cache
.StrP
+ (*Bucket2
)->String
) == 0)
649 return (*Bucket2
)->String
;
653 pkgCache::StringItem
*&Bucket
= *Bucket2
;
654 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
655 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
658 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
662 // Fill in the structure
663 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
664 ItemP
->NextItem
= I
- Cache
.StringItemP
;
666 ItemP
->String
= Map
.WriteString(S
,Size
);
667 if (ItemP
->String
== 0)
671 return ItemP
->String
;
675 // CheckValidity - Check that a cache is up-to-date /*{{{*/
676 // ---------------------------------------------------------------------
677 /* This just verifies that each file in the list of index files exists,
678 has matching attributes with the cache and the cache does not have
680 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
681 FileIterator End
,MMap
**OutMap
= 0)
683 // No file, certainly invalid
684 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
688 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
689 SPtr
<MMap
> Map
= new MMap(CacheF
,MMap::Public
| MMap::ReadOnly
);
691 if (_error
->PendingError() == true || Map
->Size() == 0)
697 /* Now we check every index file, see if it is in the cache,
698 verify the IMS data and check that it is on the disk too.. */
699 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
700 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
701 for (; Start
!= End
; Start
++)
703 if ((*Start
)->HasPackages() == false)
706 if ((*Start
)->Exists() == false)
708 #if 0 // mvo: we no longer give a message here (Default Sources spec)
709 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
710 (*Start
)->Describe().c_str());
715 // FindInCache is also expected to do an IMS check.
716 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
717 if (File
.end() == true)
720 Visited
[File
->ID
] = true;
723 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
724 if (Visited
[I
] == false)
727 if (_error
->PendingError() == true)
734 *OutMap
= Map
.UnGuard();
738 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
739 // ---------------------------------------------------------------------
740 /* Size is kind of an abstract notion that is only used for the progress
742 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
744 unsigned long TotalSize
= 0;
745 for (; Start
!= End
; Start
++)
747 if ((*Start
)->HasPackages() == false)
749 TotalSize
+= (*Start
)->Size();
754 // BuildCache - Merge the list of index files into the cache /*{{{*/
755 // ---------------------------------------------------------------------
757 static bool BuildCache(pkgCacheGenerator
&Gen
,
758 OpProgress
&Progress
,
759 unsigned long &CurrentSize
,unsigned long TotalSize
,
760 FileIterator Start
, FileIterator End
)
763 for (I
= Start
; I
!= End
; I
++)
765 if ((*I
)->HasPackages() == false)
768 if ((*I
)->Exists() == false)
771 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
773 _error
->Warning("Duplicate sources.list entry %s",
774 (*I
)->Describe().c_str());
778 unsigned long Size
= (*I
)->Size();
779 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
782 if ((*I
)->Merge(Gen
,Progress
) == false)
786 if (Gen
.HasFileDeps() == true)
789 TotalSize
= ComputeSize(Start
, End
);
791 for (I
= Start
; I
!= End
; I
++)
793 unsigned long Size
= (*I
)->Size();
794 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
796 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
804 // MakeStatusCache - Construct the status cache /*{{{*/
805 // ---------------------------------------------------------------------
806 /* This makes sure that the status cache (the cache that has all
807 index files from the sources list and all local ones) is ready
808 to be mmaped. If OutMap is not zero then a MMap object representing
809 the cache will be stored there. This is pretty much mandetory if you
810 are using AllowMem. AllowMem lets the function be run as non-root
811 where it builds the cache 'fast' into a memory buffer. */
812 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
813 MMap
**OutMap
,bool AllowMem
)
815 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
817 vector
<pkgIndexFile
*> Files
;
818 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
822 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
823 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
826 Files
.push_back (*j
);
829 unsigned long EndOfSource
= Files
.size();
830 if (_system
->AddStatusFiles(Files
) == false)
833 // Decide if we can write to the files..
834 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
835 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
837 // Decide if we can write to the cache
838 bool Writeable
= false;
839 if (CacheFile
.empty() == false)
840 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
842 if (SrcCacheFile
.empty() == false)
843 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
845 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
846 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
848 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
851 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
853 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
857 /* At this point we know we need to reconstruct the package cache,
860 SPtr
<DynamicMMap
> Map
;
861 if (Writeable
== true && CacheFile
.empty() == false)
863 unlink(CacheFile
.c_str());
864 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
865 fchmod(CacheF
->Fd(),0644);
866 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
867 if (_error
->PendingError() == true)
872 // Just build it in memory..
873 Map
= new DynamicMMap(MMap::Public
,MapSize
);
876 // Lets try the source cache.
877 unsigned long CurrentSize
= 0;
878 unsigned long TotalSize
= 0;
879 if (CheckValidity(SrcCacheFile
,Files
.begin(),
880 Files
.begin()+EndOfSource
) == true)
882 // Preload the map with the source cache
883 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
884 if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()),
885 SCacheF
.Size()) == false)
888 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
890 // Build the status cache
891 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
892 if (_error
->PendingError() == true)
894 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
895 Files
.begin()+EndOfSource
,Files
.end()) == false)
900 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
902 // Build the source cache
903 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
904 if (_error
->PendingError() == true)
906 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
907 Files
.begin(),Files
.begin()+EndOfSource
) == false)
911 if (Writeable
== true && SrcCacheFile
.empty() == false)
913 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
914 if (_error
->PendingError() == true)
917 fchmod(SCacheF
.Fd(),0644);
919 // Write out the main data
920 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
921 return _error
->Error(_("IO Error saving source cache"));
924 // Write out the proper header
925 Gen
.GetCache().HeaderP
->Dirty
= false;
926 if (SCacheF
.Seek(0) == false ||
927 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
928 return _error
->Error(_("IO Error saving source cache"));
929 Gen
.GetCache().HeaderP
->Dirty
= true;
933 // Build the status cache
934 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
935 Files
.begin()+EndOfSource
,Files
.end()) == false)
939 if (_error
->PendingError() == true)
945 delete Map
.UnGuard();
946 *OutMap
= new MMap(*CacheF
,MMap::Public
| MMap::ReadOnly
);
950 *OutMap
= Map
.UnGuard();
957 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
958 // ---------------------------------------------------------------------
960 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
962 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
963 vector
<pkgIndexFile
*> Files
;
964 unsigned long EndOfSource
= Files
.size();
965 if (_system
->AddStatusFiles(Files
) == false)
968 SPtr
<DynamicMMap
> Map
;
969 Map
= new DynamicMMap(MMap::Public
,MapSize
);
970 unsigned long CurrentSize
= 0;
971 unsigned long TotalSize
= 0;
973 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
975 // Build the status cache
976 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
977 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
978 if (_error
->PendingError() == true)
980 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
981 Files
.begin()+EndOfSource
,Files
.end()) == false)
984 if (_error
->PendingError() == true)
986 *OutMap
= Map
.UnGuard();