]>
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 #if 0 // mvo: we no longer give a message here (Default Sources spec)
575 _error
->WarningE("stat",_("Couldn't stat source package list %s"),
576 (*Start
)->Describe().c_str());
581 // FindInCache is also expected to do an IMS check.
582 pkgCache::PkgFileIterator File
= (*Start
)->FindInCache(Cache
);
583 if (File
.end() == true)
586 Visited
[File
->ID
] = true;
589 for (unsigned I
= 0; I
!= Cache
.HeaderP
->PackageFileCount
; I
++)
590 if (Visited
[I
] == false)
593 if (_error
->PendingError() == true)
600 *OutMap
= Map
.UnGuard();
604 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
605 // ---------------------------------------------------------------------
606 /* Size is kind of an abstract notion that is only used for the progress
608 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
)
610 unsigned long TotalSize
= 0;
611 for (; Start
!= End
; Start
++)
613 if ((*Start
)->HasPackages() == false)
615 TotalSize
+= (*Start
)->Size();
620 // BuildCache - Merge the list of index files into the cache /*{{{*/
621 // ---------------------------------------------------------------------
623 static bool BuildCache(pkgCacheGenerator
&Gen
,
624 OpProgress
&Progress
,
625 unsigned long &CurrentSize
,unsigned long TotalSize
,
626 FileIterator Start
, FileIterator End
)
629 for (I
= Start
; I
!= End
; I
++)
631 if ((*I
)->HasPackages() == false)
634 if ((*I
)->Exists() == false)
637 if ((*I
)->FindInCache(Gen
.GetCache()).end() == false)
639 _error
->Warning("Duplicate sources.list entry %s",
640 (*I
)->Describe().c_str());
644 unsigned long Size
= (*I
)->Size();
645 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists"));
648 if ((*I
)->Merge(Gen
,Progress
) == false)
652 if (Gen
.HasFileDeps() == true)
655 TotalSize
= ComputeSize(Start
, End
);
657 for (I
= Start
; I
!= End
; I
++)
659 unsigned long Size
= (*I
)->Size();
660 Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides"));
662 if ((*I
)->MergeFileProvides(Gen
,Progress
) == false)
670 // MakeStatusCache - Construct the status cache /*{{{*/
671 // ---------------------------------------------------------------------
672 /* This makes sure that the status cache (the cache that has all
673 index files from the sources list and all local ones) is ready
674 to be mmaped. If OutMap is not zero then a MMap object representing
675 the cache will be stored there. This is pretty much mandetory if you
676 are using AllowMem. AllowMem lets the function be run as non-root
677 where it builds the cache 'fast' into a memory buffer. */
678 bool pkgMakeStatusCache(pkgSourceList
&List
,OpProgress
&Progress
,
679 MMap
**OutMap
,bool AllowMem
)
681 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",12*1024*1024);
683 vector
<pkgIndexFile
*> Files
;
684 for (vector
<metaIndex
*>::const_iterator i
= List
.begin();
688 vector
<pkgIndexFile
*> *Indexes
= (*i
)->GetIndexFiles();
689 for (vector
<pkgIndexFile
*>::const_iterator j
= Indexes
->begin();
692 Files
.push_back (*j
);
695 unsigned long EndOfSource
= Files
.size();
696 if (_system
->AddStatusFiles(Files
) == false)
699 // Decide if we can write to the files..
700 string CacheFile
= _config
->FindFile("Dir::Cache::pkgcache");
701 string SrcCacheFile
= _config
->FindFile("Dir::Cache::srcpkgcache");
703 // Decide if we can write to the cache
704 bool Writeable
= false;
705 if (CacheFile
.empty() == false)
706 Writeable
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0;
708 if (SrcCacheFile
.empty() == false)
709 Writeable
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0;
711 if (Writeable
== false && AllowMem
== false && CacheFile
.empty() == false)
712 return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str());
714 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
717 if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true)
719 Progress
.OverallProgress(1,1,1,_("Reading package lists"));
723 /* At this point we know we need to reconstruct the package cache,
726 SPtr
<DynamicMMap
> Map
;
727 if (Writeable
== true && CacheFile
.empty() == false)
729 unlink(CacheFile
.c_str());
730 CacheF
= new FileFd(CacheFile
,FileFd::WriteEmpty
);
731 fchmod(CacheF
->Fd(),0644);
732 Map
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
);
733 if (_error
->PendingError() == true)
738 // Just build it in memory..
739 Map
= new DynamicMMap(MMap::Public
,MapSize
);
742 // Lets try the source cache.
743 unsigned long CurrentSize
= 0;
744 unsigned long TotalSize
= 0;
745 if (CheckValidity(SrcCacheFile
,Files
.begin(),
746 Files
.begin()+EndOfSource
) == true)
748 // Preload the map with the source cache
749 FileFd
SCacheF(SrcCacheFile
,FileFd::ReadOnly
);
750 if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()),
751 SCacheF
.Size()) == false)
754 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
756 // Build the status cache
757 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
758 if (_error
->PendingError() == true)
760 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
761 Files
.begin()+EndOfSource
,Files
.end()) == false)
766 TotalSize
= ComputeSize(Files
.begin(),Files
.end());
768 // Build the source cache
769 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
770 if (_error
->PendingError() == true)
772 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
773 Files
.begin(),Files
.begin()+EndOfSource
) == false)
777 if (Writeable
== true && SrcCacheFile
.empty() == false)
779 FileFd
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
);
780 if (_error
->PendingError() == true)
783 fchmod(SCacheF
.Fd(),0644);
785 // Write out the main data
786 if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false)
787 return _error
->Error(_("IO Error saving source cache"));
790 // Write out the proper header
791 Gen
.GetCache().HeaderP
->Dirty
= false;
792 if (SCacheF
.Seek(0) == false ||
793 SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false)
794 return _error
->Error(_("IO Error saving source cache"));
795 Gen
.GetCache().HeaderP
->Dirty
= true;
799 // Build the status cache
800 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
801 Files
.begin()+EndOfSource
,Files
.end()) == false)
805 if (_error
->PendingError() == true)
811 delete Map
.UnGuard();
812 *OutMap
= new MMap(*CacheF
,MMap::Public
| MMap::ReadOnly
);
816 *OutMap
= Map
.UnGuard();
823 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
824 // ---------------------------------------------------------------------
826 bool pkgMakeOnlyStatusCache(OpProgress
&Progress
,DynamicMMap
**OutMap
)
828 unsigned long MapSize
= _config
->FindI("APT::Cache-Limit",8*1024*1024);
829 vector
<pkgIndexFile
*> Files
;
830 unsigned long EndOfSource
= Files
.size();
831 if (_system
->AddStatusFiles(Files
) == false)
834 SPtr
<DynamicMMap
> Map
;
835 Map
= new DynamicMMap(MMap::Public
,MapSize
);
836 unsigned long CurrentSize
= 0;
837 unsigned long TotalSize
= 0;
839 TotalSize
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end());
841 // Build the status cache
842 Progress
.OverallProgress(0,1,1,_("Reading package lists"));
843 pkgCacheGenerator
Gen(Map
.Get(),&Progress
);
844 if (_error
->PendingError() == true)
846 if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
,
847 Files
.begin()+EndOfSource
,Files
.end()) == false)
850 if (_error
->PendingError() == true)
852 *OutMap
= Map
.UnGuard();