]>
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>
29 #include <apt-pkg/tagfile.h>
41 typedef vector
<pkgIndexFile
*>::iterator FileIterator
;
43 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
44 // ---------------------------------------------------------------------
45 /* We set the diry flag and make sure that is written to the disk */
46 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
47 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
51 memset(UniqHash
,0,sizeof(UniqHash
));
53 if (_error
->PendingError() == true)
58 // Setup the map interface..
59 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
60 Map
.RawAllocate(sizeof(pkgCache::Header
));
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
)
109 unsigned int Counter
= 0;
110 while (List
.Step() == true)
112 // Get a pointer to the package structure
113 string PackageName
= List
.Package();
114 if (PackageName
.empty() == true)
117 pkgCache::PkgIterator Pkg
;
118 if (NewPackage(Pkg
,PackageName
) == false)
119 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str());
121 if (Counter
% 100 == 0 && Progress
!= 0)
122 Progress
->Progress(List
.Offset());
124 /* Get a pointer to the version structure. We know the list is sorted
125 so we use that fact in the search. Insertion of new versions is
126 done with correct sorting */
127 string Version
= List
.Version();
128 if (Version
.empty() == true)
130 // we first process the package, then the descriptions
131 // (this has the bonus that we get MMap error when we run out
133 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
134 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
135 PackageName
.c_str());
137 // Find the right version to write the description
138 MD5SumValue CurMd5
= List
.Description_md5();
139 pkgCache::VerIterator Ver
= Pkg
.VersionList();
140 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
142 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
144 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
145 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
147 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++)
150 if (MD5SumValue(Desc
.md5()) == CurMd5
)
152 // Add new description
153 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
154 Desc
->ParentPkg
= Pkg
.Index();
156 if (NewFileDesc(Desc
,List
) == false)
157 return _error
->Error(_("Error occured while processing %s (NewFileDesc1)"),PackageName
.c_str());
166 pkgCache::VerIterator Ver
= Pkg
.VersionList();
167 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
169 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
171 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
176 /* We already have a version for this item, record that we
178 unsigned long Hash
= List
.VersionHash();
179 if (Res
== 0 && Ver
->Hash
== Hash
)
181 if (List
.UsePackage(Pkg
,Ver
) == false)
182 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
183 PackageName
.c_str());
185 if (NewFileVer(Ver
,List
) == false)
186 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
187 PackageName
.c_str());
189 // Read only a single record and return
193 FoundFileDeps
|= List
.HasFileDeps();
200 // Skip to the end of the same version set.
203 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
205 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
212 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
213 Ver
->ParentPkg
= Pkg
.Index();
216 if (List
.NewVersion(Ver
) == false)
217 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
218 PackageName
.c_str());
220 if (List
.UsePackage(Pkg
,Ver
) == false)
221 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
222 PackageName
.c_str());
224 if (NewFileVer(Ver
,List
) == false)
225 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
226 PackageName
.c_str());
228 // Read only a single record and return
232 FoundFileDeps
|= List
.HasFileDeps();
236 /* Record the Description data. Description data always exist in
237 Packages and Translation-* files. */
238 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
239 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
241 // Skip to the end of description set
242 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
244 // Add new description
245 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
246 Desc
->ParentPkg
= Pkg
.Index();
248 if (NewFileDesc(Desc
,List
) == false)
249 return _error
->Error(_("Error occured while processing %s (NewFileDesc2)"),PackageName
.c_str());
252 FoundFileDeps
|= List
.HasFileDeps();
254 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
255 return _error
->Error(_("Wow, you exceeded the number of package "
256 "names this APT is capable of."));
257 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
258 return _error
->Error(_("Wow, you exceeded the number of versions "
259 "this APT is capable of."));
260 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
261 return _error
->Error(_("Wow, you exceeded the number of descriptions "
262 "this APT is capable of."));
263 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
264 return _error
->Error(_("Wow, you exceeded the number of dependencies "
265 "this APT is capable of."));
269 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
270 // ---------------------------------------------------------------------
271 /* If we found any file depends while parsing the main list we need to
272 resolve them. Since it is undesired to load the entire list of files
273 into the cache as virtual packages we do a two stage effort. MergeList
274 identifies the file depends and this creates Provdies for them by
275 re-parsing all the indexs. */
276 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
280 unsigned int Counter
= 0;
281 while (List
.Step() == true)
283 string PackageName
= List
.Package();
284 if (PackageName
.empty() == true)
286 string Version
= List
.Version();
287 if (Version
.empty() == true)
290 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
291 if (Pkg
.end() == true)
292 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
293 PackageName
.c_str());
295 if (Counter
% 100 == 0 && Progress
!= 0)
296 Progress
->Progress(List
.Offset());
298 unsigned long Hash
= List
.VersionHash();
299 pkgCache::VerIterator Ver
= Pkg
.VersionList();
300 for (; Ver
.end() == false; Ver
++)
302 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
304 if (List
.CollectFileProvides(Cache
,Ver
) == false)
305 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
310 if (Ver
.end() == true)
311 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
317 // CacheGenerator::NewPackage - Add a new package /*{{{*/
318 // ---------------------------------------------------------------------
319 /* This creates a new package structure and adds it to the hash table */
320 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
322 Pkg
= Cache
.FindPkg(Name
);
323 if (Pkg
.end() == false)
327 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
331 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
333 // Insert it into the hash table
334 unsigned long Hash
= Cache
.Hash(Name
);
335 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
336 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
338 // Set the name and the ID
339 Pkg
->Name
= Map
.WriteString(Name
);
342 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
347 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
348 // ---------------------------------------------------------------------
350 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
353 if (CurrentFile
== 0)
357 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
361 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
362 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
364 // Link it to the end of the list
365 map_ptrloc
*Last
= &Ver
->FileList
;
366 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
368 VF
->NextFile
= *Last
;
371 VF
->Offset
= List
.Offset();
372 VF
->Size
= List
.Size();
373 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
374 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
375 Cache
.HeaderP
->VerFileCount
++;
380 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
381 // ---------------------------------------------------------------------
382 /* This puts a version structure in the linked list */
383 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
384 const string
&VerStr
,
388 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
393 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
395 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
396 Ver
->VerStr
= Map
.WriteString(VerStr
);
397 if (Ver
->VerStr
== 0)
403 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
404 // ---------------------------------------------------------------------
406 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
409 if (CurrentFile
== 0)
413 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
417 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
418 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
420 // Link it to the end of the list
421 map_ptrloc
*Last
= &Desc
->FileList
;
422 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
425 DF
->NextFile
= *Last
;
428 DF
->Offset
= List
.Offset();
429 DF
->Size
= List
.Size();
430 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
431 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
432 Cache
.HeaderP
->DescFileCount
++;
437 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
438 // ---------------------------------------------------------------------
439 /* This puts a description structure in the linked list */
440 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
441 const string
&Lang
, const MD5SumValue
&md5sum
,
445 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
446 if (Description
== 0)
450 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
451 Desc
->NextDesc
= Next
;
452 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
453 Desc
->language_code
= Map
.WriteString(Lang
);
454 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
459 // ListParser::NewDepends - Create a dependency element /*{{{*/
460 // ---------------------------------------------------------------------
461 /* This creates a dependency element in the tree. It is linked to the
462 version and to the package that it is pointing to. */
463 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
464 const string
&PackageName
,
465 const string
&Version
,
469 pkgCache
&Cache
= Owner
->Cache
;
472 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
477 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
478 Dep
->ParentVer
= Ver
.Index();
481 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
483 // Locate the target package
484 pkgCache::PkgIterator Pkg
;
485 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
488 // Probe the reverse dependency list for a version string that matches
489 if (Version
.empty() == false)
491 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
492 if (I->Version != 0 && I.TargetVer() == Version)
493 Dep->Version = I->Version;*/
494 if (Dep
->Version
== 0)
495 if ((Dep
->Version
= WriteString(Version
)) == 0)
499 // Link it to the package
500 Dep
->Package
= Pkg
.Index();
501 Dep
->NextRevDepends
= Pkg
->RevDepends
;
502 Pkg
->RevDepends
= Dep
.Index();
504 /* Link it to the version (at the end of the list)
505 Caching the old end point speeds up generation substantially */
506 if (OldDepVer
!= Ver
)
508 OldDepLast
= &Ver
->DependsList
;
509 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
510 OldDepLast
= &D
->NextDepends
;
514 // Is it a file dependency?
515 if (PackageName
[0] == '/')
516 FoundFileDeps
= true;
518 Dep
->NextDepends
= *OldDepLast
;
519 *OldDepLast
= Dep
.Index();
520 OldDepLast
= &Dep
->NextDepends
;
525 // ListParser::NewProvides - Create a Provides element /*{{{*/
526 // ---------------------------------------------------------------------
528 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
529 const string
&PackageName
,
530 const string
&Version
)
532 pkgCache
&Cache
= Owner
->Cache
;
534 // We do not add self referencing provides
535 if (Ver
.ParentPkg().Name() == PackageName
)
539 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
542 Cache
.HeaderP
->ProvidesCount
++;
545 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
546 Prv
->Version
= Ver
.Index();
547 Prv
->NextPkgProv
= Ver
->ProvidesList
;
548 Ver
->ProvidesList
= Prv
.Index();
549 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
552 // Locate the target package
553 pkgCache::PkgIterator Pkg
;
554 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
557 // Link it to the package
558 Prv
->ParentPkg
= Pkg
.Index();
559 Prv
->NextProvides
= Pkg
->ProvidesList
;
560 Pkg
->ProvidesList
= Prv
.Index();
565 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
566 // ---------------------------------------------------------------------
567 /* This is used to select which file is to be associated with all newly
568 added versions. The caller is responsible for setting the IMS fields. */
569 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
570 const pkgIndexFile
&Index
,
573 // Get some space for the structure
574 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
575 if (CurrentFile
== Cache
.PkgFileP
)
579 CurrentFile
->FileName
= Map
.WriteString(File
);
580 CurrentFile
->Site
= WriteUniqString(Site
);
581 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
582 CurrentFile
->Flags
= Flags
;
583 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
584 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
586 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
587 Cache
.HeaderP
->PackageFileCount
++;
589 if (CurrentFile
->FileName
== 0)
593 Progress
->SubProgress(Index
.Size());
597 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
598 // ---------------------------------------------------------------------
599 /* This is used to create handles to strings. Given the same text it
600 always returns the same number */
601 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
604 /* We use a very small transient hash table here, this speeds up generation
605 by a fair amount on slower machines */
606 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
608 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
609 return Bucket
->String
;
611 // Search for an insertion point
612 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
614 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
615 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
616 I
= Cache
.StringItemP
+ I
->NextItem
)
618 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
631 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
635 // Fill in the structure
636 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
637 ItemP
->NextItem
= I
- Cache
.StringItemP
;
639 ItemP
->String
= Map
.WriteString(S
,Size
);
640 if (ItemP
->String
== 0)
644 return ItemP
->String
;
648 // CheckValidity - Check that a cache is up-to-date /*{{{*/
649 // ---------------------------------------------------------------------
650 /* This just verifies that each file in the list of index files exists,
651 has matching attributes with the cache and the cache does not have
653 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
654 FileIterator End
,MMap
**OutMap
= 0)
656 // No file, certainly invalid
657 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
661 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
662 SPtr
<MMap
> Map
= new MMap(CacheF
,MMap::Public
| MMap::ReadOnly
);
664 if (_error
->PendingError() == true || Map
->Size() == 0)
670 /* Now we check every index file, see if it is in the cache,
671 verify the IMS data and check that it is on the disk too.. */
672 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
673 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
674 for (; Start
!= End
; Start
++)
676 if ((*Start
)->HasPackages() == false)
679 if ((*Start
)->Exists() == false)
681 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
682 (*Start
)->Describe().c_str());
686 // FindInCache is also expected to do an IMS check.
687 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
688 if (File
.end() == true)
691 Visited
[File
->ID
] = true;
694 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
695 if (Visited
[I
] == false)
698 if (_error
->PendingError() == true)
705 *OutMap
= Map
.UnGuard();
709 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
710 // ---------------------------------------------------------------------
711 /* Size is kind of an abstract notion that is only used for the progress
713 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
715 unsigned long TotalSize
= 0;
716 for (; Start
!= End
; Start
++)
718 if ((*Start
)->HasPackages() == false)
720 TotalSize
+= (*Start
)->Size();
725 // BuildCache - Merge the list of index files into the cache /*{{{*/
726 // ---------------------------------------------------------------------
728 static bool BuildCache(pkgCacheGenerator
&Gen
,
729 OpProgress
&Progress
,
730 unsigned long &CurrentSize
,unsigned long TotalSize
,
731 FileIterator Start
, FileIterator End
)
734 for (I
= Start
; I
!= End
; I
++)
736 if ((*I
)->HasPackages() == false)
739 if ((*I
)->Exists() == false)
742 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
744 _error
->Warning("Duplicate sources.list entry %s",
745 (*I
)->Describe().c_str());
749 unsigned long Size
= (*I
)->Size();
750 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
753 if ((*I
)->Merge(Gen
,Progress
) == false)
757 if (Gen
.HasFileDeps() == true)
760 TotalSize
= ComputeSize(Start
, End
);
762 for (I
= Start
; I
!= End
; I
++)
764 unsigned long Size
= (*I
)->Size();
765 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
767 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
775 // MakeStatusCache - Construct the status cache /*{{{*/
776 // ---------------------------------------------------------------------
777 /* This makes sure that the status cache (the cache that has all
778 index files from the sources list and all local ones) is ready
779 to be mmaped. If OutMap is not zero then a MMap object representing
780 the cache will be stored there. This is pretty much mandetory if you
781 are using AllowMem. AllowMem lets the function be run as non-root
782 where it builds the cache 'fast' into a memory buffer. */
783 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
784 MMap
**OutMap
,bool AllowMem
)
786 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",12*1024*1024);
788 vector
<pkgIndexFile
*> Files
;
789 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
793 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
794 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
797 Files
.push_back (*j
);
800 unsigned long EndOfSource
= Files
.size();
801 if (_system
->AddStatusFiles(Files
) == false)
804 // Decide if we can write to the files..
805 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
806 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
808 // Decide if we can write to the cache
809 bool Writeable
= false;
810 if (CacheFile
.empty() == false)
811 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
813 if (SrcCacheFile
.empty() == false)
814 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
816 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
817 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
819 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
822 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
824 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
828 /* At this point we know we need to reconstruct the package cache,
831 SPtr
<DynamicMMap
> Map
;
832 if (Writeable
== true && CacheFile
.empty() == false)
834 unlink(CacheFile
.c_str());
835 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
836 fchmod(CacheF
->Fd(),0644);
837 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
838 if (_error
->PendingError() == true)
843 // Just build it in memory..
844 Map
= new DynamicMMap(MMap::Public
,MapSize
);
847 // Lets try the source cache.
848 unsigned long CurrentSize
= 0;
849 unsigned long TotalSize
= 0;
850 if (CheckValidity(SrcCacheFile
,Files
.begin(),
851 Files
.begin()+EndOfSource
) == true)
853 // Preload the map with the source cache
854 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
855 if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()),
856 SCacheF
.Size()) == false)
859 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
861 // Build the status cache
862 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
863 if (_error
->PendingError() == true)
865 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
866 Files
.begin()+EndOfSource
,Files
.end()) == false)
871 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
873 // Build the source cache
874 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
875 if (_error
->PendingError() == true)
877 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
878 Files
.begin(),Files
.begin()+EndOfSource
) == false)
882 if (Writeable
== true && SrcCacheFile
.empty() == false)
884 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
885 if (_error
->PendingError() == true)
888 fchmod(SCacheF
.Fd(),0644);
890 // Write out the main data
891 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
892 return _error
->Error(_("IO Error saving source cache"));
895 // Write out the proper header
896 Gen
.GetCache().HeaderP
->Dirty
= false;
897 if (SCacheF
.Seek(0) == false ||
898 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
899 return _error
->Error(_("IO Error saving source cache"));
900 Gen
.GetCache().HeaderP
->Dirty
= true;
904 // Build the status cache
905 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
906 Files
.begin()+EndOfSource
,Files
.end()) == false)
910 if (_error
->PendingError() == true)
916 delete Map
.UnGuard();
917 *OutMap
= new MMap(*CacheF
,MMap::Public
| MMap::ReadOnly
);
921 *OutMap
= Map
.UnGuard();
928 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
929 // ---------------------------------------------------------------------
931 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
933 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",8*1024*1024);
934 vector
<pkgIndexFile
*> Files
;
935 unsigned long EndOfSource
= Files
.size();
936 if (_system
->AddStatusFiles(Files
) == false)
939 SPtr
<DynamicMMap
> Map
;
940 Map
= new DynamicMMap(MMap::Public
,MapSize
);
941 unsigned long CurrentSize
= 0;
942 unsigned long TotalSize
= 0;
944 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
946 // Build the status cache
947 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
948 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
949 if (_error
->PendingError() == true)
951 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
952 Files
.begin()+EndOfSource
,Files
.end()) == false)
955 if (_error
->PendingError() == true)
957 *OutMap
= Map
.UnGuard();