446
// SrcCacheCheck - Check if the source package cache is uptodate /*{{{*/
468
// CheckValidity - Check that a cache is up-to-date /*{{{*/
447
469
// ---------------------------------------------------------------------
448
/* The source cache is checked against the source list and the files
449
on disk, any difference results in a false. */
450
bool pkgSrcCacheCheck(pkgSourceList &List)
470
/* This just verifies that each file in the list of index files exists,
471
has matching attributes with the cache and the cache does not have
473
static bool CheckValidity(string CacheFile,pkgIndexFile **Start,
474
pkgIndexFile **End,MMap **OutMap = 0)
452
if (_error->PendingError() == true)
455
string CacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
456
string ListDir = _config->FindDir("Dir::State::lists");
458
// Count the number of missing files
460
for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
462
// Only cache deb source types.
463
if (I->Type != pkgSourceList::Item::Deb)
469
string File = ListDir + URItoFileName(I->PackagesURI());
471
if (stat(File.c_str(),&Buf) != 0)
473
// Old format file name.. rename it
474
if (File[0] == '_' && stat(File.c_str()+1,&Buf) == 0)
476
if (rename(File.c_str()+1,File.c_str()) != 0)
477
return _error->Errno("rename","Failed to rename %s to %s",
478
File.c_str()+1,File.c_str());
482
_error->WarningE("stat","Couldn't stat source package list '%s' (%s)",
483
I->PackagesInfo().c_str(),File.c_str());
488
// Open the source package cache
489
if (FileExists(CacheFile) == false)
476
// No file, certainly invalid
477
if (CacheFile.empty() == true || FileExists(CacheFile) == false)
492
481
FileFd CacheF(CacheFile,FileFd::ReadOnly);
493
if (_error->PendingError() == true)
499
MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
500
if (_error->PendingError() == true || Map.Size() == 0)
482
SPtr<MMap> Map = new MMap(CacheF,MMap::Public | MMap::ReadOnly);
506
483
pkgCache Cache(Map);
507
if (_error->PendingError() == true)
484
if (_error->PendingError() == true || Map->Size() == 0)
509
486
_error->Discard();
513
// They are certianly out of sync
514
if (Cache.Head().PackageFileCount != List.size() - Missing)
517
for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
519
// Search for a match in the source list
521
for (pkgSourceList::const_iterator I = List.begin();
522
I != List.end(); I++)
490
/* Now we check every index file, see if it is in the cache,
491
verify the IMS data and check that it is on the disk too.. */
492
SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
493
memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
494
for (; Start != End; Start++)
496
if ((*Start)->HasPackages() == false)
499
if ((*Start)->Exists() == false)
524
// Only cache deb source types.
525
if (I->Type != pkgSourceList::Item::Deb)
528
string File = ListDir + URItoFileName(I->PackagesURI());
529
if (F.FileName() == File)
501
_error->WarningE("stat",_("Couldn't stat source package list %s"),
502
(*Start)->Describe().c_str());
506
// FindInCache is also expected to do an IMS check.
507
pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
508
if (File.end() == true)
536
// Check if the file matches what was cached
511
Visited[File->ID] = true;
514
for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
515
if (Visited[I] == false)
518
if (_error->PendingError() == true)
525
*OutMap = Map.UnGuard();
545
// PkgCacheCheck - Check if the package cache is uptodate /*{{{*/
546
// ---------------------------------------------------------------------
547
/* This does a simple check of all files used to compose the cache */
548
bool pkgPkgCacheCheck(string CacheFile)
550
if (_error->PendingError() == true)
553
// Open the source package cache
554
if (FileExists(CacheFile) == false)
557
FileFd CacheF(CacheFile,FileFd::ReadOnly);
558
if (_error->PendingError() == true)
564
MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
565
if (_error->PendingError() == true || Map.Size() == 0)
572
if (_error->PendingError() == true)
529
// ComputeSize - Compute the total size of a bunch of files /*{{{*/
530
// ---------------------------------------------------------------------
531
/* Size is kind of an abstract notion that is only used for the progress
533
static unsigned long ComputeSize(pkgIndexFile **Start,pkgIndexFile **End)
535
unsigned long TotalSize = 0;
536
for (; Start != End; Start++)
538
if ((*Start)->HasPackages() == false)
540
TotalSize += (*Start)->Size();
545
// BuildCache - Merge the list of index files into the cache /*{{{*/
546
// ---------------------------------------------------------------------
548
static bool BuildCache(pkgCacheGenerator &Gen,
549
OpProgress &Progress,
550
unsigned long &CurrentSize,unsigned long TotalSize,
551
pkgIndexFile **Start,pkgIndexFile **End)
553
for (; Start != End; Start++)
555
if ((*Start)->HasPackages() == false)
558
if ((*Start)->Exists() == false)
578
// Status files that must be in the cache
580
Status[0] = _config->FindFile("Dir::State::xstatus");
581
Status[1]= _config->FindFile("Dir::State::userstatus");
582
Status[2] = _config->FindFile("Dir::State::status");
585
for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
587
if (F.IsOk() == false)
561
unsigned long Size = (*Start)->Size();
562
Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists"));
590
// See if this is one of the status files
591
for (int I = 0; I != 3; I++)
592
if (F.FileName() == Status[I])
593
Status[I] = string();
596
// Make sure all the status files are loaded.
597
for (int I = 0; I != 3; I++)
599
if (Status[I].empty() == false && FileExists(Status[I]) == true)
565
if ((*Start)->Merge(Gen,Progress) == false)
606
// AddStatusSize - Add the size of the status files /*{{{*/
607
// ---------------------------------------------------------------------
608
/* This adds the size of all the status files to the size counter */
609
bool pkgAddStatusSize(unsigned long &TotalSize)
611
// Grab the file names
612
string xstatus = _config->FindFile("Dir::State::xstatus");
613
string userstatus = _config->FindFile("Dir::State::userstatus");
614
string status = _config->FindFile("Dir::State::status");
618
if (stat(xstatus.c_str(),&Buf) == 0)
619
TotalSize += Buf.st_size;
620
if (stat(userstatus.c_str(),&Buf) == 0)
621
TotalSize += Buf.st_size;
622
if (stat(status.c_str(),&Buf) != 0)
623
return _error->Errno("stat","Couldn't stat the status file %s",status.c_str());
624
TotalSize += Buf.st_size;
629
// MergeStatus - Add the status files to the cache /*{{{*/
630
// ---------------------------------------------------------------------
631
/* This adds the status files to the map */
632
bool pkgMergeStatus(OpProgress &Progress,pkgCacheGenerator &Gen,
633
unsigned long &CurrentSize,unsigned long TotalSize)
635
// Grab the file names
637
Status[0] = _config->FindFile("Dir::State::xstatus");
638
Status[1]= _config->FindFile("Dir::State::userstatus");
639
Status[2] = _config->FindFile("Dir::State::status");
641
for (int I = 0; I != 3; I++)
643
// Check if the file exists and it is not the primary status file.
644
string File = Status[I];
645
if (I != 2 && FileExists(File) == false)
648
FileFd Pkg(File,FileFd::ReadOnly);
649
debListParser Parser(Pkg);
650
Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists");
572
// MakeStatusCache - Construct the status cache /*{{{*/
573
// ---------------------------------------------------------------------
574
/* This makes sure that the status cache (the cache that has all
575
index files from the sources list and all local ones) is ready
576
to be mmaped. If OutMap is not zero then a MMap object representing
577
the cache will be stored there. This is pretty much mandetory if you
578
are using AllowMem. AllowMem lets the function be run as non-root
579
where it builds the cache 'fast' into a memory buffer. */
580
bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
581
MMap **OutMap,bool AllowMem)
583
unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
585
vector<pkgIndexFile *> Files(List.begin(),List.end());
586
unsigned long EndOfSource = Files.size();
587
if (_system->AddStatusFiles(Files) == false)
590
// Decide if we can write to the files..
591
string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
592
string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
594
// Decide if we can write to the cache
595
bool Writeable = false;
596
if (CacheFile.empty() == false)
597
Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
599
if (SrcCacheFile.empty() == false)
600
Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
602
if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
603
return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
605
Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
608
if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
610
Progress.OverallProgress(1,1,1,_("Reading Package Lists"));
614
/* At this point we know we need to reconstruct the package cache,
617
SPtr<DynamicMMap> Map;
618
if (Writeable == true && CacheFile.empty() == false)
620
unlink(CacheFile.c_str());
621
CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
622
Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
651
623
if (_error->PendingError() == true)
652
return _error->Error("Problem opening %s",File.c_str());
653
CurrentSize += Pkg.Size();
628
// Just build it in memory..
629
Map = new DynamicMMap(MMap::Public,MapSize);
632
// Lets try the source cache.
633
unsigned long CurrentSize = 0;
634
unsigned long TotalSize = 0;
635
if (CheckValidity(SrcCacheFile,Files.begin(),
636
Files.begin()+EndOfSource) == true)
638
// Preload the map with the source cache
639
FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
640
if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
641
SCacheF.Size()) == false)
655
Progress.SubProgress(0,"Local Package State - " + flNotDir(File));
656
if (Gen.SelectFile(File,pkgCache::Flag::NotSource) == false)
657
return _error->Error("Problem with SelectFile %s",File.c_str());
659
if (Gen.MergeList(Parser) == false)
660
return _error->Error("Problem with MergeList %s",File.c_str());
661
Progress.Progress(Pkg.Size());
667
// GenerateSrcCache - Write the source package lists to the map /*{{{*/
668
// ---------------------------------------------------------------------
669
/* This puts the source package cache into the given generator. */
670
bool pkgGenerateSrcCache(pkgSourceList &List,OpProgress &Progress,
671
pkgCacheGenerator &Gen,
672
unsigned long &CurrentSize,unsigned long &TotalSize)
674
string ListDir = _config->FindDir("Dir::State::lists");
676
// Prepare the progress indicator
679
for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
681
string File = ListDir + URItoFileName(I->PackagesURI());
682
if (stat(File.c_str(),&Buf) != 0)
684
TotalSize += Buf.st_size;
687
if (pkgAddStatusSize(TotalSize) == false)
690
// Generate the pkg source cache
692
for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
694
// Only cache deb source types.
695
if (I->Type != pkgSourceList::Item::Deb)
698
string File = ListDir + URItoFileName(I->PackagesURI());
700
if (FileExists(File) == false)
703
FileFd Pkg(File,FileFd::ReadOnly);
704
debListParser Parser(Pkg);
705
Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists");
706
if (_error->PendingError() == true)
707
return _error->Error("Problem opening %s",File.c_str());
708
CurrentSize += Pkg.Size();
710
Progress.SubProgress(0,I->PackagesInfo());
711
if (Gen.SelectFile(File) == false)
712
return _error->Error("Problem with SelectFile %s",File.c_str());
714
if (Gen.MergeList(Parser) == false)
715
return _error->Error("Problem with MergeList %s",File.c_str());
717
// Check the release file
718
string RFile = ListDir + URItoFileName(I->ReleaseURI());
719
if (FileExists(RFile) == true)
644
TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
646
// Build the status cache
647
pkgCacheGenerator Gen(Map.Get(),&Progress);
648
if (_error->PendingError() == true)
650
if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
651
Files.begin()+EndOfSource,Files.end()) == false)
656
TotalSize = ComputeSize(Files.begin(),Files.end());
658
// Build the source cache
659
pkgCacheGenerator Gen(Map.Get(),&Progress);
660
if (_error->PendingError() == true)
662
if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
663
Files.begin(),Files.begin()+EndOfSource) == false)
667
if (Writeable == true && SrcCacheFile.empty() == false)
721
FileFd Rel(RFile,FileFd::ReadOnly);
669
FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
722
670
if (_error->PendingError() == true)
724
Parser.LoadReleaseInfo(Gen.GetCurFile(),Rel);
731
// MakeStatusCache - Generates a cache that includes the status files /*{{{*/
732
// ---------------------------------------------------------------------
733
/* This copies the package source cache and then merges the status and
734
xstatus files into it. */
735
bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress)
737
unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
739
Progress.OverallProgress(0,1,1,"Reading Package Lists");
741
string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
742
bool SrcOk = pkgSrcCacheCheck(List);
743
bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
745
// Rebuild the source and package caches
748
string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
749
FileFd SCacheF(SCacheFile,FileFd::WriteEmpty);
751
/* Open the pkgcache, we want a new inode here so we do no corrupt
753
unlink(CacheFile.c_str());
754
FileFd CacheF(CacheFile,FileFd::WriteEmpty);
755
DynamicMMap Map(CacheF,MMap::Public,MapSize);
756
if (_error->PendingError() == true)
759
pkgCacheGenerator Gen(Map,Progress);
760
unsigned long CurrentSize = 0;
761
unsigned long TotalSize = 0;
762
if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
765
// Write the src cache
766
Gen.GetCache().HeaderP->Dirty = false;
767
if (SCacheF.Write(Map.Data(),Map.Size()) == false)
768
return _error->Error("IO Error saving source cache");
769
Gen.GetCache().HeaderP->Dirty = true;
771
// Merge in the source caches
772
return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
777
Progress.OverallProgress(1,1,1,"Reading Package Lists");
781
// We use the source cache to generate the package cache
782
string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
783
FileFd SCacheF(SCacheFile,FileFd::ReadOnly);
785
/* Open the pkgcache, we want a new inode here so we do no corrupt
787
unlink(CacheFile.c_str());
788
FileFd CacheF(CacheFile,FileFd::WriteEmpty);
789
DynamicMMap Map(CacheF,MMap::Public,MapSize);
790
if (_error->PendingError() == true)
793
// Preload the map with the source cache
794
if (SCacheF.Read((unsigned char *)Map.Data() + Map.RawAllocate(SCacheF.Size()),
795
SCacheF.Size()) == false)
798
pkgCacheGenerator Gen(Map,Progress);
800
// Compute the progress
801
unsigned long TotalSize = 0;
802
if (pkgAddStatusSize(TotalSize) == false)
805
unsigned long CurrentSize = 0;
806
return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
809
// MakeStatusCacheMem - Returns a map for the status cache /*{{{*/
810
// ---------------------------------------------------------------------
811
/* This creates a map object for the status cache. If the process has write
812
access to the caches then it is the same as MakeStatusCache, otherwise it
813
creates a memory block and puts the cache in there. */
814
MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress)
816
unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
818
/* If the cache file is writeable this is just a wrapper for
820
string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
821
bool Writeable = (access(CacheFile.c_str(),W_OK) == 0) ||
824
if (Writeable == true)
826
if (pkgMakeStatusCache(List,Progress) == false)
829
// Open the cache file
830
FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
831
if (_error->PendingError() == true)
834
MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
835
if (_error->PendingError() == true)
843
// Mostly from MakeStatusCache..
844
Progress.OverallProgress(0,1,1,"Reading Package Lists");
846
bool SrcOk = pkgSrcCacheCheck(List);
847
bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
849
// Rebuild the source and package caches
852
DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize);
853
if (_error->PendingError() == true)
859
pkgCacheGenerator Gen(*Map,Progress);
860
unsigned long CurrentSize = 0;
861
unsigned long TotalSize = 0;
862
if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
868
// Merge in the source caches
869
if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
880
Progress.OverallProgress(1,1,1,"Reading Package Lists");
882
// Open the cache file
883
FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
884
if (_error->PendingError() == true)
887
MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
888
if (_error->PendingError() == true)
896
// We use the source cache to generate the package cache
897
string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
898
FileFd SCacheF(SCacheFile,FileFd::ReadOnly);
899
DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize);
900
if (_error->PendingError() == true)
906
// Preload the map with the source cache
907
if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
908
SCacheF.Size()) == false)
914
pkgCacheGenerator Gen(*Map,Progress);
916
// Compute the progress
917
unsigned long TotalSize = 0;
918
if (pkgAddStatusSize(TotalSize) == false)
924
unsigned long CurrentSize = 0;
925
if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
672
// Write out the main data
673
if (SCacheF.Write(Map->Data(),Map->Size()) == false)
674
return _error->Error(_("IO Error saving source cache"));
677
// Write out the proper header
678
Gen.GetCache().HeaderP->Dirty = false;
679
if (SCacheF.Seek(0) == false ||
680
SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
681
return _error->Error(_("IO Error saving source cache"));
683
Gen.GetCache().HeaderP->Dirty = true;
686
// Build the status cache
687
if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
688
Files.begin()+EndOfSource,Files.end()) == false)
692
if (_error->PendingError() == true)
698
delete Map.UnGuard();
699
*OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly);
703
*OutMap = Map.UnGuard();
710
// MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
711
// ---------------------------------------------------------------------
713
bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
715
unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
716
vector<pkgIndexFile *> Files;
717
unsigned long EndOfSource = Files.size();
718
if (_system->AddStatusFiles(Files) == false)
721
SPtr<DynamicMMap> Map;
722
Map = new DynamicMMap(MMap::Public,MapSize);
723
unsigned long CurrentSize = 0;
724
unsigned long TotalSize = 0;
726
TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
728
// Build the status cache
729
Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
730
pkgCacheGenerator Gen(Map.Get(),&Progress);
731
if (_error->PendingError() == true)
733
if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
734
Files.begin()+EndOfSource,Files.end()) == false)
737
if (_error->PendingError() == true)
739
*OutMap = Map.UnGuard();