]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz Exp $
4 /* ######################################################################
6 Package Cache Generator - Generator for the cache structure.
8 This builds the cache structure from the abstract package list parser.
10 ##################################################################### */
12 // Include Files /*{{{*/
14 #pragma implementation "apt-pkg/pkgcachegen.h"
17 #define APT_COMPATIBILITY 986
19 #include <apt-pkg/pkgcachegen.h>
20 #include <apt-pkg/error.h>
21 #include <apt-pkg/version.h>
22 #include <apt-pkg/progress.h>
23 #include <apt-pkg/sourcelist.h>
24 #include <apt-pkg/configuration.h>
25 #include <apt-pkg/strutl.h>
26 #include <apt-pkg/sptr.h>
27 #include <apt-pkg/pkgsystem.h>
39 typedef vector
<pkgIndexFile
*>::iterator FileIterator
;
41 // CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
42 // ---------------------------------------------------------------------
43 /* We set the diry flag and make sure that is written to the disk */
44 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap
*pMap
,OpProgress
*Prog
) :
45 Map(*pMap
), Cache(pMap
,false), Progress(Prog
),
49 memset(UniqHash
,0,sizeof(UniqHash
));
51 if (_error
->PendingError() == true)
56 // Setup the map interface..
57 Cache
.HeaderP
= (pkgCache::Header
*)Map
.Data();
58 Map
.RawAllocate(sizeof(pkgCache::Header
));
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 if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false)
129 return _error
->Error(_("Error occurred while processing %s (UsePackage1)"),
130 PackageName
.c_str());
134 pkgCache::VerIterator Ver
= Pkg
.VersionList();
135 map_ptrloc
*Last
= &Pkg
->VersionList
;
137 for (; Ver
.end() == false; Last
= &Ver
->NextVer
, Ver
++)
139 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
144 /* We already have a version for this item, record that we
146 unsigned long Hash
= List
.VersionHash();
147 if (Res
== 0 && Ver
->Hash
== Hash
)
149 if (List
.UsePackage(Pkg
,Ver
) == false)
150 return _error
->Error(_("Error occurred while processing %s (UsePackage2)"),
151 PackageName
.c_str());
153 if (NewFileVer(Ver
,List
) == false)
154 return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"),
155 PackageName
.c_str());
157 // Read only a single record and return
161 FoundFileDeps
|= List
.HasFileDeps();
168 // Skip to the end of the same version set.
171 for (; Ver
.end() == false; Last
= &Ver
->NextVer
, Ver
++)
173 Res
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr());
180 *Last
= NewVersion(Ver
,Version
,*Last
);
181 Ver
->ParentPkg
= Pkg
.Index();
183 if (List
.NewVersion(Ver
) == false)
184 return _error
->Error(_("Error occurred while processing %s (NewVersion1)"),
185 PackageName
.c_str());
187 if (List
.UsePackage(Pkg
,Ver
) == false)
188 return _error
->Error(_("Error occurred while processing %s (UsePackage3)"),
189 PackageName
.c_str());
191 if (NewFileVer(Ver
,List
) == false)
192 return _error
->Error(_("Error occurred while processing %s (NewVersion2)"),
193 PackageName
.c_str());
195 // Read only a single record and return
199 FoundFileDeps
|= List
.HasFileDeps();
204 FoundFileDeps
|= List
.HasFileDeps();
206 if (Cache
.HeaderP
->PackageCount
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1)
207 return _error
->Error(_("Wow, you exceeded the number of package "
208 "names this APT is capable of."));
209 if (Cache
.HeaderP
->VersionCount
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1)
210 return _error
->Error(_("Wow, you exceeded the number of versions "
211 "this APT is capable of."));
212 if (Cache
.HeaderP
->DependsCount
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL)
213 return _error
->Error(_("Wow, you exceeded the number of dependencies "
214 "this APT is capable of."));
218 // CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
219 // ---------------------------------------------------------------------
220 /* If we found any file depends while parsing the main list we need to
221 resolve them. Since it is undesired to load the entire list of files
222 into the cache as virtual packages we do a two stage effort. MergeList
223 identifies the file depends and this creates Provdies for them by
224 re-parsing all the indexs. */
225 bool pkgCacheGenerator::MergeFileProvides(ListParser
&List
)
229 unsigned int Counter
= 0;
230 while (List
.Step() == true)
232 string PackageName
= List
.Package();
233 if (PackageName
.empty() == true)
235 string Version
= List
.Version();
236 if (Version
.empty() == true)
239 pkgCache::PkgIterator Pkg
= Cache
.FindPkg(PackageName
);
240 if (Pkg
.end() == true)
241 return _error
->Error(_("Error occurred while processing %s (FindPkg)"),
242 PackageName
.c_str());
244 if (Counter
% 100 == 0 && Progress
!= 0)
245 Progress
->Progress(List
.Offset());
247 unsigned long Hash
= List
.VersionHash();
248 pkgCache::VerIterator Ver
= Pkg
.VersionList();
249 for (; Ver
.end() == false; Ver
++)
251 if (Ver
->Hash
== Hash
&& Version
.c_str() == Ver
.VerStr())
253 if (List
.CollectFileProvides(Cache
,Ver
) == false)
254 return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str());
259 if (Ver
.end() == true)
260 _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str());
266 // CacheGenerator::NewPackage - Add a new package /*{{{*/
267 // ---------------------------------------------------------------------
268 /* This creates a new package structure and adds it to the hash table */
269 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator
&Pkg
,const string
&Name
)
271 Pkg
= Cache
.FindPkg(Name
);
272 if (Pkg
.end() == false)
276 unsigned long Package
= Map
.Allocate(sizeof(pkgCache::Package
));
280 Pkg
= pkgCache::PkgIterator(Cache
,Cache
.PkgP
+ Package
);
282 // Insert it into the hash table
283 unsigned long Hash
= Cache
.Hash(Name
);
284 Pkg
->NextPackage
= Cache
.HeaderP
->HashTable
[Hash
];
285 Cache
.HeaderP
->HashTable
[Hash
] = Package
;
287 // Set the name and the ID
288 Pkg
->Name
= Map
.WriteString(Name
);
291 Pkg
->ID
= Cache
.HeaderP
->PackageCount
++;
296 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
297 // ---------------------------------------------------------------------
299 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator
&Ver
,
302 if (CurrentFile
== 0)
306 unsigned long VerFile
= Map
.Allocate(sizeof(pkgCache::VerFile
));
310 pkgCache::VerFileIterator
VF(Cache
,Cache
.VerFileP
+ VerFile
);
311 VF
->File
= CurrentFile
- Cache
.PkgFileP
;
313 // Link it to the end of the list
314 map_ptrloc
*Last
= &Ver
->FileList
;
315 for (pkgCache::VerFileIterator V
= Ver
.FileList(); V
.end() == false; V
++)
317 VF
->NextFile
= *Last
;
320 VF
->Offset
= List
.Offset();
321 VF
->Size
= List
.Size();
322 if (Cache
.HeaderP
->MaxVerFileSize
< VF
->Size
)
323 Cache
.HeaderP
->MaxVerFileSize
= VF
->Size
;
324 Cache
.HeaderP
->VerFileCount
++;
329 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
330 // ---------------------------------------------------------------------
331 /* This puts a version structure in the linked list */
332 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator
&Ver
,
333 const string
&VerStr
,
337 unsigned long Version
= Map
.Allocate(sizeof(pkgCache::Version
));
342 Ver
= pkgCache::VerIterator(Cache
,Cache
.VerP
+ Version
);
344 Ver
->ID
= Cache
.HeaderP
->VersionCount
++;
345 Ver
->VerStr
= Map
.WriteString(VerStr
);
346 if (Ver
->VerStr
== 0)
352 // ListParser::NewDepends - Create a dependency element /*{{{*/
353 // ---------------------------------------------------------------------
354 /* This creates a dependency element in the tree. It is linked to the
355 version and to the package that it is pointing to. */
356 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
,
357 const string
&PackageName
,
358 const string
&Version
,
362 pkgCache
&Cache
= Owner
->Cache
;
365 unsigned long Dependency
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
));
370 pkgCache::DepIterator
Dep(Cache
,Cache
.DepP
+ Dependency
);
371 Dep
->ParentVer
= Ver
.Index();
374 Dep
->ID
= Cache
.HeaderP
->DependsCount
++;
376 // Locate the target package
377 pkgCache::PkgIterator Pkg
;
378 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
381 // Probe the reverse dependency list for a version string that matches
382 if (Version
.empty() == false)
384 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
385 if (I->Version != 0 && I.TargetVer() == Version)
386 Dep->Version = I->Version;*/
387 if (Dep
->Version
== 0)
388 if ((Dep
->Version
= WriteString(Version
)) == 0)
392 // Link it to the package
393 Dep
->Package
= Pkg
.Index();
394 Dep
->NextRevDepends
= Pkg
->RevDepends
;
395 Pkg
->RevDepends
= Dep
.Index();
397 /* Link it to the version (at the end of the list)
398 Caching the old end point speeds up generation substantially */
399 if (OldDepVer
!= Ver
)
401 OldDepLast
= &Ver
->DependsList
;
402 for (pkgCache::DepIterator D
= Ver
.DependsList(); D
.end() == false; D
++)
403 OldDepLast
= &D
->NextDepends
;
407 // Is it a file dependency?
408 if (PackageName
[0] == '/')
409 FoundFileDeps
= true;
411 Dep
->NextDepends
= *OldDepLast
;
412 *OldDepLast
= Dep
.Index();
413 OldDepLast
= &Dep
->NextDepends
;
418 // ListParser::NewProvides - Create a Provides element /*{{{*/
419 // ---------------------------------------------------------------------
421 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
,
422 const string
&PackageName
,
423 const string
&Version
)
425 pkgCache
&Cache
= Owner
->Cache
;
427 // We do not add self referencing provides
428 if (Ver
.ParentPkg().Name() == PackageName
)
432 unsigned long Provides
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
));
435 Cache
.HeaderP
->ProvidesCount
++;
438 pkgCache::PrvIterator
Prv(Cache
,Cache
.ProvideP
+ Provides
,Cache
.PkgP
);
439 Prv
->Version
= Ver
.Index();
440 Prv
->NextPkgProv
= Ver
->ProvidesList
;
441 Ver
->ProvidesList
= Prv
.Index();
442 if (Version
.empty() == false && (Prv
->ProvideVersion
= WriteString(Version
)) == 0)
445 // Locate the target package
446 pkgCache::PkgIterator Pkg
;
447 if (Owner
->NewPackage(Pkg
,PackageName
) == false)
450 // Link it to the package
451 Prv
->ParentPkg
= Pkg
.Index();
452 Prv
->NextProvides
= Pkg
->ProvidesList
;
453 Pkg
->ProvidesList
= Prv
.Index();
458 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
459 // ---------------------------------------------------------------------
460 /* This is used to select which file is to be associated with all newly
461 added versions. The caller is responsible for setting the IMS fields. */
462 bool pkgCacheGenerator::SelectFile(const string
&File
,const string
&Site
,
463 const pkgIndexFile
&Index
,
466 // Get some space for the structure
467 CurrentFile
= Cache
.PkgFileP
+ Map
.Allocate(sizeof(*CurrentFile
));
468 if (CurrentFile
== Cache
.PkgFileP
)
472 CurrentFile
->FileName
= Map
.WriteString(File
);
473 CurrentFile
->Site
= WriteUniqString(Site
);
474 CurrentFile
->NextFile
= Cache
.HeaderP
->FileList
;
475 CurrentFile
->Flags
= Flags
;
476 CurrentFile
->ID
= Cache
.HeaderP
->PackageFileCount
;
477 CurrentFile
->IndexType
= WriteUniqString(Index
.GetType()->Label
);
479 Cache
.HeaderP
->FileList
= CurrentFile
- Cache
.PkgFileP
;
480 Cache
.HeaderP
->PackageFileCount
++;
482 if (CurrentFile
->FileName
== 0)
486 Progress
->SubProgress(Index
.Size());
490 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
491 // ---------------------------------------------------------------------
492 /* This is used to create handles to strings. Given the same text it
493 always returns the same number */
494 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
,
497 /* We use a very small transient hash table here, this speeds up generation
498 by a fair amount on slower machines */
499 pkgCache::StringItem
*&Bucket
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)];
501 stringcmp(S
,S
+Size
,Cache
.StrP
+ Bucket
->String
) == 0)
502 return Bucket
->String
;
504 // Search for an insertion point
505 pkgCache::StringItem
*I
= Cache
.StringItemP
+ Cache
.HeaderP
->StringList
;
507 map_ptrloc
*Last
= &Cache
.HeaderP
->StringList
;
508 for (; I
!= Cache
.StringItemP
; Last
= &I
->NextItem
,
509 I
= Cache
.StringItemP
+ I
->NextItem
)
511 Res
= stringcmp(S
,S
+Size
,Cache
.StrP
+ I
->String
);
524 unsigned long Item
= Map
.Allocate(sizeof(pkgCache::StringItem
));
528 // Fill in the structure
529 pkgCache::StringItem
*ItemP
= Cache
.StringItemP
+ Item
;
530 ItemP
->NextItem
= I
- Cache
.StringItemP
;
532 ItemP
->String
= Map
.WriteString(S
,Size
);
533 if (ItemP
->String
== 0)
537 return ItemP
->String
;
541 // CheckValidity - Check that a cache is up-to-date /*{{{*/
542 // ---------------------------------------------------------------------
543 /* This just verifies that each file in the list of index files exists,
544 has matching attributes with the cache and the cache does not have
546 static bool CheckValidity(const string
&CacheFile
, FileIterator Start
,
547 FileIterator End
,MMap
**OutMap
= 0)
549 // No file, certainly invalid
550 if (CacheFile
.empty() == true || FileExists(CacheFile
) == false)
554 FileFd
CacheF(CacheFile
,FileFd::ReadOnly
);
555 SPtr
<MMap
> Map
= new MMap(CacheF
,MMap::Public
| MMap::ReadOnly
);
557 if (_error
->PendingError() == true || Map
->Size() == 0)
563 /* Now we check every index file, see if it is in the cache,
564 verify the IMS data and check that it is on the disk too.. */
565 SPtrArray
<bool> Visited
= new bool[Cache
.HeaderP
->PackageFileCount
];
566 memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
);
567 for (; Start
!= End
; Start
++)
569 if ((*Start
)->HasPackages() == false)
572 if ((*Start
)->Exists() == false)
574 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
575 (*Start
)->Describe().c_str());
579 // FindInCache is also expected to do an IMS check.
580 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
581 if (File
.end() == true)
584 Visited
[File
->ID
] = true;
587 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
588 if (Visited
[I
] == false)
591 if (_error
->PendingError() == true)
598 *OutMap
= Map
.UnGuard();
602 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
603 // ---------------------------------------------------------------------
604 /* Size is kind of an abstract notion that is only used for the progress
606 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
608 unsigned long TotalSize
= 0;
609 for (; Start
!= End
; Start
++)
611 if ((*Start
)->HasPackages() == false)
613 TotalSize
+= (*Start
)->Size();
618 // BuildCache - Merge the list of index files into the cache /*{{{*/
619 // ---------------------------------------------------------------------
621 static bool BuildCache(pkgCacheGenerator
&Gen
,
622 OpProgress
&Progress
,
623 unsigned long &CurrentSize
,unsigned long TotalSize
,
624 FileIterator Start
, FileIterator End
)
627 for (I
= Start
; I
!= End
; I
++)
629 if ((*I
)->HasPackages() == false)
632 if ((*I
)->Exists() == false)
635 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
637 _error
->Warning("Duplicate sources.list entry %s",
638 (*I
)->Describe().c_str());
642 unsigned long Size
= (*I
)->Size();
643 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
646 if ((*I
)->Merge(Gen
,Progress
) == false)
650 if (Gen
.HasFileDeps() == true)
653 TotalSize
= ComputeSize(Start
, End
);
655 for (I
= Start
; I
!= End
; I
++)
657 unsigned long Size
= (*I
)->Size();
658 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
660 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
668 // MakeStatusCache - Construct the status cache /*{{{*/
669 // ---------------------------------------------------------------------
670 /* This makes sure that the status cache (the cache that has all
671 index files from the sources list and all local ones) is ready
672 to be mmaped. If OutMap is not zero then a MMap object representing
673 the cache will be stored there. This is pretty much mandetory if you
674 are using AllowMem. AllowMem lets the function be run as non-root
675 where it builds the cache 'fast' into a memory buffer. */
676 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
677 MMap
**OutMap
,bool AllowMem
)
679 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",12*1024*1024);
681 vector
<pkgIndexFile
*> Files
;
682 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
686 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
687 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
690 Files
.push_back (*j
);
693 unsigned long EndOfSource
= Files
.size();
694 if (_system
->AddStatusFiles(Files
) == false)
697 // Decide if we can write to the files..
698 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
699 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
701 // Decide if we can write to the cache
702 bool Writeable
= false;
703 if (CacheFile
.empty() == false)
704 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
706 if (SrcCacheFile
.empty() == false)
707 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
709 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
710 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
712 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
715 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
717 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
721 /* At this point we know we need to reconstruct the package cache,
724 SPtr
<DynamicMMap
> Map
;
725 if (Writeable
== true && CacheFile
.empty() == false)
727 unlink(CacheFile
.c_str());
728 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
729 fchmod(CacheF
->Fd(),0644);
730 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
731 if (_error
->PendingError() == true)
736 // Just build it in memory..
737 Map
= new DynamicMMap(MMap::Public
,MapSize
);
740 // Lets try the source cache.
741 unsigned long CurrentSize
= 0;
742 unsigned long TotalSize
= 0;
743 if (CheckValidity(SrcCacheFile
,Files
.begin(),
744 Files
.begin()+EndOfSource
) == true)
746 // Preload the map with the source cache
747 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
748 if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()),
749 SCacheF
.Size()) == false)
752 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
754 // Build the status cache
755 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
756 if (_error
->PendingError() == true)
758 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
759 Files
.begin()+EndOfSource
,Files
.end()) == false)
764 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
766 // Build the source cache
767 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
768 if (_error
->PendingError() == true)
770 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
771 Files
.begin(),Files
.begin()+EndOfSource
) == false)
775 if (Writeable
== true && SrcCacheFile
.empty() == false)
777 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
778 if (_error
->PendingError() == true)
781 fchmod(SCacheF
.Fd(),0644);
783 // Write out the main data
784 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
785 return _error
->Error(_("IO Error saving source cache"));
788 // Write out the proper header
789 Gen
.GetCache().HeaderP
->Dirty
= false;
790 if (SCacheF
.Seek(0) == false ||
791 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
792 return _error
->Error(_("IO Error saving source cache"));
793 Gen
.GetCache().HeaderP
->Dirty
= true;
797 // Build the status cache
798 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
799 Files
.begin()+EndOfSource
,Files
.end()) == false)
803 if (_error
->PendingError() == true)
809 delete Map
.UnGuard();
810 *OutMap
= new MMap(*CacheF
,MMap::Public
| MMap::ReadOnly
);
814 *OutMap
= Map
.UnGuard();
821 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
822 // ---------------------------------------------------------------------
824 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
826 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",8*1024*1024);
827 vector
<pkgIndexFile
*> Files
;
828 unsigned long EndOfSource
= Files
.size();
829 if (_system
->AddStatusFiles(Files
) == false)
832 SPtr
<DynamicMMap
> Map
;
833 Map
= new DynamicMMap(MMap::Public
,MapSize
);
834 unsigned long CurrentSize
= 0;
835 unsigned long TotalSize
= 0;
837 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
839 // Build the status cache
840 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
841 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
842 if (_error
->PendingError() == true)
844 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
845 Files
.begin()+EndOfSource
,Files
.end()) == false)
848 if (_error
->PendingError() == true)
850 *OutMap
= Map
.UnGuard();