]>
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();