]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
75a0e34f076d8f5dbb23d468cdd0fddd5a1020d1
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>
24 #include <apt-pkg/macros.h>
26 #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 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
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
;
144 bool duplicate
=false;
146 // don't add a new description if we have one for the given
148 for ( ; Desc
.end() == false; Desc
++)
149 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
150 Desc
.LanguageCode() == List
.DescriptionLanguage())
155 for (Desc
= Ver
.DescriptionList();
157 LastDesc
= &Desc
->NextDesc
, Desc
++)
159 if (MD5SumValue(Desc
.md5()) == CurMd5
)
161 // Add new description
162 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
163 Desc
->ParentPkg
= Pkg
.Index();
165 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
166 return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName
.c_str());
175 pkgCache::VerIterator Ver
= Pkg
.VersionList();
176 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
178 unsigned long const Hash
= List
.VersionHash();
179 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
181 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
182 // Version is higher as current version - insert here
185 // Versionstrings are equal - is hash also equal?
186 if (Res
== 0 && Ver
->Hash
== Hash
)
188 // proceed with the next till we have either the right
189 // or we found another version (which will be lower)
192 /* We already have a version for this item, record that we saw it */
195 if (List
.UsePackage(Pkg
,Ver
) == false)
196 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
197 PackageName
.c_str());
199 if (NewFileVer(Ver
,List
) == false)
200 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
201 PackageName
.c_str());
203 // Read only a single record and return
207 FoundFileDeps
|= List
.HasFileDeps();
215 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
216 Ver
->ParentPkg
= Pkg
.Index();
219 if ((*LastVer
== 0 && _error
->PendingError()) || List
.NewVersion(Ver
) == false)
220 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
221 PackageName
.c_str());
223 if (List
.UsePackage(Pkg
,Ver
) == false)
224 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
225 PackageName
.c_str());
227 if (NewFileVer(Ver
,List
) == false)
228 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
229 PackageName
.c_str());
231 // Read only a single record and return
235 FoundFileDeps
|= List
.HasFileDeps();
239 /* Record the Description data. Description data always exist in
240 Packages and Translation-* files. */
241 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
242 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
244 // Skip to the end of description set
245 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
247 // Add new description
248 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
249 Desc
->ParentPkg
= Pkg
.Index();
251 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
252 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str());
255 FoundFileDeps
|= List
.HasFileDeps();
257 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
258 return _error
->Error(_("Wow, you exceeded the number of package "
259 "names this APT is capable of."));
260 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
261 return _error
->Error(_("Wow, you exceeded the number of versions "
262 "this APT is capable of."));
263 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
264 return _error
->Error(_("Wow, you exceeded the number of descriptions "
265 "this APT is capable of."));
266 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
267 return _error
->Error(_("Wow, you exceeded the number of dependencies "
268 "this APT is capable of."));
272 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
273 // ---------------------------------------------------------------------
274 /* If we found any file depends while parsing the main list we need to
275 resolve them. Since it is undesired to load the entire list of files
276 into the cache as virtual packages we do a two stage effort. MergeList
277 identifies the file depends and this creates Provdies for them by
278 re-parsing all the indexs. */
279 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
283 unsigned int Counter
= 0;
284 while (List
.Step() == true)
286 string PackageName
= List
.Package();
287 if (PackageName
.empty() == true)
289 string Version
= List
.Version();
290 if (Version
.empty() == true)
293 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
294 if (Pkg
.end() == true)
295 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
296 PackageName
.c_str());
298 if (Counter
% 100 == 0 && Progress
!= 0)
299 Progress
->Progress(List
.Offset());
301 unsigned long Hash
= List
.VersionHash();
302 pkgCache::VerIterator Ver
= Pkg
.VersionList();
303 for (; Ver
.end() == false; Ver
++)
305 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
307 if (List
.CollectFileProvides(Cache
,Ver
) == false)
308 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
313 if (Ver
.end() == true)
314 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
320 // CacheGenerator::NewPackage - Add a new package /*{{{*/
321 // ---------------------------------------------------------------------
322 /* This creates a new package structure and adds it to the hash table */
323 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
325 Pkg
= Cache
.FindPkg(Name
);
326 if (Pkg
.end() == false)
330 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
334 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
336 // Insert it into the hash table
337 unsigned long Hash
= Cache
.Hash(Name
);
338 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
339 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
341 // Set the name and the ID
342 Pkg
->Name
= Map
.WriteString(Name
);
345 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
350 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
351 // ---------------------------------------------------------------------
353 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
356 if (CurrentFile
== 0)
360 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
364 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
365 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
367 // Link it to the end of the list
368 map_ptrloc
*Last
= &Ver
->FileList
;
369 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
371 VF
->NextFile
= *Last
;
374 VF
->Offset
= List
.Offset();
375 VF
->Size
= List
.Size();
376 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
377 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
378 Cache
.HeaderP
->VerFileCount
++;
383 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
384 // ---------------------------------------------------------------------
385 /* This puts a version structure in the linked list */
386 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
387 const string
&VerStr
,
391 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
396 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
398 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
399 Ver
->VerStr
= Map
.WriteString(VerStr
);
400 if (Ver
->VerStr
== 0)
406 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
407 // ---------------------------------------------------------------------
409 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
412 if (CurrentFile
== 0)
416 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
420 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
421 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
423 // Link it to the end of the list
424 map_ptrloc
*Last
= &Desc
->FileList
;
425 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
428 DF
->NextFile
= *Last
;
431 DF
->Offset
= List
.Offset();
432 DF
->Size
= List
.Size();
433 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
434 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
435 Cache
.HeaderP
->DescFileCount
++;
440 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
441 // ---------------------------------------------------------------------
442 /* This puts a description structure in the linked list */
443 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
445 const MD5SumValue
&md5sum
,
449 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
450 if (Description
== 0)
454 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
455 Desc
->NextDesc
= Next
;
456 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
457 Desc
->language_code
= Map
.WriteString(Lang
);
458 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
459 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
465 // ListParser::NewDepends - Create a dependency element /*{{{*/
466 // ---------------------------------------------------------------------
467 /* This creates a dependency element in the tree. It is linked to the
468 version and to the package that it is pointing to. */
469 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
470 const string
&PackageName
,
471 const string
&Version
,
475 pkgCache
&Cache
= Owner
->Cache
;
478 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
483 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
484 Dep
->ParentVer
= Ver
.Index();
487 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
489 // Locate the target package
490 pkgCache::PkgIterator Pkg
;
491 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
494 // Probe the reverse dependency list for a version string that matches
495 if (Version
.empty() == false)
497 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
498 if (I->Version != 0 && I.TargetVer() == Version)
499 Dep->Version = I->Version;*/
500 if (Dep
->Version
== 0)
501 if ((Dep
->Version
= WriteString(Version
)) == 0)
505 // Link it to the package
506 Dep
->Package
= Pkg
.Index();
507 Dep
->NextRevDepends
= Pkg
->RevDepends
;
508 Pkg
->RevDepends
= Dep
.Index();
510 /* Link it to the version (at the end of the list)
511 Caching the old end point speeds up generation substantially */
512 if (OldDepVer
!= Ver
)
514 OldDepLast
= &Ver
->DependsList
;
515 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
516 OldDepLast
= &D
->NextDepends
;
520 // Is it a file dependency?
521 if (PackageName
[0] == '/')
522 FoundFileDeps
= true;
524 Dep
->NextDepends
= *OldDepLast
;
525 *OldDepLast
= Dep
.Index();
526 OldDepLast
= &Dep
->NextDepends
;
531 // ListParser::NewProvides - Create a Provides element /*{{{*/
532 // ---------------------------------------------------------------------
534 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
535 const string
&PackageName
,
536 const string
&Version
)
538 pkgCache
&Cache
= Owner
->Cache
;
540 // We do not add self referencing provides
541 if (Ver
.ParentPkg().Name() == PackageName
)
545 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
548 Cache
.HeaderP
->ProvidesCount
++;
551 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
552 Prv
->Version
= Ver
.Index();
553 Prv
->NextPkgProv
= Ver
->ProvidesList
;
554 Ver
->ProvidesList
= Prv
.Index();
555 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
558 // Locate the target package
559 pkgCache::PkgIterator Pkg
;
560 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
563 // Link it to the package
564 Prv
->ParentPkg
= Pkg
.Index();
565 Prv
->NextProvides
= Pkg
->ProvidesList
;
566 Pkg
->ProvidesList
= Prv
.Index();
571 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
572 // ---------------------------------------------------------------------
573 /* This is used to select which file is to be associated with all newly
574 added versions. The caller is responsible for setting the IMS fields. */
575 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
576 const pkgIndexFile
&Index
,
579 // Get some space for the structure
580 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
581 if (CurrentFile
== Cache
.PkgFileP
)
585 CurrentFile
->FileName
= Map
.WriteString(File
);
586 CurrentFile
->Site
= WriteUniqString(Site
);
587 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
588 CurrentFile
->Flags
= Flags
;
589 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
590 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
592 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
593 Cache
.HeaderP
->PackageFileCount
++;
595 if (CurrentFile
->FileName
== 0)
599 Progress
->SubProgress(Index
.Size());
603 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
604 // ---------------------------------------------------------------------
605 /* This is used to create handles to strings. Given the same text it
606 always returns the same number */
607 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
610 /* We use a very small transient hash table here, this speeds up generation
611 by a fair amount on slower machines */
612 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
614 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
615 return Bucket
->String
;
617 // Search for an insertion point
618 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
620 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
621 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
622 I
= Cache
.StringItemP
+ I
->NextItem
)
624 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
637 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
641 // Fill in the structure
642 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
643 ItemP
->NextItem
= I
- Cache
.StringItemP
;
645 ItemP
->String
= Map
.WriteString(S
,Size
);
646 if (ItemP
->String
== 0)
650 return ItemP
->String
;
653 // CheckValidity - Check that a cache is up-to-date /*{{{*/
654 // ---------------------------------------------------------------------
655 /* This just verifies that each file in the list of index files exists,
656 has matching attributes with the cache and the cache does not have
658 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
659 FileIterator End
,MMap
**OutMap
= 0)
661 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
662 // No file, certainly invalid
663 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
666 std::clog
<< "CacheFile doesn't exist" << std::endl
;
671 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
672 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
674 if (_error
->PendingError() == true || Map
->Size() == 0)
677 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
682 /* Now we check every index file, see if it is in the cache,
683 verify the IMS data and check that it is on the disk too.. */
684 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
685 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
686 for (; Start
!= End
; Start
++)
689 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
690 if ((*Start
)->HasPackages() == false)
693 std::clog
<< "Has NO packages" << std::endl
;
697 if ((*Start
)->Exists() == false)
699 #if 0 // mvo: we no longer give a message here (Default Sources spec)
700 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
701 (*Start
)->Describe().c_str());
704 std::clog
<< "file doesn't exist" << std::endl
;
708 // FindInCache is also expected to do an IMS check.
709 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
710 if (File
.end() == true)
713 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
717 Visited
[File
->ID
] = true;
719 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
722 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
723 if (Visited
[I
] == false)
726 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
730 if (_error
->PendingError() == true)
734 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
735 _error
->DumpErrors();
742 *OutMap
= Map
.UnGuard();
746 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
747 // ---------------------------------------------------------------------
748 /* Size is kind of an abstract notion that is only used for the progress
750 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
752 unsigned long TotalSize
= 0;
753 for (; Start
!= End
; Start
++)
755 if ((*Start
)->HasPackages() == false)
757 TotalSize
+= (*Start
)->Size();
762 // BuildCache - Merge the list of index files into the cache /*{{{*/
763 // ---------------------------------------------------------------------
765 static bool BuildCache(pkgCacheGenerator
&Gen
,
766 OpProgress
&Progress
,
767 unsigned long &CurrentSize
,unsigned long TotalSize
,
768 FileIterator Start
, FileIterator End
)
771 for (I
= Start
; I
!= End
; I
++)
773 if ((*I
)->HasPackages() == false)
776 if ((*I
)->Exists() == false)
779 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
781 _error
->Warning("Duplicate sources.list entry %s",
782 (*I
)->Describe().c_str());
786 unsigned long Size
= (*I
)->Size();
787 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
790 if ((*I
)->Merge(Gen
,Progress
) == false)
794 if (Gen
.HasFileDeps() == true)
797 TotalSize
= ComputeSize(Start
, End
);
799 for (I
= Start
; I
!= End
; I
++)
801 unsigned long Size
= (*I
)->Size();
802 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
804 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
812 // MakeStatusCache - Construct the status cache /*{{{*/
813 // ---------------------------------------------------------------------
814 /* This makes sure that the status cache (the cache that has all
815 index files from the sources list and all local ones) is ready
816 to be mmaped. If OutMap is not zero then a MMap object representing
817 the cache will be stored there. This is pretty much mandetory if you
818 are using AllowMem. AllowMem lets the function be run as non-root
819 where it builds the cache 'fast' into a memory buffer. */
820 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
821 MMap
**OutMap
,bool AllowMem
)
823 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
824 unsigned long const MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
826 vector
<pkgIndexFile
*> Files
;
827 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
831 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
832 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
835 Files
.push_back (*j
);
838 unsigned long const EndOfSource
= Files
.size();
839 if (_system
->AddStatusFiles(Files
) == false)
842 // Decide if we can write to the files..
843 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
844 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
846 // Decide if we can write to the cache
847 bool Writeable
= false;
848 if (CacheFile
.empty() == false)
849 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
851 if (SrcCacheFile
.empty() == false)
852 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
854 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
856 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
857 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
859 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
862 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
864 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
866 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
869 else if (Debug
== true)
870 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
872 /* At this point we know we need to reconstruct the package cache,
875 SPtr
<DynamicMMap
> Map
;
876 if (Writeable
== true && CacheFile
.empty() == false)
878 unlink(CacheFile
.c_str());
879 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
880 fchmod(CacheF
->Fd(),0644);
881 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
882 if (_error
->PendingError() == true)
885 std::clog
<< "Open filebased MMap" << std::endl
;
889 // Just build it in memory..
890 Map
= new DynamicMMap(0,MapSize
);
892 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
895 // Lets try the source cache.
896 unsigned long CurrentSize
= 0;
897 unsigned long TotalSize
= 0;
898 if (CheckValidity(SrcCacheFile
,Files
.begin(),
899 Files
.begin()+EndOfSource
) == true)
902 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
903 // Preload the map with the source cache
904 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
905 unsigned long const alloc
= Map
->RawAllocate(SCacheF
.Size());
906 if ((alloc
== 0 && _error
->PendingError())
907 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
908 SCacheF
.Size()) == false)
911 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
913 // Build the status cache
914 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
915 if (_error
->PendingError() == true)
917 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
918 Files
.begin()+EndOfSource
,Files
.end()) == false)
924 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
925 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
927 // Build the source cache
928 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
929 if (_error
->PendingError() == true)
931 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
932 Files
.begin(),Files
.begin()+EndOfSource
) == false)
936 if (Writeable
== true && SrcCacheFile
.empty() == false)
938 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
939 if (_error
->PendingError() == true)
942 fchmod(SCacheF
.Fd(),0644);
944 // Write out the main data
945 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
946 return _error
->Error(_("IO Error saving source cache"));
949 // Write out the proper header
950 Gen
.GetCache().HeaderP
->Dirty
= false;
951 if (SCacheF
.Seek(0) == false ||
952 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
953 return _error
->Error(_("IO Error saving source cache"));
954 Gen
.GetCache().HeaderP
->Dirty
= true;
958 // Build the status cache
959 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
960 Files
.begin()+EndOfSource
,Files
.end()) == false)
964 std::clog
<< "Caches are ready for shipping" << std::endl
;
966 if (_error
->PendingError() == true)
972 delete Map
.UnGuard();
973 *OutMap
= new MMap(*CacheF
,0);
977 *OutMap
= Map
.UnGuard();
984 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
985 // ---------------------------------------------------------------------
987 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
989 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
990 vector
<pkgIndexFile
*> Files
;
991 unsigned long EndOfSource
= Files
.size();
992 if (_system
->AddStatusFiles(Files
) == false)
995 SPtr
<DynamicMMap
> Map
= new DynamicMMap(0,MapSize
);
996 unsigned long CurrentSize
= 0;
997 unsigned long TotalSize
= 0;
999 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1001 // Build the status cache
1002 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
1003 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1004 if (_error
->PendingError() == true)
1006 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1007 Files
.begin()+EndOfSource
,Files
.end()) == false)
1010 if (_error
->PendingError() == true)
1012 *OutMap
= Map
.UnGuard();