]>
git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
7833d6476645e905820d5d00c4a0ba3886df41f1
   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> 
  25 #include <apt-pkg/tagfile.h> 
  37 typedef vector
<pkgIndexFile 
*>::iterator FileIterator
; 
  39 // CacheGenerator::pkgCacheGenerator - Constructor                      /*{{{*/ 
  40 // --------------------------------------------------------------------- 
  41 /* We set the diry flag and make sure that is written to the disk */ 
  42 pkgCacheGenerator::pkgCacheGenerator(DynamicMMap 
*pMap
,OpProgress 
*Prog
) : 
  43                     Map(*pMap
), Cache(pMap
,false), Progress(Prog
), 
  47    memset(UniqHash
,0,sizeof(UniqHash
)); 
  49    if (_error
->PendingError() == true) 
  54       // Setup the map interface.. 
  55       Cache
.HeaderP 
= (pkgCache::Header 
*)Map
.Data(); 
  56       Map
.RawAllocate(sizeof(pkgCache::Header
)); 
  57       Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0])); 
  60       *Cache
.HeaderP 
= pkgCache::Header(); 
  61       Cache
.HeaderP
->VerSysName 
= Map
.WriteString(_system
->VS
->Label
); 
  62       Cache
.HeaderP
->Architecture 
= Map
.WriteString(_config
->Find("APT::Architecture")); 
  67       // Map directly from the existing file 
  69       Map
.UsePools(*Cache
.HeaderP
->Pools
,sizeof(Cache
.HeaderP
->Pools
)/sizeof(Cache
.HeaderP
->Pools
[0])); 
  70       if (Cache
.VS 
!= _system
->VS
) 
  72          _error
->Error(_("Cache has an incompatible versioning system")); 
  77    Cache
.HeaderP
->Dirty 
= true; 
  78    Map
.Sync(0,sizeof(pkgCache::Header
)); 
  81 // CacheGenerator::~pkgCacheGenerator - Destructor                      /*{{{*/ 
  82 // --------------------------------------------------------------------- 
  83 /* We sync the data then unset the dirty flag in two steps so as to 
  84    advoid a problem during a crash */ 
  85 pkgCacheGenerator::~pkgCacheGenerator() 
  87    if (_error
->PendingError() == true) 
  89    if (Map
.Sync() == false) 
  92    Cache
.HeaderP
->Dirty 
= false; 
  93    Map
.Sync(0,sizeof(pkgCache::Header
)); 
  96 // CacheGenerator::MergeList - Merge the package list                   /*{{{*/ 
  97 // --------------------------------------------------------------------- 
  98 /* This provides the generation of the entries in the cache. Each loop 
  99    goes through a single package record from the underlying parse engine. */ 
 100 bool pkgCacheGenerator::MergeList(ListParser 
&List
, 
 101                                   pkgCache::VerIterator 
*OutVer
) 
 105    unsigned int Counter 
= 0; 
 106    while (List
.Step() == true) 
 108       // Get a pointer to the package structure 
 109       string PackageName 
= List
.Package(); 
 110       if (PackageName
.empty() == true) 
 113       pkgCache::PkgIterator Pkg
; 
 114       if (NewPackage(Pkg
,PackageName
) == false) 
 115          return _error
->Error(_("Error occurred while processing %s (NewPackage)"),PackageName
.c_str()); 
 117       if (Counter 
% 100 == 0 && Progress 
!= 0) 
 118          Progress
->Progress(List
.Offset()); 
 120       /* Get a pointer to the version structure. We know the list is sorted 
 121          so we use that fact in the search. Insertion of new versions is 
 122          done with correct sorting */ 
 123       string Version 
= List
.Version(); 
 124       if (Version
.empty() == true) 
 126          // we first process the package, then the descriptions 
 127          // (this has the bonus that we get MMap error when we run out 
 129          if (List
.UsePackage(Pkg
,pkgCache::VerIterator(Cache
)) == false) 
 130             return _error
->Error(_("Error occurred while processing %s (UsePackage1)"), 
 131                                  PackageName
.c_str()); 
 133          // Find the right version to write the description 
 134          MD5SumValue CurMd5 
= List
.Description_md5(); 
 135          pkgCache::VerIterator Ver 
= Pkg
.VersionList(); 
 136          map_ptrloc 
*LastVer 
= &Pkg
->VersionList
; 
 138          for (; Ver
.end() == false; LastVer 
= &Ver
->NextVer
, Ver
++)  
 140             pkgCache::DescIterator Desc 
= Ver
.DescriptionList(); 
 141             map_ptrloc 
*LastDesc 
= &Ver
->DescriptionList
; 
 142             bool duplicate
=false; 
 144             // don't add a new description if we have one for the given 
 146             for ( ; Desc
.end() == false; Desc
++) 
 147                if (MD5SumValue(Desc
.md5()) == CurMd5 
&&  
 148                    Desc
.LanguageCode() == List
.DescriptionLanguage()) 
 153             for (Desc 
= Ver
.DescriptionList(); 
 155                  LastDesc 
= &Desc
->NextDesc
, Desc
++) 
 157                if (MD5SumValue(Desc
.md5()) == CurMd5
)  
 159                   // Add new description 
 160                   *LastDesc 
= NewDescription(Desc
, List
.DescriptionLanguage(), CurMd5
, *LastDesc
); 
 161                   Desc
->ParentPkg 
= Pkg
.Index(); 
 163                   if (NewFileDesc(Desc
,List
) == false) 
 164                      return _error
->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName
.c_str()); 
 173       pkgCache::VerIterator Ver 
= Pkg
.VersionList(); 
 174       map_ptrloc 
*LastVer 
= &Pkg
->VersionList
; 
 176       for (; Ver
.end() == false; LastVer 
= &Ver
->NextVer
, Ver
++) 
 178          Res 
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr()); 
 183       /* We already have a version for this item, record that we 
 185       unsigned long Hash 
= List
.VersionHash(); 
 186       if (Res 
== 0 && Ver
->Hash 
== Hash
) 
 188          if (List
.UsePackage(Pkg
,Ver
) == false) 
 189             return _error
->Error(_("Error occurred while processing %s (UsePackage2)"), 
 190                                  PackageName
.c_str()); 
 192          if (NewFileVer(Ver
,List
) == false) 
 193             return _error
->Error(_("Error occurred while processing %s (NewFileVer1)"), 
 194                                  PackageName
.c_str()); 
 196          // Read only a single record and return 
 200             FoundFileDeps 
|= List
.HasFileDeps(); 
 207       // Skip to the end of the same version set. 
 210          for (; Ver
.end() == false; LastVer 
= &Ver
->NextVer
, Ver
++) 
 212             Res 
= Cache
.VS
->CmpVersion(Version
,Ver
.VerStr()); 
 219       *LastVer 
= NewVersion(Ver
,Version
,*LastVer
); 
 220       Ver
->ParentPkg 
= Pkg
.Index(); 
 223       if (List
.NewVersion(Ver
) == false) 
 224          return _error
->Error(_("Error occurred while processing %s (NewVersion1)"), 
 225                               PackageName
.c_str()); 
 227       if (List
.UsePackage(Pkg
,Ver
) == false) 
 228          return _error
->Error(_("Error occurred while processing %s (UsePackage3)"), 
 229                               PackageName
.c_str()); 
 231       if (NewFileVer(Ver
,List
) == false) 
 232          return _error
->Error(_("Error occurred while processing %s (NewVersion2)"), 
 233                               PackageName
.c_str()); 
 235       // Read only a single record and return 
 239          FoundFileDeps 
|= List
.HasFileDeps(); 
 243       /* Record the Description data. Description data always exist in 
 244          Packages and Translation-* files. */ 
 245       pkgCache::DescIterator Desc 
= Ver
.DescriptionList(); 
 246       map_ptrloc 
*LastDesc 
= &Ver
->DescriptionList
; 
 248       // Skip to the end of description set 
 249       for (; Desc
.end() == false; LastDesc 
= &Desc
->NextDesc
, Desc
++); 
 251       // Add new description 
 252       *LastDesc 
= NewDescription(Desc
, List
.DescriptionLanguage(), List
.Description_md5(), *LastDesc
); 
 253       Desc
->ParentPkg 
= Pkg
.Index(); 
 255       if (NewFileDesc(Desc
,List
) == false) 
 256          return _error
->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName
.c_str()); 
 259    FoundFileDeps 
|= List
.HasFileDeps(); 
 261    if (Cache
.HeaderP
->PackageCount 
>= (1ULL<<sizeof(Cache
.PkgP
->ID
)*8)-1) 
 262       return _error
->Error(_("Wow, you exceeded the number of package " 
 263                              "names this APT is capable of.")); 
 264    if (Cache
.HeaderP
->VersionCount 
>= (1ULL<<(sizeof(Cache
.VerP
->ID
)*8))-1) 
 265       return _error
->Error(_("Wow, you exceeded the number of versions " 
 266                              "this APT is capable of.")); 
 267    if (Cache
.HeaderP
->DescriptionCount 
>= (1ULL<<(sizeof(Cache
.DescP
->ID
)*8))-1) 
 268       return _error
->Error(_("Wow, you exceeded the number of descriptions " 
 269                              "this APT is capable of.")); 
 270    if (Cache
.HeaderP
->DependsCount 
>= (1ULL<<(sizeof(Cache
.DepP
->ID
)*8))-1ULL) 
 271       return _error
->Error(_("Wow, you exceeded the number of dependencies " 
 272                              "this APT is capable of.")); 
 276 // CacheGenerator::MergeFileProvides - Merge file provides              /*{{{*/ 
 277 // --------------------------------------------------------------------- 
 278 /* If we found any file depends while parsing the main list we need to  
 279    resolve them. Since it is undesired to load the entire list of files 
 280    into the cache as virtual packages we do a two stage effort. MergeList 
 281    identifies the file depends and this creates Provdies for them by 
 282    re-parsing all the indexs. */ 
 283 bool pkgCacheGenerator::MergeFileProvides(ListParser 
&List
) 
 287    unsigned int Counter 
= 0; 
 288    while (List
.Step() == true) 
 290       string PackageName 
= List
.Package(); 
 291       if (PackageName
.empty() == true) 
 293       string Version 
= List
.Version(); 
 294       if (Version
.empty() == true) 
 297       pkgCache::PkgIterator Pkg 
= Cache
.FindPkg(PackageName
); 
 298       if (Pkg
.end() == true) 
 299          return _error
->Error(_("Error occurred while processing %s (FindPkg)"), 
 300                                 PackageName
.c_str()); 
 302       if (Counter 
% 100 == 0 && Progress 
!= 0) 
 303          Progress
->Progress(List
.Offset()); 
 305       unsigned long Hash 
= List
.VersionHash(); 
 306       pkgCache::VerIterator Ver 
= Pkg
.VersionList(); 
 307       for (; Ver
.end() == false; Ver
++) 
 309          if (Ver
->Hash 
== Hash 
&& Version
.c_str() == Ver
.VerStr()) 
 311             if (List
.CollectFileProvides(Cache
,Ver
) == false) 
 312                return _error
->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName
.c_str()); 
 317       if (Ver
.end() == true) 
 318          _error
->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName
.c_str(),Version
.c_str()); 
 324 // CacheGenerator::NewPackage - Add a new package                       /*{{{*/ 
 325 // --------------------------------------------------------------------- 
 326 /* This creates a new package structure and adds it to the hash table */ 
 327 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator 
&Pkg
,const string 
&Name
) 
 329    Pkg 
= Cache
.FindPkg(Name
); 
 330    if (Pkg
.end() == false) 
 334    unsigned long Package 
= Map
.Allocate(sizeof(pkgCache::Package
)); 
 338    Pkg 
= pkgCache::PkgIterator(Cache
,Cache
.PkgP 
+ Package
); 
 340    // Insert it into the hash table 
 341    unsigned long Hash 
= Cache
.Hash(Name
); 
 342    Pkg
->NextPackage 
= Cache
.HeaderP
->HashTable
[Hash
]; 
 343    Cache
.HeaderP
->HashTable
[Hash
] = Package
; 
 345    // Set the name and the ID 
 346    Pkg
->Name 
= Map
.WriteString(Name
); 
 349    Pkg
->ID 
= Cache
.HeaderP
->PackageCount
++; 
 354 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/ 
 355 // --------------------------------------------------------------------- 
 357 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator 
&Ver
, 
 360    if (CurrentFile 
== 0) 
 364    unsigned long VerFile 
= Map
.Allocate(sizeof(pkgCache::VerFile
)); 
 368    pkgCache::VerFileIterator 
VF(Cache
,Cache
.VerFileP 
+ VerFile
); 
 369    VF
->File 
= CurrentFile 
- Cache
.PkgFileP
; 
 371    // Link it to the end of the list 
 372    map_ptrloc 
*Last 
= &Ver
->FileList
; 
 373    for (pkgCache::VerFileIterator V 
= Ver
.FileList(); V
.end() == false; V
++) 
 375    VF
->NextFile 
= *Last
; 
 378    VF
->Offset 
= List
.Offset(); 
 379    VF
->Size 
= List
.Size(); 
 380    if (Cache
.HeaderP
->MaxVerFileSize 
< VF
->Size
) 
 381       Cache
.HeaderP
->MaxVerFileSize 
= VF
->Size
; 
 382    Cache
.HeaderP
->VerFileCount
++; 
 387 // CacheGenerator::NewVersion - Create a new Version                    /*{{{*/ 
 388 // --------------------------------------------------------------------- 
 389 /* This puts a version structure in the linked list */ 
 390 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator 
&Ver
, 
 391                                             const string 
&VerStr
, 
 395    unsigned long Version 
= Map
.Allocate(sizeof(pkgCache::Version
)); 
 400    Ver 
= pkgCache::VerIterator(Cache
,Cache
.VerP 
+ Version
); 
 402    Ver
->ID 
= Cache
.HeaderP
->VersionCount
++; 
 403    Ver
->VerStr 
= Map
.WriteString(VerStr
); 
 404    if (Ver
->VerStr 
== 0) 
 410 // CacheGenerator::NewFileDesc - Create a new File<->Desc association   /*{{{*/ 
 411 // --------------------------------------------------------------------- 
 413 bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator 
&Desc
, 
 416    if (CurrentFile 
== 0) 
 420    unsigned long DescFile 
= Map
.Allocate(sizeof(pkgCache::DescFile
)); 
 424    pkgCache::DescFileIterator 
DF(Cache
,Cache
.DescFileP 
+ DescFile
); 
 425    DF
->File 
= CurrentFile 
- Cache
.PkgFileP
; 
 427    // Link it to the end of the list 
 428    map_ptrloc 
*Last 
= &Desc
->FileList
; 
 429    for (pkgCache::DescFileIterator D 
= Desc
.FileList(); D
.end() == false; D
++) 
 432    DF
->NextFile 
= *Last
; 
 435    DF
->Offset 
= List
.Offset(); 
 436    DF
->Size 
= List
.Size(); 
 437    if (Cache
.HeaderP
->MaxDescFileSize 
< DF
->Size
) 
 438       Cache
.HeaderP
->MaxDescFileSize 
= DF
->Size
; 
 439    Cache
.HeaderP
->DescFileCount
++; 
 444 // CacheGenerator::NewDescription - Create a new Description            /*{{{*/ 
 445 // --------------------------------------------------------------------- 
 446 /* This puts a description structure in the linked list */ 
 447 map_ptrloc 
pkgCacheGenerator::NewDescription(pkgCache::DescIterator 
&Desc
, 
 449                                             const MD5SumValue 
&md5sum
, 
 453    map_ptrloc Description 
= Map
.Allocate(sizeof(pkgCache::Description
)); 
 454    if (Description 
== 0) 
 458    Desc 
= pkgCache::DescIterator(Cache
,Cache
.DescP 
+ Description
); 
 459    Desc
->NextDesc 
= Next
; 
 460    Desc
->ID 
= Cache
.HeaderP
->DescriptionCount
++; 
 461    Desc
->language_code 
= Map
.WriteString(Lang
); 
 462    Desc
->md5sum 
= Map
.WriteString(md5sum
.Value()); 
 467 // ListParser::NewDepends - Create a dependency element                 /*{{{*/ 
 468 // --------------------------------------------------------------------- 
 469 /* This creates a dependency element in the tree. It is linked to the 
 470    version and to the package that it is pointing to. */ 
 471 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver
, 
 472                                                const string 
&PackageName
, 
 473                                                const string 
&Version
, 
 477    pkgCache 
&Cache 
= Owner
->Cache
; 
 480    unsigned long Dependency 
= Owner
->Map
.Allocate(sizeof(pkgCache::Dependency
)); 
 485    pkgCache::DepIterator 
Dep(Cache
,Cache
.DepP 
+ Dependency
); 
 486    Dep
->ParentVer 
= Ver
.Index(); 
 489    Dep
->ID 
= Cache
.HeaderP
->DependsCount
++; 
 491    // Locate the target package 
 492    pkgCache::PkgIterator Pkg
; 
 493    if (Owner
->NewPackage(Pkg
,PackageName
) == false) 
 496    // Probe the reverse dependency list for a version string that matches 
 497    if (Version
.empty() == false) 
 499 /*      for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++) 
 500          if (I->Version != 0 && I.TargetVer() == Version) 
 501             Dep->Version = I->Version;*/ 
 502       if (Dep
->Version 
== 0) 
 503          if ((Dep
->Version 
= WriteString(Version
)) == 0) 
 507    // Link it to the package 
 508    Dep
->Package 
= Pkg
.Index(); 
 509    Dep
->NextRevDepends 
= Pkg
->RevDepends
; 
 510    Pkg
->RevDepends 
= Dep
.Index(); 
 512    /* Link it to the version (at the end of the list) 
 513       Caching the old end point speeds up generation substantially */ 
 514    if (OldDepVer 
!= Ver
) 
 516       OldDepLast 
= &Ver
->DependsList
; 
 517       for (pkgCache::DepIterator D 
= Ver
.DependsList(); D
.end() == false; D
++) 
 518          OldDepLast 
= &D
->NextDepends
; 
 522    // Is it a file dependency? 
 523    if (PackageName
[0] == '/') 
 524       FoundFileDeps 
= true; 
 526    Dep
->NextDepends 
= *OldDepLast
; 
 527    *OldDepLast 
= Dep
.Index(); 
 528    OldDepLast 
= &Dep
->NextDepends
; 
 533 // ListParser::NewProvides - Create a Provides element                  /*{{{*/ 
 534 // --------------------------------------------------------------------- 
 536 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver
, 
 537                                                 const string 
&PackageName
, 
 538                                                 const string 
&Version
) 
 540    pkgCache 
&Cache 
= Owner
->Cache
; 
 542    // We do not add self referencing provides 
 543    if (Ver
.ParentPkg().Name() == PackageName
) 
 547    unsigned long Provides 
= Owner
->Map
.Allocate(sizeof(pkgCache::Provides
)); 
 550    Cache
.HeaderP
->ProvidesCount
++; 
 553    pkgCache::PrvIterator 
Prv(Cache
,Cache
.ProvideP 
+ Provides
,Cache
.PkgP
); 
 554    Prv
->Version 
= Ver
.Index(); 
 555    Prv
->NextPkgProv 
= Ver
->ProvidesList
; 
 556    Ver
->ProvidesList 
= Prv
.Index(); 
 557    if (Version
.empty() == false && (Prv
->ProvideVersion 
= WriteString(Version
)) == 0) 
 560    // Locate the target package 
 561    pkgCache::PkgIterator Pkg
; 
 562    if (Owner
->NewPackage(Pkg
,PackageName
) == false) 
 565    // Link it to the package 
 566    Prv
->ParentPkg 
= Pkg
.Index(); 
 567    Prv
->NextProvides 
= Pkg
->ProvidesList
; 
 568    Pkg
->ProvidesList 
= Prv
.Index(); 
 573 // CacheGenerator::SelectFile - Select the current file being parsed    /*{{{*/ 
 574 // --------------------------------------------------------------------- 
 575 /* This is used to select which file is to be associated with all newly 
 576    added versions. The caller is responsible for setting the IMS fields. */ 
 577 bool pkgCacheGenerator::SelectFile(const string 
&File
,const string 
&Site
, 
 578                                    const pkgIndexFile 
&Index
, 
 581    // Get some space for the structure 
 582    CurrentFile 
= Cache
.PkgFileP 
+ Map
.Allocate(sizeof(*CurrentFile
)); 
 583    if (CurrentFile 
== Cache
.PkgFileP
) 
 587    CurrentFile
->FileName 
= Map
.WriteString(File
); 
 588    CurrentFile
->Site 
= WriteUniqString(Site
); 
 589    CurrentFile
->NextFile 
= Cache
.HeaderP
->FileList
; 
 590    CurrentFile
->Flags 
= Flags
; 
 591    CurrentFile
->ID 
= Cache
.HeaderP
->PackageFileCount
; 
 592    CurrentFile
->IndexType 
= WriteUniqString(Index
.GetType()->Label
); 
 594    Cache
.HeaderP
->FileList 
= CurrentFile 
- Cache
.PkgFileP
; 
 595    Cache
.HeaderP
->PackageFileCount
++; 
 597    if (CurrentFile
->FileName 
== 0) 
 601       Progress
->SubProgress(Index
.Size()); 
 605 // CacheGenerator::WriteUniqueString - Insert a unique string           /*{{{*/ 
 606 // --------------------------------------------------------------------- 
 607 /* This is used to create handles to strings. Given the same text it 
 608    always returns the same number */ 
 609 unsigned long pkgCacheGenerator::WriteUniqString(const char *S
, 
 612    /* We use a very small transient hash table here, this speeds up generation 
 613       by a fair amount on slower machines */ 
 614    pkgCache::StringItem 
*&Bucket 
= UniqHash
[(S
[0]*5 + S
[1]) % _count(UniqHash
)]; 
 616        stringcmp(S
,S
+Size
,Cache
.StrP 
+ Bucket
->String
) == 0) 
 617       return Bucket
->String
; 
 619    // Search for an insertion point 
 620    pkgCache::StringItem 
*I 
= Cache
.StringItemP 
+ Cache
.HeaderP
->StringList
; 
 622    map_ptrloc 
*Last 
= &Cache
.HeaderP
->StringList
; 
 623    for (; I 
!= Cache
.StringItemP
; Last 
= &I
->NextItem
,  
 624         I 
= Cache
.StringItemP 
+ I
->NextItem
) 
 626       Res 
= stringcmp(S
,S
+Size
,Cache
.StrP 
+ I
->String
); 
 639    unsigned long Item 
= Map
.Allocate(sizeof(pkgCache::StringItem
)); 
 643    // Fill in the structure 
 644    pkgCache::StringItem 
*ItemP 
= Cache
.StringItemP 
+ Item
; 
 645    ItemP
->NextItem 
= I 
- Cache
.StringItemP
; 
 647    ItemP
->String 
= Map
.WriteString(S
,Size
); 
 648    if (ItemP
->String 
== 0) 
 652    return ItemP
->String
; 
 655 // CheckValidity - Check that a cache is up-to-date                     /*{{{*/ 
 656 // --------------------------------------------------------------------- 
 657 /* This just verifies that each file in the list of index files exists, 
 658    has matching attributes with the cache and the cache does not have 
 660 static bool CheckValidity(const string 
&CacheFile
, FileIterator Start
,  
 661                           FileIterator End
,MMap 
**OutMap 
= 0) 
 663    // No file, certainly invalid 
 664    if (CacheFile
.empty() == true || FileExists(CacheFile
) == false) 
 668    FileFd 
CacheF(CacheFile
,FileFd::ReadOnly
); 
 669    SPtr
<MMap
> Map 
= new MMap(CacheF
,MMap::Public 
| MMap::ReadOnly
); 
 671    if (_error
->PendingError() == true || Map
->Size() == 0) 
 677    /* Now we check every index file, see if it is in the cache, 
 678       verify the IMS data and check that it is on the disk too.. */ 
 679    SPtrArray
<bool> Visited 
= new bool[Cache
.HeaderP
->PackageFileCount
]; 
 680    memset(Visited
,0,sizeof(*Visited
)*Cache
.HeaderP
->PackageFileCount
); 
 681    for (; Start 
!= End
; Start
++) 
 683       if ((*Start
)->HasPackages() == false) 
 686       if ((*Start
)->Exists() == false) 
 688 #if 0 // mvo: we no longer give a message here (Default Sources spec) 
 689          _error
->WarningE("stat",_("Couldn't stat source package list %s"), 
 690                           (*Start
)->Describe().c_str()); 
 695       // FindInCache is also expected to do an IMS check. 
 696       pkgCache::PkgFileIterator File 
= (*Start
)->FindInCache(Cache
); 
 697       if (File
.end() == true) 
 700       Visited
[File
->ID
] = true; 
 703    for (unsigned I 
= 0; I 
!= Cache
.HeaderP
->PackageFileCount
; I
++) 
 704       if (Visited
[I
] == false) 
 707    if (_error
->PendingError() == true) 
 714       *OutMap 
= Map
.UnGuard(); 
 718 // ComputeSize - Compute the total size of a bunch of files             /*{{{*/ 
 719 // --------------------------------------------------------------------- 
 720 /* Size is kind of an abstract notion that is only used for the progress 
 722 static unsigned long ComputeSize(FileIterator Start
,FileIterator End
) 
 724    unsigned long TotalSize 
= 0; 
 725    for (; Start 
!= End
; Start
++) 
 727       if ((*Start
)->HasPackages() == false) 
 729       TotalSize 
+= (*Start
)->Size(); 
 734 // BuildCache - Merge the list of index files into the cache            /*{{{*/ 
 735 // --------------------------------------------------------------------- 
 737 static bool BuildCache(pkgCacheGenerator 
&Gen
, 
 738                        OpProgress 
&Progress
, 
 739                        unsigned long &CurrentSize
,unsigned long TotalSize
, 
 740                        FileIterator Start
, FileIterator End
) 
 743    for (I 
= Start
; I 
!= End
; I
++) 
 745       if ((*I
)->HasPackages() == false) 
 748       if ((*I
)->Exists() == false) 
 751       if ((*I
)->FindInCache(Gen
.GetCache()).end() == false) 
 753          _error
->Warning("Duplicate sources.list entry %s", 
 754                          (*I
)->Describe().c_str()); 
 758       unsigned long Size 
= (*I
)->Size(); 
 759       Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Reading package lists")); 
 762       if ((*I
)->Merge(Gen
,Progress
) == false) 
 766    if (Gen
.HasFileDeps() == true) 
 769       TotalSize 
= ComputeSize(Start
, End
); 
 771       for (I 
= Start
; I 
!= End
; I
++) 
 773          unsigned long Size 
= (*I
)->Size(); 
 774          Progress
.OverallProgress(CurrentSize
,TotalSize
,Size
,_("Collecting File Provides")); 
 776          if ((*I
)->MergeFileProvides(Gen
,Progress
) == false) 
 784 // MakeStatusCache - Construct the status cache                         /*{{{*/ 
 785 // --------------------------------------------------------------------- 
 786 /* This makes sure that the status cache (the cache that has all  
 787    index files from the sources list and all local ones) is ready 
 788    to be mmaped. If OutMap is not zero then a MMap object representing 
 789    the cache will be stored there. This is pretty much mandetory if you 
 790    are using AllowMem. AllowMem lets the function be run as non-root 
 791    where it builds the cache 'fast' into a memory buffer. */ 
 792 bool pkgMakeStatusCache(pkgSourceList 
&List
,OpProgress 
&Progress
, 
 793                         MMap 
**OutMap
,bool AllowMem
) 
 795    unsigned long MapSize 
= _config
->FindI("APT::Cache-Limit",24*1024*1024); 
 797    vector
<pkgIndexFile 
*> Files
; 
 798    for (vector
<metaIndex 
*>::const_iterator i 
= List
.begin(); 
 802       vector 
<pkgIndexFile 
*> *Indexes 
= (*i
)->GetIndexFiles(); 
 803       for (vector
<pkgIndexFile 
*>::const_iterator j 
= Indexes
->begin(); 
 806          Files
.push_back (*j
); 
 809    unsigned long EndOfSource 
= Files
.size(); 
 810    if (_system
->AddStatusFiles(Files
) == false) 
 813    // Decide if we can write to the files.. 
 814    string CacheFile 
= _config
->FindFile("Dir::Cache::pkgcache"); 
 815    string SrcCacheFile 
= _config
->FindFile("Dir::Cache::srcpkgcache"); 
 817    // Decide if we can write to the cache 
 818    bool Writeable 
= false; 
 819    if (CacheFile
.empty() == false) 
 820       Writeable 
= access(flNotFile(CacheFile
).c_str(),W_OK
) == 0; 
 822       if (SrcCacheFile
.empty() == false) 
 823          Writeable 
= access(flNotFile(SrcCacheFile
).c_str(),W_OK
) == 0; 
 825    if (Writeable 
== false && AllowMem 
== false && CacheFile
.empty() == false) 
 826       return _error
->Error(_("Unable to write to %s"),flNotFile(CacheFile
).c_str()); 
 828    Progress
.OverallProgress(0,1,1,_("Reading package lists")); 
 831    if (CheckValidity(CacheFile
,Files
.begin(),Files
.end(),OutMap
) == true) 
 833       Progress
.OverallProgress(1,1,1,_("Reading package lists")); 
 837    /* At this point we know we need to reconstruct the package cache, 
 840    SPtr
<DynamicMMap
> Map
; 
 841    if (Writeable 
== true && CacheFile
.empty() == false) 
 843       unlink(CacheFile
.c_str()); 
 844       CacheF 
= new FileFd(CacheFile
,FileFd::WriteEmpty
); 
 845       fchmod(CacheF
->Fd(),0644); 
 846       Map 
= new DynamicMMap(*CacheF
,MMap::Public
,MapSize
); 
 847       if (_error
->PendingError() == true) 
 852       // Just build it in memory.. 
 853       Map 
= new DynamicMMap(MMap::Public
,MapSize
); 
 856    // Lets try the source cache. 
 857    unsigned long CurrentSize 
= 0; 
 858    unsigned long TotalSize 
= 0; 
 859    if (CheckValidity(SrcCacheFile
,Files
.begin(), 
 860                      Files
.begin()+EndOfSource
) == true) 
 862       // Preload the map with the source cache 
 863       FileFd 
SCacheF(SrcCacheFile
,FileFd::ReadOnly
); 
 864       if (SCacheF
.Read((unsigned char *)Map
->Data() + Map
->RawAllocate(SCacheF
.Size()), 
 865                        SCacheF
.Size()) == false) 
 868       TotalSize 
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end()); 
 870       // Build the status cache 
 871       pkgCacheGenerator 
Gen(Map
.Get(),&Progress
); 
 872       if (_error
->PendingError() == true) 
 874       if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, 
 875                      Files
.begin()+EndOfSource
,Files
.end()) == false) 
 880       TotalSize 
= ComputeSize(Files
.begin(),Files
.end()); 
 882       // Build the source cache 
 883       pkgCacheGenerator 
Gen(Map
.Get(),&Progress
); 
 884       if (_error
->PendingError() == true) 
 886       if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, 
 887                      Files
.begin(),Files
.begin()+EndOfSource
) == false) 
 891       if (Writeable 
== true && SrcCacheFile
.empty() == false) 
 893          FileFd 
SCacheF(SrcCacheFile
,FileFd::WriteEmpty
); 
 894          if (_error
->PendingError() == true) 
 897          fchmod(SCacheF
.Fd(),0644); 
 899          // Write out the main data 
 900          if (SCacheF
.Write(Map
->Data(),Map
->Size()) == false) 
 901             return _error
->Error(_("IO Error saving source cache")); 
 904          // Write out the proper header 
 905          Gen
.GetCache().HeaderP
->Dirty 
= false; 
 906          if (SCacheF
.Seek(0) == false || 
 907              SCacheF
.Write(Map
->Data(),sizeof(*Gen
.GetCache().HeaderP
)) == false) 
 908             return _error
->Error(_("IO Error saving source cache")); 
 909          Gen
.GetCache().HeaderP
->Dirty 
= true; 
 913       // Build the status cache 
 914       if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, 
 915                      Files
.begin()+EndOfSource
,Files
.end()) == false) 
 919    if (_error
->PendingError() == true) 
 925          delete Map
.UnGuard(); 
 926          *OutMap 
= new MMap(*CacheF
,MMap::Public 
| MMap::ReadOnly
); 
 930          *OutMap 
= Map
.UnGuard(); 
 937 // MakeOnlyStatusCache - Build a cache with just the status files       /*{{{*/ 
 938 // --------------------------------------------------------------------- 
 940 bool pkgMakeOnlyStatusCache(OpProgress 
&Progress
,DynamicMMap 
**OutMap
) 
 942    unsigned long MapSize 
= _config
->FindI("APT::Cache-Limit",20*1024*1024); 
 943    vector
<pkgIndexFile 
*> Files
; 
 944    unsigned long EndOfSource 
= Files
.size(); 
 945    if (_system
->AddStatusFiles(Files
) == false) 
 948    SPtr
<DynamicMMap
> Map
;    
 949    Map 
= new DynamicMMap(MMap::Public
,MapSize
); 
 950    unsigned long CurrentSize 
= 0; 
 951    unsigned long TotalSize 
= 0; 
 953    TotalSize 
= ComputeSize(Files
.begin()+EndOfSource
,Files
.end()); 
 955    // Build the status cache 
 956    Progress
.OverallProgress(0,1,1,_("Reading package lists")); 
 957    pkgCacheGenerator 
Gen(Map
.Get(),&Progress
); 
 958    if (_error
->PendingError() == true) 
 960    if (BuildCache(Gen
,Progress
,CurrentSize
,TotalSize
, 
 961                   Files
.begin()+EndOfSource
,Files
.end()) == false) 
 964    if (_error
->PendingError() == true) 
 966    *OutMap 
= Map
.UnGuard();