]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/pkgcachegen.cc
1b536495da86bafe84ae2eef5c04e0c9e244b5c1
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
;
39 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
40 // ---------------------------------------------------------------------
41 /* We set the diry flag and make sure that is written to the disk */
42 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
43 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
47 memset(UniqHash
,0,sizeof(UniqHash
));
49 if (_error
->PendingError() == true)
54 // Setup the map interface..
55 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
56 Map
.RawAllocate(sizeof(pkgCache::Header
));
57 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
60 *Cache
.HeaderP
= pkgCache::Header();
61 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
62 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
67 // Map directly from the existing file
69 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
70 if (Cache
.VS
!= _system
->VS
)
72 _error
->Error(_("Cache has an incompatible versioning system"));
77 Cache
.HeaderP
->Dirty
= true;
78 Map
.Sync(0,sizeof(pkgCache::Header
));
81 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
82 // ---------------------------------------------------------------------
83 /* We sync the data then unset the dirty flag in two steps so as to
84 advoid a problem during a crash */
85 pkgCacheGenerator::~pkgCacheGenerator()
87 if (_error
->PendingError() == true)
89 if (Map
.Sync() == false)
92 Cache
.HeaderP
->Dirty
= false;
93 Map
.Sync(0,sizeof(pkgCache::Header
));
96 // CacheGenerator::MergeList - Merge the package list /*{{{*/
97 // ---------------------------------------------------------------------
98 /* This provides the generation of the entries in the cache. Each loop
99 goes through a single package record from the underlying parse engine. */
100 bool pkgCacheGenerator::MergeList(ListParser
&List
,
101 pkgCache::VerIterator
*OutVer
)
105 unsigned int Counter
= 0;
106 while (List
.Step() == true)
108 // Get a pointer to the package structure
109 string PackageName
= List
.Package();
110 if (PackageName
.empty() == true)
113 pkgCache::PkgIterator Pkg
;
114 if (NewPackage(Pkg
,PackageName
) == false)
115 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str());
117 if (Counter
% 100 == 0 && Progress
!= 0)
118 Progress
->Progress(List
.Offset());
120 /* Get a pointer to the version structure. We know the list is sorted
121 so we use that fact in the search. Insertion of new versions is
122 done with correct sorting */
123 string Version
= List
.Version();
124 if (Version
.empty() == true)
126 // we first process the package, then the descriptions
127 // (this has the bonus that we get MMap error when we run out
129 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
130 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
131 PackageName
.c_str());
133 // Find the right version to write the description
134 MD5SumValue CurMd5
= List
.Description_md5();
135 pkgCache::VerIterator Ver
= Pkg
.VersionList();
136 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
138 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
140 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
141 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
142 bool duplicate
=false;
144 // don't add a new description if we have one for the given
146 for ( ; Desc
.end() == false; Desc
++)
147 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
148 Desc
.LanguageCode() == List
.DescriptionLanguage())
153 for (Desc
= Ver
.DescriptionList();
155 LastDesc
= &Desc
->NextDesc
, Desc
++)
157 if (MD5SumValue(Desc
.md5()) == CurMd5
)
159 // Add new description
160 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
161 Desc
->ParentPkg
= Pkg
.Index();
163 if (NewFileDesc(Desc
,List
) == false)
164 return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName
.c_str());
173 pkgCache::VerIterator Ver
= Pkg
.VersionList();
174 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
176 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
178 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
183 /* We already have a version for this item, record that we
185 unsigned long Hash
= List
.VersionHash();
186 if (Res
== 0 && Ver
->Hash
== Hash
)
188 if (List
.UsePackage(Pkg
,Ver
) == false)
189 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
190 PackageName
.c_str());
192 if (NewFileVer(Ver
,List
) == false)
193 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
194 PackageName
.c_str());
196 // Read only a single record and return
200 FoundFileDeps
|= List
.HasFileDeps();
207 // Skip to the end of the same version set.
210 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
212 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
219 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
220 Ver
->ParentPkg
= Pkg
.Index();
223 if (List
.NewVersion(Ver
) == false)
224 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
225 PackageName
.c_str());
227 if (List
.UsePackage(Pkg
,Ver
) == false)
228 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
229 PackageName
.c_str());
231 if (NewFileVer(Ver
,List
) == false)
232 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
233 PackageName
.c_str());
235 // Read only a single record and return
239 FoundFileDeps
|= List
.HasFileDeps();
243 /* Record the Description data. Description data always exist in
244 Packages and Translation-* files. */
245 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
246 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
248 // Skip to the end of description set
249 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
251 // Add new description
252 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
253 Desc
->ParentPkg
= Pkg
.Index();
255 if (NewFileDesc(Desc
,List
) == false)
256 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str());
259 FoundFileDeps
|= List
.HasFileDeps();
261 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
262 return _error
->Error(_("Wow, you exceeded the number of package "
263 "names this APT is capable of."));
264 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
265 return _error
->Error(_("Wow, you exceeded the number of versions "
266 "this APT is capable of."));
267 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
268 return _error
->Error(_("Wow, you exceeded the number of descriptions "
269 "this APT is capable of."));
270 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
271 return _error
->Error(_("Wow, you exceeded the number of dependencies "
272 "this APT is capable of."));
276 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
277 // ---------------------------------------------------------------------
278 /* If we found any file depends while parsing the main list we need to
279 resolve them. Since it is undesired to load the entire list of files
280 into the cache as virtual packages we do a two stage effort. MergeList
281 identifies the file depends and this creates Provdies for them by
282 re-parsing all the indexs. */
283 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
287 unsigned int Counter
= 0;
288 while (List
.Step() == true)
290 string PackageName
= List
.Package();
291 if (PackageName
.empty() == true)
293 string Version
= List
.Version();
294 if (Version
.empty() == true)
297 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
298 if (Pkg
.end() == true)
299 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
300 PackageName
.c_str());
302 if (Counter
% 100 == 0 && Progress
!= 0)
303 Progress
->Progress(List
.Offset());
305 unsigned long Hash
= List
.VersionHash();
306 pkgCache::VerIterator Ver
= Pkg
.VersionList();
307 for (; Ver
.end() == false; Ver
++)
309 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
311 if (List
.CollectFileProvides(Cache
,Ver
) == false)
312 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
317 if (Ver
.end() == true)
318 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
324 // CacheGenerator::NewPackage - Add a new package /*{{{*/
325 // ---------------------------------------------------------------------
326 /* This creates a new package structure and adds it to the hash table */
327 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
329 Pkg
= Cache
.FindPkg(Name
);
330 if (Pkg
.end() == false)
334 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
338 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
340 // Insert it into the hash table
341 unsigned long Hash
= Cache
.Hash(Name
);
342 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
343 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
345 // Set the name and the ID
346 Pkg
->Name
= Map
.WriteString(Name
);
349 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
354 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
355 // ---------------------------------------------------------------------
357 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
360 if (CurrentFile
== 0)
364 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
368 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
369 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
371 // Link it to the end of the list
372 map_ptrloc
*Last
= &Ver
->FileList
;
373 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
375 VF
->NextFile
= *Last
;
378 VF
->Offset
= List
.Offset();
379 VF
->Size
= List
.Size();
380 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
381 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
382 Cache
.HeaderP
->VerFileCount
++;
387 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
388 // ---------------------------------------------------------------------
389 /* This puts a version structure in the linked list */
390 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
391 const string
&VerStr
,
395 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
400 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
402 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
403 Ver
->VerStr
= Map
.WriteString(VerStr
);
404 if (Ver
->VerStr
== 0)
410 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
411 // ---------------------------------------------------------------------
413 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
416 if (CurrentFile
== 0)
420 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
424 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
425 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
427 // Link it to the end of the list
428 map_ptrloc
*Last
= &Desc
->FileList
;
429 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
432 DF
->NextFile
= *Last
;
435 DF
->Offset
= List
.Offset();
436 DF
->Size
= List
.Size();
437 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
438 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
439 Cache
.HeaderP
->DescFileCount
++;
444 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
445 // ---------------------------------------------------------------------
446 /* This puts a description structure in the linked list */
447 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
449 const MD5SumValue
&md5sum
,
453 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
454 if (Description
== 0)
458 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
459 Desc
->NextDesc
= Next
;
460 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
461 Desc
->language_code
= Map
.WriteString(Lang
);
462 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
467 // ListParser::NewDepends - Create a dependency element /*{{{*/
468 // ---------------------------------------------------------------------
469 /* This creates a dependency element in the tree. It is linked to the
470 version and to the package that it is pointing to. */
471 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
472 const string
&PackageName
,
473 const string
&Version
,
477 pkgCache
&Cache
= Owner
->Cache
;
480 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
485 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
486 Dep
->ParentVer
= Ver
.Index();
489 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
491 // Locate the target package
492 pkgCache::PkgIterator Pkg
;
493 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
496 // Probe the reverse dependency list for a version string that matches
497 if (Version
.empty() == false)
499 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
500 if (I->Version != 0 && I.TargetVer() == Version)
501 Dep->Version = I->Version;*/
502 if (Dep
->Version
== 0)
503 if ((Dep
->Version
= WriteString(Version
)) == 0)
507 // Link it to the package
508 Dep
->Package
= Pkg
.Index();
509 Dep
->NextRevDepends
= Pkg
->RevDepends
;
510 Pkg
->RevDepends
= Dep
.Index();
512 /* Link it to the version (at the end of the list)
513 Caching the old end point speeds up generation substantially */
514 if (OldDepVer
!= Ver
)
516 OldDepLast
= &Ver
->DependsList
;
517 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
518 OldDepLast
= &D
->NextDepends
;
522 // Is it a file dependency?
523 if (PackageName
[0] == '/')
524 FoundFileDeps
= true;
526 Dep
->NextDepends
= *OldDepLast
;
527 *OldDepLast
= Dep
.Index();
528 OldDepLast
= &Dep
->NextDepends
;
533 // ListParser::NewProvides - Create a Provides element /*{{{*/
534 // ---------------------------------------------------------------------
536 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
537 const string
&PackageName
,
538 const string
&Version
)
540 pkgCache
&Cache
= Owner
->Cache
;
542 // We do not add self referencing provides
543 if (Ver
.ParentPkg().Name() == PackageName
)
547 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
550 Cache
.HeaderP
->ProvidesCount
++;
553 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
554 Prv
->Version
= Ver
.Index();
555 Prv
->NextPkgProv
= Ver
->ProvidesList
;
556 Ver
->ProvidesList
= Prv
.Index();
557 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
560 // Locate the target package
561 pkgCache::PkgIterator Pkg
;
562 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
565 // Link it to the package
566 Prv
->ParentPkg
= Pkg
.Index();
567 Prv
->NextProvides
= Pkg
->ProvidesList
;
568 Pkg
->ProvidesList
= Prv
.Index();
573 // ListParser::NewTag - Create a Tag element /*{{{*/
574 // ---------------------------------------------------------------------
576 bool pkgCacheGenerator::ListParser::NewTag(pkgCache::PkgIterator Pkg
,
577 const char *NameStart
,
578 unsigned int NameSize
)
580 pkgCache
&Cache
= Owner
->Cache
;
583 unsigned long Tagg
= Owner
->Map
.Allocate(sizeof(pkgCache::Tag
));
586 Cache
.HeaderP
->TagCount
++;
589 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ Tagg
);
590 Tg
->Name
= WriteString(NameStart
,NameSize
);
593 Tg
->NextTag
= Pkg
->TagList
;
594 Pkg
->TagList
= Tg
.Index();
599 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
600 // ---------------------------------------------------------------------
601 /* This is used to select which file is to be associated with all newly
602 added versions. The caller is responsible for setting the IMS fields. */
603 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
604 const pkgIndexFile
&Index
,
607 // Get some space for the structure
608 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
609 if (CurrentFile
== Cache
.PkgFileP
)
613 CurrentFile
->FileName
= Map
.WriteString(File
);
614 CurrentFile
->Site
= WriteUniqString(Site
);
615 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
616 CurrentFile
->Flags
= Flags
;
617 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
618 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
620 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
621 Cache
.HeaderP
->PackageFileCount
++;
623 if (CurrentFile
->FileName
== 0)
627 Progress
->SubProgress(Index
.Size());
631 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
632 // ---------------------------------------------------------------------
633 /* This is used to create handles to strings. Given the same text it
634 always returns the same number */
635 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
638 /* We use a very small transient hash table here, this speeds up generation
639 by a fair amount on slower machines */
640 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
642 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
643 return Bucket
->String
;
645 // Search for an insertion point
646 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
648 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
649 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
650 I
= Cache
.StringItemP
+ I
->NextItem
)
652 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
665 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
669 // Fill in the structure
670 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
671 ItemP
->NextItem
= I
- Cache
.StringItemP
;
673 ItemP
->String
= Map
.WriteString(S
,Size
);
674 if (ItemP
->String
== 0)
678 return ItemP
->String
;
682 // CheckValidity - Check that a cache is up-to-date /*{{{*/
683 // ---------------------------------------------------------------------
684 /* This just verifies that each file in the list of index files exists,
685 has matching attributes with the cache and the cache does not have
687 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
688 FileIterator End
,MMap
**OutMap
= 0)
690 // No file, certainly invalid
691 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
695 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
696 SPtr
<MMap
> Map
= new MMap(CacheF
,MMap::Public
| MMap::ReadOnly
);
698 if (_error
->PendingError() == true || Map
->Size() == 0)
704 /* Now we check every index file, see if it is in the cache,
705 verify the IMS data and check that it is on the disk too.. */
706 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
707 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
708 for (; Start
!= End
; Start
++)
710 if ((*Start
)->HasPackages() == false)
713 if ((*Start
)->Exists() == false)
715 #if 0 // mvo: we no longer give a message here (Default Sources spec)
716 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
717 (*Start
)->Describe().c_str());
722 // FindInCache is also expected to do an IMS check.
723 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
724 if (File
.end() == true)
727 Visited
[File
->ID
] = true;
730 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
731 if (Visited
[I
] == false)
734 if (_error
->PendingError() == true)
741 *OutMap
= Map
.UnGuard();
745 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
746 // ---------------------------------------------------------------------
747 /* Size is kind of an abstract notion that is only used for the progress
749 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
751 unsigned long TotalSize
= 0;
752 for (; Start
!= End
; Start
++)
754 if ((*Start
)->HasPackages() == false)
756 TotalSize
+= (*Start
)->Size();
761 // BuildCache - Merge the list of index files into the cache /*{{{*/
762 // ---------------------------------------------------------------------
764 static bool BuildCache(pkgCacheGenerator
&Gen
,
765 OpProgress
&Progress
,
766 unsigned long &CurrentSize
,unsigned long TotalSize
,
767 FileIterator Start
, FileIterator End
)
770 for (I
= Start
; I
!= End
; I
++)
772 if ((*I
)->HasPackages() == false)
775 if ((*I
)->Exists() == false)
778 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
780 _error
->Warning("Duplicate sources.list entry %s",
781 (*I
)->Describe().c_str());
785 unsigned long Size
= (*I
)->Size();
786 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
789 if ((*I
)->Merge(Gen
,Progress
) == false)
793 if (Gen
.HasFileDeps() == true)
796 TotalSize
= ComputeSize(Start
, End
);
798 for (I
= Start
; I
!= End
; I
++)
800 unsigned long Size
= (*I
)->Size();
801 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
803 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
811 // MakeStatusCache - Construct the status cache /*{{{*/
812 // ---------------------------------------------------------------------
813 /* This makes sure that the status cache (the cache that has all
814 index files from the sources list and all local ones) is ready
815 to be mmaped. If OutMap is not zero then a MMap object representing
816 the cache will be stored there. This is pretty much mandetory if you
817 are using AllowMem. AllowMem lets the function be run as non-root
818 where it builds the cache 'fast' into a memory buffer. */
819 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
820 MMap
**OutMap
,bool AllowMem
)
822 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
824 vector
<pkgIndexFile
*> Files
;
825 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
829 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
830 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
833 Files
.push_back (*j
);
836 unsigned long EndOfSource
= Files
.size();
837 if (_system
->AddStatusFiles(Files
) == false)
840 // Decide if we can write to the files..
841 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
842 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
844 // Decide if we can write to the cache
845 bool Writeable
= false;
846 if (CacheFile
.empty() == false)
847 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
849 if (SrcCacheFile
.empty() == false)
850 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
852 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
853 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
855 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
858 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
860 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
864 /* At this point we know we need to reconstruct the package cache,
867 SPtr
<DynamicMMap
> Map
;
868 if (Writeable
== true && CacheFile
.empty() == false)
870 unlink(CacheFile
.c_str());
871 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
872 fchmod(CacheF
->Fd(),0644);
873 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
874 if (_error
->PendingError() == true)
879 // Just build it in memory..
880 Map
= new DynamicMMap(MMap::Public
,MapSize
);
883 // Lets try the source cache.
884 unsigned long CurrentSize
= 0;
885 unsigned long TotalSize
= 0;
886 if (CheckValidity(SrcCacheFile
,Files
.begin(),
887 Files
.begin()+EndOfSource
) == true)
889 // Preload the map with the source cache
890 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
891 if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()),
892 SCacheF
.Size()) == false)
895 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
897 // Build the status cache
898 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
899 if (_error
->PendingError() == true)
901 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
902 Files
.begin()+EndOfSource
,Files
.end()) == false)
907 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
909 // Build the source cache
910 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
911 if (_error
->PendingError() == true)
913 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
914 Files
.begin(),Files
.begin()+EndOfSource
) == false)
918 if (Writeable
== true && SrcCacheFile
.empty() == false)
920 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
921 if (_error
->PendingError() == true)
924 fchmod(SCacheF
.Fd(),0644);
926 // Write out the main data
927 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
928 return _error
->Error(_("IO Error saving source cache"));
931 // Write out the proper header
932 Gen
.GetCache().HeaderP
->Dirty
= false;
933 if (SCacheF
.Seek(0) == false ||
934 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
935 return _error
->Error(_("IO Error saving source cache"));
936 Gen
.GetCache().HeaderP
->Dirty
= true;
940 // Build the status cache
941 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
942 Files
.begin()+EndOfSource
,Files
.end()) == false)
946 if (_error
->PendingError() == true)
952 delete Map
.UnGuard();
953 *OutMap
= new MMap(*CacheF
,MMap::Public
| MMap::ReadOnly
);
957 *OutMap
= Map
.UnGuard();
964 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
965 // ---------------------------------------------------------------------
967 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
969 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
970 vector
<pkgIndexFile
*> Files
;
971 unsigned long EndOfSource
= Files
.size();
972 if (_system
->AddStatusFiles(Files
) == false)
975 SPtr
<DynamicMMap
> Map
;
976 Map
= new DynamicMMap(MMap::Public
,MapSize
);
977 unsigned long CurrentSize
= 0;
978 unsigned long TotalSize
= 0;
980 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
982 // Build the status cache
983 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
984 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
985 if (_error
->PendingError() == true)
987 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
988 Files
.begin()+EndOfSource
,Files
.end()) == false)
991 if (_error
->PendingError() == true)
993 *OutMap
= Map
.UnGuard();