]>
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 /*{{{*/
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 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
180 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
185 /* We already have a version for this item, record that we
187 unsigned long Hash
= List
.VersionHash();
188 if (Res
== 0 && Ver
->Hash
== Hash
)
190 if (List
.UsePackage(Pkg
,Ver
) == false)
191 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
192 PackageName
.c_str());
194 if (NewFileVer(Ver
,List
) == false)
195 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
196 PackageName
.c_str());
198 // Read only a single record and return
202 FoundFileDeps
|= List
.HasFileDeps();
209 // Skip to the end of the same version set.
212 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
214 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
221 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
222 Ver
->ParentPkg
= Pkg
.Index();
225 if ((*LastVer
== 0 && _error
->PendingError()) || List
.NewVersion(Ver
) == false)
226 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
227 PackageName
.c_str());
229 if (List
.UsePackage(Pkg
,Ver
) == false)
230 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
231 PackageName
.c_str());
233 if (NewFileVer(Ver
,List
) == false)
234 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
235 PackageName
.c_str());
237 // Read only a single record and return
241 FoundFileDeps
|= List
.HasFileDeps();
245 /* Record the Description data. Description data always exist in
246 Packages and Translation-* files. */
247 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
248 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
250 // Skip to the end of description set
251 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
253 // Add new description
254 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
255 Desc
->ParentPkg
= Pkg
.Index();
257 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
258 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str());
261 FoundFileDeps
|= List
.HasFileDeps();
263 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
264 return _error
->Error(_("Wow, you exceeded the number of package "
265 "names this APT is capable of."));
266 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
267 return _error
->Error(_("Wow, you exceeded the number of versions "
268 "this APT is capable of."));
269 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
270 return _error
->Error(_("Wow, you exceeded the number of descriptions "
271 "this APT is capable of."));
272 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
273 return _error
->Error(_("Wow, you exceeded the number of dependencies "
274 "this APT is capable of."));
278 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
279 // ---------------------------------------------------------------------
280 /* If we found any file depends while parsing the main list we need to
281 resolve them. Since it is undesired to load the entire list of files
282 into the cache as virtual packages we do a two stage effort. MergeList
283 identifies the file depends and this creates Provdies for them by
284 re-parsing all the indexs. */
285 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
289 unsigned int Counter
= 0;
290 while (List
.Step() == true)
292 string PackageName
= List
.Package();
293 if (PackageName
.empty() == true)
295 string Version
= List
.Version();
296 if (Version
.empty() == true)
299 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
300 if (Pkg
.end() == true)
301 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
302 PackageName
.c_str());
304 if (Counter
% 100 == 0 && Progress
!= 0)
305 Progress
->Progress(List
.Offset());
307 unsigned long Hash
= List
.VersionHash();
308 pkgCache::VerIterator Ver
= Pkg
.VersionList();
309 for (; Ver
.end() == false; Ver
++)
311 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
313 if (List
.CollectFileProvides(Cache
,Ver
) == false)
314 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
319 if (Ver
.end() == true)
320 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
326 // CacheGenerator::NewPackage - Add a new package /*{{{*/
327 // ---------------------------------------------------------------------
328 /* This creates a new package structure and adds it to the hash table */
329 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
331 Pkg
= Cache
.FindPkg(Name
);
332 if (Pkg
.end() == false)
336 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
340 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
342 // Insert it into the hash table
343 unsigned long Hash
= Cache
.Hash(Name
);
344 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
345 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
347 // Set the name and the ID
348 Pkg
->Name
= Map
.WriteString(Name
);
351 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
356 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
357 // ---------------------------------------------------------------------
359 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
362 if (CurrentFile
== 0)
366 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
370 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
371 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
373 // Link it to the end of the list
374 map_ptrloc
*Last
= &Ver
->FileList
;
375 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
377 VF
->NextFile
= *Last
;
380 VF
->Offset
= List
.Offset();
381 VF
->Size
= List
.Size();
382 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
383 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
384 Cache
.HeaderP
->VerFileCount
++;
389 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
390 // ---------------------------------------------------------------------
391 /* This puts a version structure in the linked list */
392 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
393 const string
&VerStr
,
397 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
402 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
404 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
405 Ver
->VerStr
= Map
.WriteString(VerStr
);
406 if (Ver
->VerStr
== 0)
412 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
413 // ---------------------------------------------------------------------
415 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
418 if (CurrentFile
== 0)
422 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
426 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
427 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
429 // Link it to the end of the list
430 map_ptrloc
*Last
= &Desc
->FileList
;
431 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
434 DF
->NextFile
= *Last
;
437 DF
->Offset
= List
.Offset();
438 DF
->Size
= List
.Size();
439 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
440 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
441 Cache
.HeaderP
->DescFileCount
++;
446 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
447 // ---------------------------------------------------------------------
448 /* This puts a description structure in the linked list */
449 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
451 const MD5SumValue
&md5sum
,
455 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
456 if (Description
== 0)
460 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
461 Desc
->NextDesc
= Next
;
462 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
463 Desc
->language_code
= Map
.WriteString(Lang
);
464 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
465 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
471 // ListParser::NewDepends - Create a dependency element /*{{{*/
472 // ---------------------------------------------------------------------
473 /* This creates a dependency element in the tree. It is linked to the
474 version and to the package that it is pointing to. */
475 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
476 const string
&PackageName
,
477 const string
&Version
,
481 pkgCache
&Cache
= Owner
->Cache
;
484 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
489 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
490 Dep
->ParentVer
= Ver
.Index();
493 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
495 // Locate the target package
496 pkgCache::PkgIterator Pkg
;
497 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
500 // Probe the reverse dependency list for a version string that matches
501 if (Version
.empty() == false)
503 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
504 if (I->Version != 0 && I.TargetVer() == Version)
505 Dep->Version = I->Version;*/
506 if (Dep
->Version
== 0)
507 if ((Dep
->Version
= WriteString(Version
)) == 0)
511 // Link it to the package
512 Dep
->Package
= Pkg
.Index();
513 Dep
->NextRevDepends
= Pkg
->RevDepends
;
514 Pkg
->RevDepends
= Dep
.Index();
516 /* Link it to the version (at the end of the list)
517 Caching the old end point speeds up generation substantially */
518 if (OldDepVer
!= Ver
)
520 OldDepLast
= &Ver
->DependsList
;
521 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
522 OldDepLast
= &D
->NextDepends
;
526 // Is it a file dependency?
527 if (PackageName
[0] == '/')
528 FoundFileDeps
= true;
530 Dep
->NextDepends
= *OldDepLast
;
531 *OldDepLast
= Dep
.Index();
532 OldDepLast
= &Dep
->NextDepends
;
537 // ListParser::NewProvides - Create a Provides element /*{{{*/
538 // ---------------------------------------------------------------------
540 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
541 const string
&PackageName
,
542 const string
&Version
)
544 pkgCache
&Cache
= Owner
->Cache
;
546 // We do not add self referencing provides
547 if (Ver
.ParentPkg().Name() == PackageName
)
551 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
554 Cache
.HeaderP
->ProvidesCount
++;
557 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
558 Prv
->Version
= Ver
.Index();
559 Prv
->NextPkgProv
= Ver
->ProvidesList
;
560 Ver
->ProvidesList
= Prv
.Index();
561 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
564 // Locate the target package
565 pkgCache::PkgIterator Pkg
;
566 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
569 // Link it to the package
570 Prv
->ParentPkg
= Pkg
.Index();
571 Prv
->NextProvides
= Pkg
->ProvidesList
;
572 Pkg
->ProvidesList
= Prv
.Index();
577 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
578 // ---------------------------------------------------------------------
579 /* This is used to select which file is to be associated with all newly
580 added versions. The caller is responsible for setting the IMS fields. */
581 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
582 const pkgIndexFile
&Index
,
585 // Get some space for the structure
586 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
587 if (CurrentFile
== Cache
.PkgFileP
)
591 CurrentFile
->FileName
= Map
.WriteString(File
);
592 CurrentFile
->Site
= WriteUniqString(Site
);
593 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
594 CurrentFile
->Flags
= Flags
;
595 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
596 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
598 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
599 Cache
.HeaderP
->PackageFileCount
++;
601 if (CurrentFile
->FileName
== 0)
605 Progress
->SubProgress(Index
.Size());
609 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
610 // ---------------------------------------------------------------------
611 /* This is used to create handles to strings. Given the same text it
612 always returns the same number */
613 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
616 /* We use a very small transient hash table here, this speeds up generation
617 by a fair amount on slower machines */
618 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
620 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
621 return Bucket
->String
;
623 // Search for an insertion point
624 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
626 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
627 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
628 I
= Cache
.StringItemP
+ I
->NextItem
)
630 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
643 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
647 // Fill in the structure
648 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
649 ItemP
->NextItem
= I
- Cache
.StringItemP
;
651 ItemP
->String
= Map
.WriteString(S
,Size
);
652 if (ItemP
->String
== 0)
656 return ItemP
->String
;
659 // CheckValidity - Check that a cache is up-to-date /*{{{*/
660 // ---------------------------------------------------------------------
661 /* This just verifies that each file in the list of index files exists,
662 has matching attributes with the cache and the cache does not have
664 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
665 FileIterator End
,MMap
**OutMap
= 0)
667 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
668 // No file, certainly invalid
669 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
672 std::clog
<< "CacheFile doesn't exist" << std::endl
;
677 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
678 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
680 if (_error
->PendingError() == true || Map
->Size() == 0)
683 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
688 /* Now we check every index file, see if it is in the cache,
689 verify the IMS data and check that it is on the disk too.. */
690 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
691 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
692 for (; Start
!= End
; Start
++)
695 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
696 if ((*Start
)->HasPackages() == false)
699 std::clog
<< "Has NO packages" << std::endl
;
703 if ((*Start
)->Exists() == false)
705 #if 0 // mvo: we no longer give a message here (Default Sources spec)
706 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
707 (*Start
)->Describe().c_str());
710 std::clog
<< "file doesn't exist" << std::endl
;
714 // FindInCache is also expected to do an IMS check.
715 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
716 if (File
.end() == true)
719 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
723 Visited
[File
->ID
] = true;
725 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
728 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
729 if (Visited
[I
] == false)
732 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
736 if (_error
->PendingError() == true)
740 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
741 _error
->DumpErrors();
748 *OutMap
= Map
.UnGuard();
752 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
753 // ---------------------------------------------------------------------
754 /* Size is kind of an abstract notion that is only used for the progress
756 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
758 unsigned long TotalSize
= 0;
759 for (; Start
!= End
; Start
++)
761 if ((*Start
)->HasPackages() == false)
763 TotalSize
+= (*Start
)->Size();
768 // BuildCache - Merge the list of index files into the cache /*{{{*/
769 // ---------------------------------------------------------------------
771 static bool BuildCache(pkgCacheGenerator
&Gen
,
772 OpProgress
&Progress
,
773 unsigned long &CurrentSize
,unsigned long TotalSize
,
774 FileIterator Start
, FileIterator End
)
777 for (I
= Start
; I
!= End
; I
++)
779 if ((*I
)->HasPackages() == false)
782 if ((*I
)->Exists() == false)
785 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
787 _error
->Warning("Duplicate sources.list entry %s",
788 (*I
)->Describe().c_str());
792 unsigned long Size
= (*I
)->Size();
793 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
796 if ((*I
)->Merge(Gen
,Progress
) == false)
800 if (Gen
.HasFileDeps() == true)
803 TotalSize
= ComputeSize(Start
, End
);
805 for (I
= Start
; I
!= End
; I
++)
807 unsigned long Size
= (*I
)->Size();
808 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
810 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
818 // MakeStatusCache - Construct the status cache /*{{{*/
819 // ---------------------------------------------------------------------
820 /* This makes sure that the status cache (the cache that has all
821 index files from the sources list and all local ones) is ready
822 to be mmaped. If OutMap is not zero then a MMap object representing
823 the cache will be stored there. This is pretty much mandetory if you
824 are using AllowMem. AllowMem lets the function be run as non-root
825 where it builds the cache 'fast' into a memory buffer. */
826 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
827 MMap
**OutMap
,bool AllowMem
)
829 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
830 unsigned long const MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
832 vector
<pkgIndexFile
*> Files
;
833 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
837 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
838 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
841 Files
.push_back (*j
);
844 unsigned long const EndOfSource
= Files
.size();
845 if (_system
->AddStatusFiles(Files
) == false)
848 // Decide if we can write to the files..
849 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
850 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
852 // Decide if we can write to the cache
853 bool Writeable
= false;
854 if (CacheFile
.empty() == false)
855 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
857 if (SrcCacheFile
.empty() == false)
858 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
860 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
862 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
863 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
865 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
868 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
870 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
872 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
875 else if (Debug
== true)
876 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
878 /* At this point we know we need to reconstruct the package cache,
881 SPtr
<DynamicMMap
> Map
;
882 if (Writeable
== true && CacheFile
.empty() == false)
884 unlink(CacheFile
.c_str());
885 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
886 fchmod(CacheF
->Fd(),0644);
887 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
888 if (_error
->PendingError() == true)
891 std::clog
<< "Open filebased MMap" << std::endl
;
895 // Just build it in memory..
896 Map
= new DynamicMMap(0,MapSize
);
898 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
901 // Lets try the source cache.
902 unsigned long CurrentSize
= 0;
903 unsigned long TotalSize
= 0;
904 if (CheckValidity(SrcCacheFile
,Files
.begin(),
905 Files
.begin()+EndOfSource
) == true)
908 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
909 // Preload the map with the source cache
910 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
911 unsigned long const alloc
= Map
->RawAllocate(SCacheF
.Size());
912 if ((alloc
== 0 && _error
->PendingError())
913 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
914 SCacheF
.Size()) == false)
917 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
919 // Build the status cache
920 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
921 if (_error
->PendingError() == true)
923 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
924 Files
.begin()+EndOfSource
,Files
.end()) == false)
930 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
931 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
933 // Build the source cache
934 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
935 if (_error
->PendingError() == true)
937 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
938 Files
.begin(),Files
.begin()+EndOfSource
) == false)
942 if (Writeable
== true && SrcCacheFile
.empty() == false)
944 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
945 if (_error
->PendingError() == true)
948 fchmod(SCacheF
.Fd(),0644);
950 // Write out the main data
951 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
952 return _error
->Error(_("IO Error saving source cache"));
955 // Write out the proper header
956 Gen
.GetCache().HeaderP
->Dirty
= false;
957 if (SCacheF
.Seek(0) == false ||
958 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
959 return _error
->Error(_("IO Error saving source cache"));
960 Gen
.GetCache().HeaderP
->Dirty
= true;
964 // Build the status cache
965 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
966 Files
.begin()+EndOfSource
,Files
.end()) == false)
970 std::clog
<< "Caches are ready for shipping" << std::endl
;
972 if (_error
->PendingError() == true)
978 delete Map
.UnGuard();
979 *OutMap
= new MMap(*CacheF
,0);
983 *OutMap
= Map
.UnGuard();
990 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
991 // ---------------------------------------------------------------------
993 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
995 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
996 vector
<pkgIndexFile
*> Files
;
997 unsigned long EndOfSource
= Files
.size();
998 if (_system
->AddStatusFiles(Files
) == false)
1001 SPtr
<DynamicMMap
> Map
= new DynamicMMap(0,MapSize
);
1002 unsigned long CurrentSize
= 0;
1003 unsigned long TotalSize
= 0;
1005 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1007 // Build the status cache
1008 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
1009 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1010 if (_error
->PendingError() == true)
1012 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1013 Files
.begin()+EndOfSource
,Files
.end()) == false)
1016 if (_error
->PendingError() == true)
1018 *OutMap
= Map
.UnGuard();