]>
git.saurik.com Git - apt-legacy.git/blob - apt-pkg/pkgcachegen.cc
4ee8cd64af60892e53da3a2ac12397ea032f11b7
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
;
38 uint32_t hashlittle( const void *key
, size_t length
, uint32_t initval
);
40 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
41 // ---------------------------------------------------------------------
42 /* We set the diry flag and make sure that is written to the disk */
43 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
44 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
48 memset(UniqHash
,0,sizeof(UniqHash
));
50 if (_error
->PendingError() == true)
55 // Setup the map interface..
56 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
57 if (Map
.RawAllocate(sizeof(pkgCache::Header
)) == 0 && _error
->PendingError() == true)
60 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
63 *Cache
.HeaderP
= pkgCache::Header();
64 Cache
.HeaderP
->VerSysName
= Map
.WriteString(_system
->VS
->Label
);
65 Cache
.HeaderP
->Architecture
= Map
.WriteString(_config
->Find("APT::Architecture"));
70 // Map directly from the existing file
72 Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0]));
73 if (Cache
.VS
!= _system
->VS
)
75 _error
->Error(_("Cache has an incompatible versioning system"));
80 Cache
.HeaderP
->Dirty
= true;
81 Map
.Sync(0,sizeof(pkgCache::Header
));
84 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
85 // ---------------------------------------------------------------------
86 /* We sync the data then unset the dirty flag in two steps so as to
87 advoid a problem during a crash */
88 pkgCacheGenerator::~pkgCacheGenerator()
90 if (_error
->PendingError() == true)
92 if (Map
.Sync() == false)
95 Cache
.HeaderP
->Dirty
= false;
96 Map
.Sync(0,sizeof(pkgCache::Header
));
99 // CacheGenerator::MergeList - Merge the package list /*{{{*/
100 // ---------------------------------------------------------------------
101 /* This provides the generation of the entries in the cache. Each loop
102 goes through a single package record from the underlying parse engine. */
103 bool pkgCacheGenerator::MergeList(ListParser
&List
,
104 pkgCache::VerIterator
*OutVer
)
108 unsigned int Counter
= 0;
109 while (List
.Step() == true)
111 // Get a pointer to the package structure
112 string PackageName
= List
.Package();
113 if (PackageName
.empty() == true)
116 pkgCache::PkgIterator Pkg
;
117 if (NewPackage(Pkg
,PackageName
) == false)
118 return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str());
120 if (Counter
% 100 == 0 && Progress
!= 0)
121 Progress
->Progress(List
.Offset());
123 /* Get a pointer to the version structure. We know the list is sorted
124 so we use that fact in the search. Insertion of new versions is
125 done with correct sorting */
126 string Version
= List
.Version();
127 if (Version
.empty() == true)
129 // we first process the package, then the descriptions
130 // (this has the bonus that we get MMap error when we run out
132 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
133 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
134 PackageName
.c_str());
136 // Find the right version to write the description
137 MD5SumValue CurMd5
= List
.Description_md5();
138 pkgCache::VerIterator Ver
= Pkg
.VersionList();
139 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
141 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
143 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
144 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
145 bool duplicate
=false;
147 // don't add a new description if we have one for the given
149 for ( ; Desc
.end() == false; Desc
++)
150 if (MD5SumValue(Desc
.md5()) == CurMd5
&&
151 Desc
.LanguageCode() == List
.DescriptionLanguage())
156 for (Desc
= Ver
.DescriptionList();
158 LastDesc
= &Desc
->NextDesc
, Desc
++)
160 if (MD5SumValue(Desc
.md5()) == CurMd5
)
162 // Add new description
163 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
);
164 Desc
->ParentPkg
= Pkg
.Index();
166 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
167 return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName
.c_str());
176 pkgCache::VerIterator Ver
= Pkg
.VersionList();
177 map_ptrloc
*LastVer
= &Pkg
->VersionList
;
179 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
181 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
186 /* We already have a version for this item, record that we
188 unsigned long Hash
= List
.VersionHash();
189 if (Res
== 0 && Ver
->Hash
== Hash
)
191 if (List
.UsePackage(Pkg
,Ver
) == false)
192 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
193 PackageName
.c_str());
195 if (NewFileVer(Ver
,List
) == false)
196 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
197 PackageName
.c_str());
199 // Read only a single record and return
203 FoundFileDeps
|= List
.HasFileDeps();
210 // Skip to the end of the same version set.
213 for (; Ver
.end() == false; LastVer
= &Ver
->NextVer
, Ver
++)
215 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
222 *LastVer
= NewVersion(Ver
,Version
,*LastVer
);
223 Ver
->ParentPkg
= Pkg
.Index();
226 if ((*LastVer
== 0 && _error
->PendingError()) || List
.NewVersion(Ver
) == false)
227 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
228 PackageName
.c_str());
230 if (List
.UsePackage(Pkg
,Ver
) == false)
231 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
232 PackageName
.c_str());
234 if (NewFileVer(Ver
,List
) == false)
235 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
236 PackageName
.c_str());
238 // Read only a single record and return
242 FoundFileDeps
|= List
.HasFileDeps();
246 /* Record the Description data. Description data always exist in
247 Packages and Translation-* files. */
248 pkgCache::DescIterator Desc
= Ver
.DescriptionList();
249 map_ptrloc
*LastDesc
= &Ver
->DescriptionList
;
251 // Skip to the end of description set
252 for (; Desc
.end() == false; LastDesc
= &Desc
->NextDesc
, Desc
++);
254 // Add new description
255 *LastDesc
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
);
256 Desc
->ParentPkg
= Pkg
.Index();
258 if ((*LastDesc
== 0 && _error
->PendingError()) || NewFileDesc(Desc
,List
) == false)
259 return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str());
262 FoundFileDeps
|= List
.HasFileDeps();
264 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
265 return _error
->Error(_("Wow, you exceeded the number of package "
266 "names this APT is capable of."));
267 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
268 return _error
->Error(_("Wow, you exceeded the number of versions "
269 "this APT is capable of."));
270 if (Cache
.HeaderP
->DescriptionCount
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1)
271 return _error
->Error(_("Wow, you exceeded the number of descriptions "
272 "this APT is capable of."));
273 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
274 return _error
->Error(_("Wow, you exceeded the number of dependencies "
275 "this APT is capable of."));
279 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
280 // ---------------------------------------------------------------------
281 /* If we found any file depends while parsing the main list we need to
282 resolve them. Since it is undesired to load the entire list of files
283 into the cache as virtual packages we do a two stage effort. MergeList
284 identifies the file depends and this creates Provdies for them by
285 re-parsing all the indexs. */
286 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
290 unsigned int Counter
= 0;
291 while (List
.Step() == true)
293 string PackageName
= List
.Package();
294 if (PackageName
.empty() == true)
296 string Version
= List
.Version();
297 if (Version
.empty() == true)
300 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
301 if (Pkg
.end() == true)
302 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
303 PackageName
.c_str());
305 if (Counter
% 100 == 0 && Progress
!= 0)
306 Progress
->Progress(List
.Offset());
308 unsigned long Hash
= List
.VersionHash();
309 pkgCache::VerIterator Ver
= Pkg
.VersionList();
310 for (; Ver
.end() == false; Ver
++)
312 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
314 if (List
.CollectFileProvides(Cache
,Ver
) == false)
315 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
320 if (Ver
.end() == true)
321 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
327 // CacheGenerator::NewPackage - Add a new package /*{{{*/
328 // ---------------------------------------------------------------------
329 /* This creates a new package structure and adds it to the hash table */
330 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
332 Pkg
= Cache
.FindPkg(Name
);
333 if (Pkg
.end() == false)
337 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
341 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
343 // Insert it into the hash table
344 unsigned long Hash
= Cache
.Hash(Name
);
345 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
346 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
348 // Set the name and the ID
349 Pkg
->Name
= Map
.WriteString(Name
);
352 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
357 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
358 // ---------------------------------------------------------------------
360 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
363 if (CurrentFile
== 0)
367 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
371 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
372 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
374 // Link it to the end of the list
375 map_ptrloc
*Last
= &Ver
->FileList
;
376 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
378 VF
->NextFile
= *Last
;
381 VF
->Offset
= List
.Offset();
382 VF
->Size
= List
.Size();
383 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
384 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
385 Cache
.HeaderP
->VerFileCount
++;
390 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
391 // ---------------------------------------------------------------------
392 /* This puts a version structure in the linked list */
393 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
394 const string
&VerStr
,
398 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
403 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
405 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
406 Ver
->VerStr
= Map
.WriteString(VerStr
);
407 if (Ver
->VerStr
== 0)
413 // CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
414 // ---------------------------------------------------------------------
416 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator
&Desc
,
419 if (CurrentFile
== 0)
423 unsigned long DescFile
= Map
.Allocate(sizeof(pkgCache::DescFile
));
427 pkgCache::DescFileIterator
DF(Cache
,Cache
.DescFileP
+ DescFile
);
428 DF
->File
= CurrentFile
- Cache
.PkgFileP
;
430 // Link it to the end of the list
431 map_ptrloc
*Last
= &Desc
->FileList
;
432 for (pkgCache::DescFileIterator D
= Desc
.FileList(); D
.end() == false; D
++)
435 DF
->NextFile
= *Last
;
438 DF
->Offset
= List
.Offset();
439 DF
->Size
= List
.Size();
440 if (Cache
.HeaderP
->MaxDescFileSize
< DF
->Size
)
441 Cache
.HeaderP
->MaxDescFileSize
= DF
->Size
;
442 Cache
.HeaderP
->DescFileCount
++;
447 // CacheGenerator::NewDescription - Create a new Description /*{{{*/
448 // ---------------------------------------------------------------------
449 /* This puts a description structure in the linked list */
450 map_ptrloc
pkgCacheGenerator::NewDescription(pkgCache::DescIterator
&Desc
,
452 const MD5SumValue
&md5sum
,
456 map_ptrloc Description
= Map
.Allocate(sizeof(pkgCache::Description
));
457 if (Description
== 0)
461 Desc
= pkgCache::DescIterator(Cache
,Cache
.DescP
+ Description
);
462 Desc
->NextDesc
= Next
;
463 Desc
->ID
= Cache
.HeaderP
->DescriptionCount
++;
464 Desc
->language_code
= Map
.WriteString(Lang
);
465 Desc
->md5sum
= Map
.WriteString(md5sum
.Value());
466 if (Desc
->language_code
== 0 || Desc
->md5sum
== 0)
472 // ListParser::NewDepends - Create a dependency element /*{{{*/
473 // ---------------------------------------------------------------------
474 /* This creates a dependency element in the tree. It is linked to the
475 version and to the package that it is pointing to. */
476 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
477 const string
&PackageName
,
478 const string
&Version
,
482 pkgCache
&Cache
= Owner
->Cache
;
485 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
490 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
491 Dep
->ParentVer
= Ver
.Index();
494 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
496 // Locate the target package
497 pkgCache::PkgIterator Pkg
;
498 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
501 // Probe the reverse dependency list for a version string that matches
502 if (Version
.empty() == false)
504 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
505 if (I->Version != 0 && I.TargetVer() == Version)
506 Dep->Version = I->Version;*/
507 if (Dep
->Version
== 0)
508 if ((Dep
->Version
= WriteString(Version
)) == 0)
512 // Link it to the package
513 Dep
->Package
= Pkg
.Index();
514 Dep
->NextRevDepends
= Pkg
->RevDepends
;
515 Pkg
->RevDepends
= Dep
.Index();
517 /* Link it to the version (at the end of the list)
518 Caching the old end point speeds up generation substantially */
519 if (OldDepVer
!= Ver
)
521 OldDepLast
= &Ver
->DependsList
;
522 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
523 OldDepLast
= &D
->NextDepends
;
527 // Is it a file dependency?
528 if (PackageName
[0] == '/')
529 FoundFileDeps
= true;
531 Dep
->NextDepends
= *OldDepLast
;
532 *OldDepLast
= Dep
.Index();
533 OldDepLast
= &Dep
->NextDepends
;
538 // ListParser::NewProvides - Create a Provides element /*{{{*/
539 // ---------------------------------------------------------------------
541 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
542 const string
&PackageName
,
543 const string
&Version
)
545 pkgCache
&Cache
= Owner
->Cache
;
547 // We do not add self referencing provides
548 if (Ver
.ParentPkg().Name() == PackageName
)
552 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
555 Cache
.HeaderP
->ProvidesCount
++;
558 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
559 Prv
->Version
= Ver
.Index();
560 Prv
->NextPkgProv
= Ver
->ProvidesList
;
561 Ver
->ProvidesList
= Prv
.Index();
562 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
565 // Locate the target package
566 pkgCache::PkgIterator Pkg
;
567 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
570 // Link it to the package
571 Prv
->ParentPkg
= Pkg
.Index();
572 Prv
->NextProvides
= Pkg
->ProvidesList
;
573 Pkg
->ProvidesList
= Prv
.Index();
578 // ListParser::NewTag - Create a Tag element /*{{{*/
579 // ---------------------------------------------------------------------
581 bool pkgCacheGenerator::ListParser::NewTag(pkgCache::PkgIterator Pkg
,
582 const char *NameStart
,
583 unsigned int NameSize
)
585 pkgCache
&Cache
= Owner
->Cache
;
588 unsigned long Tagg
= Owner
->Map
.Allocate(sizeof(pkgCache::Tag
));
591 Cache
.HeaderP
->TagCount
++;
594 pkgCache::TagIterator
Tg(Cache
,Cache
.TagP
+ Tagg
);
595 Tg
->Name
= WriteString(NameStart
,NameSize
);
598 Tg
->NextTag
= Pkg
->TagList
;
599 Pkg
->TagList
= Tg
.Index();
604 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
605 // ---------------------------------------------------------------------
606 /* This is used to select which file is to be associated with all newly
607 added versions. The caller is responsible for setting the IMS fields. */
608 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
609 const pkgIndexFile
&Index
,
612 // Get some space for the structure
613 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
614 if (CurrentFile
== Cache
.PkgFileP
)
618 CurrentFile
->FileName
= Map
.WriteString(File
);
619 CurrentFile
->Site
= WriteUniqString(Site
);
620 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
621 CurrentFile
->Flags
= Flags
;
622 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
623 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
625 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
626 Cache
.HeaderP
->PackageFileCount
++;
628 if (CurrentFile
->FileName
== 0)
632 Progress
->SubProgress(Index
.Size());
636 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
637 // ---------------------------------------------------------------------
638 /* This is used to create handles to strings. Given the same text it
639 always returns the same number */
640 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
643 uint32_t hash
= hashlittle(S
, Size
, 0xdeadbeef);
645 /* We use a VERY LARGE INTRANSIENT hash table here, this speeds up generation
646 by AN INSANE amount on ALL machines */
647 pkgCache::StringItem
**Bucket2
;
649 Bucket2
= &UniqHash
[hash
% _count(UniqHash
)];
650 if (*Bucket2
== NULL
)
652 if (stringcmp(S
,S
+Size
,Cache
.StrP
+ (*Bucket2
)->String
) == 0)
653 return (*Bucket2
)->String
;
657 pkgCache::StringItem
*&Bucket
= *Bucket2
;
658 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
659 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
662 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
666 // Fill in the structure
667 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
668 ItemP
->NextItem
= I
- Cache
.StringItemP
;
670 ItemP
->String
= Map
.WriteString(S
,Size
);
671 if (ItemP
->String
== 0)
675 return ItemP
->String
;
678 // CheckValidity - Check that a cache is up-to-date /*{{{*/
679 // ---------------------------------------------------------------------
680 /* This just verifies that each file in the list of index files exists,
681 has matching attributes with the cache and the cache does not have
683 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
684 FileIterator End
,MMap
**OutMap
= 0)
686 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
687 // No file, certainly invalid
688 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
691 std::clog
<< "CacheFile doesn't exist" << std::endl
;
696 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
697 SPtr
<MMap
> Map
= new MMap(CacheF
,0);
699 if (_error
->PendingError() == true || Map
->Size() == 0)
702 std::clog
<< "Errors are pending or Map is empty()" << std::endl
;
707 /* Now we check every index file, see if it is in the cache,
708 verify the IMS data and check that it is on the disk too.. */
709 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
710 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
711 for (; Start
!= End
; Start
++)
714 std::clog
<< "Checking PkgFile " << (*Start
)->Describe() << ": ";
715 if ((*Start
)->HasPackages() == false)
718 std::clog
<< "Has NO packages" << std::endl
;
722 if ((*Start
)->Exists() == false)
724 #if 0 // mvo: we no longer give a message here (Default Sources spec)
725 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
726 (*Start
)->Describe().c_str());
729 std::clog
<< "file doesn't exist" << std::endl
;
733 // FindInCache is also expected to do an IMS check.
734 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
735 if (File
.end() == true)
738 std::clog
<< "FindInCache returned end-Pointer" << std::endl
;
742 Visited
[File
->ID
] = true;
744 std::clog
<< "with ID " << File
->ID
<< " is valid" << std::endl
;
747 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
748 if (Visited
[I
] == false)
751 std::clog
<< "File with ID" << I
<< " wasn't visited" << std::endl
;
755 if (_error
->PendingError() == true)
759 std::clog
<< "Validity failed because of pending errors:" << std::endl
;
760 _error
->DumpErrors();
767 *OutMap
= Map
.UnGuard();
771 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
772 // ---------------------------------------------------------------------
773 /* Size is kind of an abstract notion that is only used for the progress
775 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
777 unsigned long TotalSize
= 0;
778 for (; Start
!= End
; Start
++)
780 if ((*Start
)->HasPackages() == false)
782 TotalSize
+= (*Start
)->Size();
787 // BuildCache - Merge the list of index files into the cache /*{{{*/
788 // ---------------------------------------------------------------------
790 static bool BuildCache(pkgCacheGenerator
&Gen
,
791 OpProgress
&Progress
,
792 unsigned long &CurrentSize
,unsigned long TotalSize
,
793 FileIterator Start
, FileIterator End
)
796 for (I
= Start
; I
!= End
; I
++)
798 if ((*I
)->HasPackages() == false)
801 if ((*I
)->Exists() == false)
804 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
806 _error
->Warning("Duplicate sources.list entry %s",
807 (*I
)->Describe().c_str());
811 unsigned long Size
= (*I
)->Size();
812 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
815 if ((*I
)->Merge(Gen
,Progress
) == false)
819 if (Gen
.HasFileDeps() == true)
822 TotalSize
= ComputeSize(Start
, End
);
824 for (I
= Start
; I
!= End
; I
++)
826 unsigned long Size
= (*I
)->Size();
827 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
829 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
837 // MakeStatusCache - Construct the status cache /*{{{*/
838 // ---------------------------------------------------------------------
839 /* This makes sure that the status cache (the cache that has all
840 index files from the sources list and all local ones) is ready
841 to be mmaped. If OutMap is not zero then a MMap object representing
842 the cache will be stored there. This is pretty much mandetory if you
843 are using AllowMem. AllowMem lets the function be run as non-root
844 where it builds the cache 'fast' into a memory buffer. */
845 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
846 MMap
**OutMap
,bool AllowMem
)
848 bool const Debug
= _config
->FindB("Debug::pkgCacheGen", false);
849 unsigned long const MapSize
= _config
->FindI("APT::Cache-Limit",24*1024*1024);
851 vector
<pkgIndexFile
*> Files
;
852 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
856 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
857 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
860 Files
.push_back (*j
);
863 unsigned long const EndOfSource
= Files
.size();
864 if (_system
->AddStatusFiles(Files
) == false)
867 // Decide if we can write to the files..
868 string
const CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
869 string
const SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
871 // Decide if we can write to the cache
872 bool Writeable
= false;
873 if (CacheFile
.empty() == false)
874 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
876 if (SrcCacheFile
.empty() == false)
877 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
879 std::clog
<< "Do we have write-access to the cache files? " << (Writeable
? "YES" : "NO") << std::endl
;
881 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
882 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
884 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
887 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
889 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
891 std::clog
<< "pkgcache.bin is valid - no need to build anything" << std::endl
;
894 else if (Debug
== true)
895 std::clog
<< "pkgcache.bin is NOT valid" << std::endl
;
897 /* At this point we know we need to reconstruct the package cache,
900 SPtr
<DynamicMMap
> Map
;
901 if (Writeable
== true && CacheFile
.empty() == false)
903 unlink(CacheFile
.c_str());
904 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
905 fchmod(CacheF
->Fd(),0644);
906 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
907 if (_error
->PendingError() == true)
910 std::clog
<< "Open filebased MMap" << std::endl
;
914 // Just build it in memory..
915 Map
= new DynamicMMap(0,MapSize
);
917 std::clog
<< "Open memory Map (not filebased)" << std::endl
;
920 // Lets try the source cache.
921 unsigned long CurrentSize
= 0;
922 unsigned long TotalSize
= 0;
923 if (CheckValidity(SrcCacheFile
,Files
.begin(),
924 Files
.begin()+EndOfSource
) == true)
927 std::clog
<< "srcpkgcache.bin is valid - populate MMap with it." << std::endl
;
928 // Preload the map with the source cache
929 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
930 unsigned long const alloc
= Map
->RawAllocate(SCacheF
.Size());
931 if ((alloc
== 0 && _error
->PendingError())
932 || SCacheF
.Read((unsigned char *)Map
->Data() + alloc
,
933 SCacheF
.Size()) == false)
936 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
938 // Build the status cache
939 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
940 if (_error
->PendingError() == true)
942 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
943 Files
.begin()+EndOfSource
,Files
.end()) == false)
949 std::clog
<< "srcpkgcache.bin is NOT valid - rebuild" << std::endl
;
950 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
952 // Build the source cache
953 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
954 if (_error
->PendingError() == true)
956 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
957 Files
.begin(),Files
.begin()+EndOfSource
) == false)
961 if (Writeable
== true && SrcCacheFile
.empty() == false)
963 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
964 if (_error
->PendingError() == true)
967 fchmod(SCacheF
.Fd(),0644);
969 // Write out the main data
970 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
971 return _error
->Error(_("IO Error saving source cache"));
974 // Write out the proper header
975 Gen
.GetCache().HeaderP
->Dirty
= false;
976 if (SCacheF
.Seek(0) == false ||
977 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
978 return _error
->Error(_("IO Error saving source cache"));
979 Gen
.GetCache().HeaderP
->Dirty
= true;
983 // Build the status cache
984 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
985 Files
.begin()+EndOfSource
,Files
.end()) == false)
989 std::clog
<< "Caches are ready for shipping" << std::endl
;
991 if (_error
->PendingError() == true)
997 delete Map
.UnGuard();
998 *OutMap
= new MMap(*CacheF
,0);
1002 *OutMap
= Map
.UnGuard();
1009 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
1010 // ---------------------------------------------------------------------
1012 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
1014 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",20*1024*1024);
1015 vector
<pkgIndexFile
*> Files
;
1016 unsigned long EndOfSource
= Files
.size();
1017 if (_system
->AddStatusFiles(Files
) == false)
1020 SPtr
<DynamicMMap
> Map
= new DynamicMMap(0,MapSize
);
1021 unsigned long CurrentSize
= 0;
1022 unsigned long TotalSize
= 0;
1024 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
1026 // Build the status cache
1027 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
1028 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
1029 if (_error
->PendingError() == true)
1031 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
1032 Files
.begin()+EndOfSource
,Files
.end()) == false)
1035 if (_error
->PendingError() == true)
1037 *OutMap
= Map
.UnGuard();