]>
git.saurik.com Git - apt.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 /*{{{*/
14 #pragma implementation "apt-pkg/pkgcachegen.h"
17 #define APT_COMPATIBILITY 986
19 #include <apt-pkg/pkgcachegen.h>
20 #include <apt-pkg/error.h>
21 #include <apt-pkg/version.h>
22 #include <apt-pkg/progress.h>
23 #include <apt-pkg/sourcelist.h>
24 #include <apt-pkg/configuration.h>
25 #include <apt-pkg/strutl.h>
26 #include <apt-pkg/sptr.h>
27 #include <apt-pkg/pkgsystem.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 Map
.RawAllocate(sizeof(pkgCache::Header
));
59 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
62 *Cache
.HeaderP
= pkgCache::Header();
63 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
64 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
69 // Map directly from the existing file
71 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
72 if (Cache
.VS
!= _system
->VS
)
74 _error
->Error(_("Cache has an incompatible versioning system"));
79 Cache
.HeaderP
->Dirty
= true;
80 Map
.Sync(0,sizeof(pkgCache::Header
));
83 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
84 // ---------------------------------------------------------------------
85 /* We sync the data then unset the dirty flag in two steps so as to
86 advoid a problem during a crash */
87 pkgCacheGenerator::~pkgCacheGenerator()
89 if (_error
->PendingError() == true)
91 if (Map
.Sync() == false)
94 Cache
.HeaderP
->Dirty
= false;
95 Map
.Sync(0,sizeof(pkgCache::Header
));
98 // CacheGenerator::MergeList - Merge the package list /*{{{*/
99 // ---------------------------------------------------------------------
100 /* This provides the generation of the entries in the cache. Each loop
101 goes through a single package record from the underlying parse engine. */
102 bool pkgCacheGenerator::MergeList(ListParser
&List
,
103 pkgCache::VerIterator
*OutVer
)
107 unsigned int Counter
= 0;
108 while (List
.Step() == true)
110 // Get a pointer to the package structure
111 string PackageName
= List
.Package();
112 if (PackageName
.empty() == true)
115 pkgCache::PkgIterator Pkg
;
116 if (NewPackage(Pkg
,PackageName
) == false)
117 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str());
119 if (Counter
% 100 == 0 && Progress
!= 0)
120 Progress
->Progress(List
.Offset());
122 /* Get a pointer to the version structure. We know the list is sorted
123 so we use that fact in the search. Insertion of new versions is
124 done with correct sorting */
125 string Version
= List
.Version();
126 if (Version
.empty() == true)
128 // we first process the package, then the descriptions
129 // (this has the bonus that we get MMap error when we run out
131 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
132 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
133 PackageName
.c_str());
135 // Find the right version to write the description
136 MD5SumValue CurMd5
= List
.Description_md5();
137 pkgCache::VerIterator Ver
= Pkg
.VersionList();
138 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
140 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
142 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
143 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
145 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++)
148 if (MD5SumValue(Desc
.md5()) == CurMd5
)
150 // Add new description
151 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
152 Desc
->ParentPkg
= Pkg
.Index();
154 if (NewFileDesc(Desc
,List
) == false)
155 return _error
->Error(_("Error occured while processing %s (NewFileDesc1)"),PackageName
.c_str());
164 pkgCache::VerIterator Ver
= Pkg
.VersionList();
165 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
167 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
169 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
174 /* We already have a version for this item, record that we
176 unsigned long Hash
= List
.VersionHash();
177 if (Res
== 0 && Ver
->Hash
== Hash
)
179 if (List
.UsePackage(Pkg
,Ver
) == false)
180 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
181 PackageName
.c_str());
183 if (NewFileVer(Ver
,List
) == false)
184 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
185 PackageName
.c_str());
187 // Read only a single record and return
191 FoundFileDeps
|= List
.HasFileDeps();
198 // Skip to the end of the same version set.
201 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
203 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
210 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
211 Ver
->ParentPkg
= Pkg
.Index();
214 if (List
.NewVersion(Ver
) == false)
215 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
216 PackageName
.c_str());
218 if (List
.UsePackage(Pkg
,Ver
) == false)
219 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
220 PackageName
.c_str());
222 if (NewFileVer(Ver
,List
) == false)
223 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
224 PackageName
.c_str());
226 // Read only a single record and return
230 FoundFileDeps
|= List
.HasFileDeps();
234 /* Record the Description data. Description data always exist in
235 Packages and Translation-* files. */
236 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
237 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
239 // Skip to the end of description set
240 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
242 // Add new description
243 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
244 Desc
->ParentPkg
= Pkg
.Index();
246 if (NewFileDesc(Desc
,List
) == false)
247 return _error
->Error(_("Error occured while processing %s (NewFileDesc2)"),PackageName
.c_str());
250 FoundFileDeps
|= List
.HasFileDeps();
252 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
253 return _error
->Error(_("Wow, you exceeded the number of package "
254 "names this APT is capable of."));
255 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
256 return _error
->Error(_("Wow, you exceeded the number of versions "
257 "this APT is capable of."));
258 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
259 return _error
->Error(_("Wow, you exceeded the number of descriptions "
260 "this APT is capable of."));
261 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
262 return _error
->Error(_("Wow, you exceeded the number of dependencies "
263 "this APT is capable of."));
267 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
268 // ---------------------------------------------------------------------
269 /* If we found any file depends while parsing the main list we need to
270 resolve them. Since it is undesired to load the entire list of files
271 into the cache as virtual packages we do a two stage effort. MergeList
272 identifies the file depends and this creates Provdies for them by
273 re-parsing all the indexs. */
274 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
278 unsigned int Counter
= 0;
279 while (List
.Step() == true)
281 string PackageName
= List
.Package();
282 if (PackageName
.empty() == true)
284 string Version
= List
.Version();
285 if (Version
.empty() == true)
288 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
289 if (Pkg
.end() == true)
290 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
291 PackageName
.c_str());
293 if (Counter
% 100 == 0 && Progress
!= 0)
294 Progress
->Progress(List
.Offset());
296 unsigned long Hash
= List
.VersionHash();
297 pkgCache::VerIterator Ver
= Pkg
.VersionList();
298 for (; Ver
.end() == false; Ver
++)
300 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
302 if (List
.CollectFileProvides(Cache
,Ver
) == false)
303 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
308 if (Ver
.end() == true)
309 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
315 // CacheGenerator::NewPackage - Add a new package /*{{{*/
316 // ---------------------------------------------------------------------
317 /* This creates a new package structure and adds it to the hash table */
318 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,string Name
)
320 Pkg
= Cache
.FindPkg(Name
);
321 if (Pkg
.end() == false)
325 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
329 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
331 // Insert it into the hash table
332 unsigned long Hash
= Cache
.Hash(Name
);
333 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
334 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
336 // Set the name and the ID
337 Pkg
->Name
= Map
.WriteString(Name
);
340 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
345 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
346 // ---------------------------------------------------------------------
348 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
351 if (CurrentFile
== 0)
355 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
359 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
360 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
362 // Link it to the end of the list
363 map_ptrloc
*Last
= &Ver
->FileList
;
364 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
366 VF
->NextFile
= *Last
;
369 VF
->Offset
= List
.Offset();
370 VF
->Size
= List
.Size();
371 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
372 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
373 Cache
.HeaderP
->VerFileCount
++;
378 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
379 // ---------------------------------------------------------------------
380 /* This puts a version structure in the linked list */
381 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
386 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
391 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
393 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
394 Ver
->VerStr
= Map
.WriteString(VerStr
);
395 if (Ver
->VerStr
== 0)
401 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
402 // ---------------------------------------------------------------------
404 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
407 if (CurrentFile
== 0)
411 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
415 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
416 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
418 // Link it to the end of the list
419 map_ptrloc
*Last
= &Desc
->FileList
;
420 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
423 DF
->NextFile
= *Last
;
426 DF
->Offset
= List
.Offset();
427 DF
->Size
= List
.Size();
428 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
429 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
430 Cache
.HeaderP
->DescFileCount
++;
435 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
436 // ---------------------------------------------------------------------
437 /* This puts a description structure in the linked list */
438 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
439 const string
&Lang
, const MD5SumValue
&md5sum
,
443 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
444 if (Description
== 0)
448 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
449 Desc
->NextDesc
= Next
;
450 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
451 Desc
->language_code
= Map
.WriteString(Lang
);
452 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
457 // ListParser::NewDepends - Create a dependency element /*{{{*/
458 // ---------------------------------------------------------------------
459 /* This creates a dependency element in the tree. It is linked to the
460 version and to the package that it is pointing to. */
461 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
467 pkgCache
&Cache
= Owner
->Cache
;
470 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
475 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
476 Dep
->ParentVer
= Ver
.Index();
479 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
481 // Locate the target package
482 pkgCache::PkgIterator Pkg
;
483 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
486 // Probe the reverse dependency list for a version string that matches
487 if (Version
.empty() == false)
489 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
490 if (I->Version != 0 && I.TargetVer() == Version)
491 Dep->Version = I->Version;*/
492 if (Dep
->Version
== 0)
493 if ((Dep
->Version
= WriteString(Version
)) == 0)
497 // Link it to the package
498 Dep
->Package
= Pkg
.Index();
499 Dep
->NextRevDepends
= Pkg
->RevDepends
;
500 Pkg
->RevDepends
= Dep
.Index();
502 /* Link it to the version (at the end of the list)
503 Caching the old end point speeds up generation substantially */
504 if (OldDepVer
!= Ver
)
506 OldDepLast
= &Ver
->DependsList
;
507 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
508 OldDepLast
= &D
->NextDepends
;
512 // Is it a file dependency?
513 if (PackageName
[0] == '/')
514 FoundFileDeps
= true;
516 Dep
->NextDepends
= *OldDepLast
;
517 *OldDepLast
= Dep
.Index();
518 OldDepLast
= &Dep
->NextDepends
;
523 // ListParser::NewProvides - Create a Provides element /*{{{*/
524 // ---------------------------------------------------------------------
526 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
530 pkgCache
&Cache
= Owner
->Cache
;
532 // We do not add self referencing provides
533 if (Ver
.ParentPkg().Name() == PackageName
)
537 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
540 Cache
.HeaderP
->ProvidesCount
++;
543 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
544 Prv
->Version
= Ver
.Index();
545 Prv
->NextPkgProv
= Ver
->ProvidesList
;
546 Ver
->ProvidesList
= Prv
.Index();
547 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
550 // Locate the target package
551 pkgCache::PkgIterator Pkg
;
552 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
555 // Link it to the package
556 Prv
->ParentPkg
= Pkg
.Index();
557 Prv
->NextProvides
= Pkg
->ProvidesList
;
558 Pkg
->ProvidesList
= Prv
.Index();
563 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
564 // ---------------------------------------------------------------------
565 /* This is used to select which file is to be associated with all newly
566 added versions. The caller is responsible for setting the IMS fields. */
567 bool pkgCacheGenerator::SelectFile(string File
,string Site
,
568 const pkgIndexFile
&Index
,
571 // Get some space for the structure
572 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
573 if (CurrentFile
== Cache
.PkgFileP
)
577 CurrentFile
->FileName
= Map
.WriteString(File
);
578 CurrentFile
->Site
= WriteUniqString(Site
);
579 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
580 CurrentFile
->Flags
= Flags
;
581 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
582 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
584 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
585 Cache
.HeaderP
->PackageFileCount
++;
587 if (CurrentFile
->FileName
== 0)
591 Progress
->SubProgress(Index
.Size());
595 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
596 // ---------------------------------------------------------------------
597 /* This is used to create handles to strings. Given the same text it
598 always returns the same number */
599 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
602 /* We use a very small transient hash table here, this speeds up generation
603 by a fair amount on slower machines */
604 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
606 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
607 return Bucket
->String
;
609 // Search for an insertion point
610 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
612 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
613 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
614 I
= Cache
.StringItemP
+ I
->NextItem
)
616 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
629 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
633 // Fill in the structure
634 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
635 ItemP
->NextItem
= I
- Cache
.StringItemP
;
637 ItemP
->String
= Map
.WriteString(S
,Size
);
638 if (ItemP
->String
== 0)
642 return ItemP
->String
;
646 // CheckValidity - Check that a cache is up-to-date /*{{{*/
647 // ---------------------------------------------------------------------
648 /* This just verifies that each file in the list of index files exists,
649 has matching attributes with the cache and the cache does not have
651 static bool CheckValidity(string CacheFile
, FileIterator Start
,
652 FileIterator End
,MMap
**OutMap
= 0)
654 // No file, certainly invalid
655 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
659 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
660 SPtr
<MMap
> Map
= new MMap(CacheF
,MMap::Public
| MMap::ReadOnly
);
662 if (_error
->PendingError() == true || Map
->Size() == 0)
668 /* Now we check every index file, see if it is in the cache,
669 verify the IMS data and check that it is on the disk too.. */
670 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
671 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
672 for (; Start
!= End
; Start
++)
674 if ((*Start
)->HasPackages() == false)
677 if ((*Start
)->Exists() == false)
679 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
680 (*Start
)->Describe().c_str());
684 // FindInCache is also expected to do an IMS check.
685 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
686 if (File
.end() == true)
689 Visited
[File
->ID
] = true;
692 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
693 if (Visited
[I
] == false)
696 if (_error
->PendingError() == true)
703 *OutMap
= Map
.UnGuard();
707 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
708 // ---------------------------------------------------------------------
709 /* Size is kind of an abstract notion that is only used for the progress
711 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
713 unsigned long TotalSize
= 0;
714 for (; Start
!= End
; Start
++)
716 if ((*Start
)->HasPackages() == false)
718 TotalSize
+= (*Start
)->Size();
723 // BuildCache - Merge the list of index files into the cache /*{{{*/
724 // ---------------------------------------------------------------------
726 static bool BuildCache(pkgCacheGenerator
&Gen
,
727 OpProgress
&Progress
,
728 unsigned long &CurrentSize
,unsigned long TotalSize
,
729 FileIterator Start
, FileIterator End
)
732 for (I
= Start
; I
!= End
; I
++)
734 if ((*I
)->HasPackages() == false)
737 if ((*I
)->Exists() == false)
740 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
742 _error
->Warning("Duplicate sources.list entry %s",
743 (*I
)->Describe().c_str());
747 unsigned long Size
= (*I
)->Size();
748 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
751 if ((*I
)->Merge(Gen
,Progress
) == false)
755 if (Gen
.HasFileDeps() == true)
758 TotalSize
= ComputeSize(Start
, End
);
760 for (I
= Start
; I
!= End
; I
++)
762 unsigned long Size
= (*I
)->Size();
763 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
765 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
773 // MakeStatusCache - Construct the status cache /*{{{*/
774 // ---------------------------------------------------------------------
775 /* This makes sure that the status cache (the cache that has all
776 index files from the sources list and all local ones) is ready
777 to be mmaped. If OutMap is not zero then a MMap object representing
778 the cache will be stored there. This is pretty much mandetory if you
779 are using AllowMem. AllowMem lets the function be run as non-root
780 where it builds the cache 'fast' into a memory buffer. */
781 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
782 MMap
**OutMap
,bool AllowMem
)
784 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",12*1024*1024);
786 vector
<pkgIndexFile
*> Files
;
787 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
791 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
792 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
795 Files
.push_back (*j
);
798 unsigned long EndOfSource
= Files
.size();
799 if (_system
->AddStatusFiles(Files
) == false)
802 // Decide if we can write to the files..
803 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
804 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
806 // Decide if we can write to the cache
807 bool Writeable
= false;
808 if (CacheFile
.empty() == false)
809 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
811 if (SrcCacheFile
.empty() == false)
812 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
814 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
815 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
817 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
820 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
822 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
826 /* At this point we know we need to reconstruct the package cache,
829 SPtr
<DynamicMMap
> Map
;
830 if (Writeable
== true && CacheFile
.empty() == false)
832 unlink(CacheFile
.c_str());
833 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
834 fchmod(CacheF
->Fd(),0644);
835 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
836 if (_error
->PendingError() == true)
841 // Just build it in memory..
842 Map
= new DynamicMMap(MMap::Public
,MapSize
);
845 // Lets try the source cache.
846 unsigned long CurrentSize
= 0;
847 unsigned long TotalSize
= 0;
848 if (CheckValidity(SrcCacheFile
,Files
.begin(),
849 Files
.begin()+EndOfSource
) == true)
851 // Preload the map with the source cache
852 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
853 if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()),
854 SCacheF
.Size()) == false)
857 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
859 // Build the status cache
860 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
861 if (_error
->PendingError() == true)
863 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
864 Files
.begin()+EndOfSource
,Files
.end()) == false)
869 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
871 // Build the source cache
872 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
873 if (_error
->PendingError() == true)
875 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
876 Files
.begin(),Files
.begin()+EndOfSource
) == false)
880 if (Writeable
== true && SrcCacheFile
.empty() == false)
882 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
883 if (_error
->PendingError() == true)
886 fchmod(SCacheF
.Fd(),0644);
888 // Write out the main data
889 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
890 return _error
->Error(_("IO Error saving source cache"));
893 // Write out the proper header
894 Gen
.GetCache().HeaderP
->Dirty
= false;
895 if (SCacheF
.Seek(0) == false ||
896 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
897 return _error
->Error(_("IO Error saving source cache"));
898 Gen
.GetCache().HeaderP
->Dirty
= true;
902 // Build the status cache
903 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
904 Files
.begin()+EndOfSource
,Files
.end()) == false)
908 if (_error
->PendingError() == true)
914 delete Map
.UnGuard();
915 *OutMap
= new MMap(*CacheF
,MMap::Public
| MMap::ReadOnly
);
919 *OutMap
= Map
.UnGuard();
926 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
927 // ---------------------------------------------------------------------
929 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
931 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",8*1024*1024);
932 vector
<pkgIndexFile
*> Files
;
933 unsigned long EndOfSource
= Files
.size();
934 if (_system
->AddStatusFiles(Files
) == false)
937 SPtr
<DynamicMMap
> Map
;
938 Map
= new DynamicMMap(MMap::Public
,MapSize
);
939 unsigned long CurrentSize
= 0;
940 unsigned long TotalSize
= 0;
942 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
944 // Build the status cache
945 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
946 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
947 if (_error
->PendingError() == true)
949 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
950 Files
.begin()+EndOfSource
,Files
.end()) == false)
953 if (_error
->PendingError() == true)
955 *OutMap
= Map
.UnGuard();