~mvo/apt/mvo

« back to all changes in this revision

Viewing changes to apt-pkg/pkgcachegen.cc

  • Committer: Arch Librarian
  • Date: 2004-09-20 16:56:32 UTC
  • Revision ID: Arch-1:apt@arch.ubuntu.com%apt--MAIN--0--patch-614
Join with aliencode
Author: jgg
Date: 2001-02-20 07:03:16 GMT
Join with aliencode

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
// -*- mode: cpp; mode: fold -*-
2
2
// Description                                                          /*{{{*/
3
 
// $Id: pkgcachegen.cc,v 1.45 2000/01/14 06:26:36 jgg Exp $
 
3
// $Id: pkgcachegen.cc,v 1.46 2001/02/20 07:03:17 jgg Exp $
4
4
/* ######################################################################
5
5
   
6
6
   Package Cache Generator - Generator for the cache structure.
14
14
#pragma implementation "apt-pkg/pkgcachegen.h"
15
15
#endif
16
16
 
 
17
#define APT_COMPATIBILITY 986
 
18
 
17
19
#include <apt-pkg/pkgcachegen.h>
18
20
#include <apt-pkg/error.h>
19
21
#include <apt-pkg/version.h>
20
22
#include <apt-pkg/progress.h>
21
23
#include <apt-pkg/sourcelist.h>
22
24
#include <apt-pkg/configuration.h>
23
 
#include <apt-pkg/deblistparser.h>
24
25
#include <apt-pkg/strutl.h>
 
26
#include <apt-pkg/sptr.h>
 
27
#include <apt-pkg/pkgsystem.h>
25
28
 
 
29
#include <apti18n.h>
 
30
    
26
31
#include <sys/stat.h>
27
32
#include <unistd.h>
28
33
#include <errno.h>
33
38
// CacheGenerator::pkgCacheGenerator - Constructor                      /*{{{*/
34
39
// ---------------------------------------------------------------------
35
40
/* We set the diry flag and make sure that is written to the disk */
36
 
pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map,OpProgress &Prog) :
37
 
                    Map(Map), Cache(Map), Progress(&Prog)
 
41
pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
 
42
                    Map(*pMap), Cache(pMap,false), Progress(Prog)
38
43
{
39
44
   CurrentFile = 0;
 
45
   memset(UniqHash,0,sizeof(UniqHash));
40
46
   
41
47
   if (_error->PendingError() == true)
42
48
      return;
43
 
   
 
49
 
44
50
   if (Map.Size() == 0)
45
51
   {
 
52
      // Setup the map interface..
 
53
      Cache.HeaderP = (pkgCache::Header *)Map.Data();
46
54
      Map.RawAllocate(sizeof(pkgCache::Header));
 
55
      Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
 
56
      
 
57
      // Starting header
47
58
      *Cache.HeaderP = pkgCache::Header();
48
 
   }
 
59
      Cache.HeaderP->VerSysName = Map.WriteString(_system->VS->Label);
 
60
      Cache.HeaderP->Architecture = Map.WriteString(_config->Find("APT::Architecture"));
 
61
      Cache.ReMap(); 
 
62
   }
 
63
   else
 
64
   {
 
65
      // Map directly from the existing file
 
66
      Cache.ReMap(); 
 
67
      Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
 
68
      if (Cache.VS != _system->VS)
 
69
      {
 
70
         _error->Error(_("Cache has an incompatible versioning system"));
 
71
         return;
 
72
      }      
 
73
   }
 
74
   
49
75
   Cache.HeaderP->Dirty = true;
50
76
   Map.Sync(0,sizeof(pkgCache::Header));
51
 
   Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
52
 
   memset(UniqHash,0,sizeof(UniqHash));
53
77
}
54
78
                                                                        /*}}}*/
55
79
// CacheGenerator::~pkgCacheGenerator - Destructor                      /*{{{*/
86
110
      
87
111
      pkgCache::PkgIterator Pkg;
88
112
      if (NewPackage(Pkg,PackageName) == false)
89
 
         return _error->Error("Error occured while processing %s (NewPackage)",PackageName.c_str());
 
113
         return _error->Error(_("Error occured while processing %s (NewPackage)"),PackageName.c_str());
90
114
      Counter++;
91
115
      if (Counter % 100 == 0 && Progress != 0)
92
116
         Progress->Progress(List.Offset());
98
122
      if (Version.empty() == true)
99
123
      {
100
124
         if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
101
 
            return _error->Error("Error occured while processing %s (UsePackage1)",PackageName.c_str());
 
125
            return _error->Error(_("Error occured while processing %s (UsePackage1)"),PackageName.c_str());
102
126
         continue;
103
127
      }
104
128
 
107
131
      int Res = 1;
108
132
      for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
109
133
      {
110
 
         Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
 
134
         Res = Cache.VS->DoCmpVersion(Version.begin(),Version.end(),Ver.VerStr(),
111
135
                                 Ver.VerStr() + strlen(Ver.VerStr()));
112
136
         if (Res >= 0)
113
137
            break;
119
143
      if (Res == 0 && Ver->Hash == Hash)
120
144
      {
121
145
         if (List.UsePackage(Pkg,Ver) == false)
122
 
            return _error->Error("Error occured while processing %s (UsePackage2)",PackageName.c_str());
 
146
            return _error->Error(_("Error occured while processing %s (UsePackage2)"),PackageName.c_str());
123
147
 
124
148
         if (NewFileVer(Ver,List) == false)
125
 
            return _error->Error("Error occured while processing %s (NewFileVer1)",PackageName.c_str());
 
149
            return _error->Error(_("Error occured while processing %s (NewFileVer1)"),PackageName.c_str());
126
150
         
127
151
         // Read only a single record and return
128
152
         if (OutVer != 0)
139
163
      {
140
164
         for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
141
165
         {
142
 
            Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
 
166
            Res = Cache.VS->DoCmpVersion(Version.begin(),Version.end(),Ver.VerStr(),
143
167
                                    Ver.VerStr() + strlen(Ver.VerStr()));
144
168
            if (Res != 0)
145
169
               break;
151
175
      Ver->ParentPkg = Pkg.Index();
152
176
      Ver->Hash = Hash;
153
177
      if (List.NewVersion(Ver) == false)
154
 
         return _error->Error("Error occured while processing %s (NewVersion1)",PackageName.c_str());
 
178
         return _error->Error(_("Error occured while processing %s (NewVersion1)"),PackageName.c_str());
155
179
 
156
180
      if (List.UsePackage(Pkg,Ver) == false)
157
 
         return _error->Error("Error occured while processing %s (UsePackage3)",PackageName.c_str());
 
181
         return _error->Error(_("Error occured while processing %s (UsePackage3)"),PackageName.c_str());
158
182
      
159
183
      if (NewFileVer(Ver,List) == false)
160
 
         return _error->Error("Error occured while processing %s (NewVersion2)",PackageName.c_str());
 
184
         return _error->Error(_("Error occured while processing %s (NewVersion2)"),PackageName.c_str());
161
185
 
162
186
      // Read only a single record and return
163
187
      if (OutVer != 0)
288
312
   // Probe the reverse dependency list for a version string that matches
289
313
   if (Version.empty() == false)
290
314
   {
291
 
/*      for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++, Hit++)
 
315
/*      for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
292
316
         if (I->Version != 0 && I.TargetVer() == Version)
293
317
            Dep->Version = I->Version;*/
294
318
      if (Dep->Version == 0)
342
366
   Prv->Version = Ver.Index();
343
367
   Prv->NextPkgProv = Ver->ProvidesList;
344
368
   Ver->ProvidesList = Prv.Index();
345
 
   if (Version.empty() == false && (Prv->Version = WriteString(Version)) == 0)
 
369
   if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
346
370
      return false;
347
371
   
348
372
   // Locate the target package
361
385
// CacheGenerator::SelectFile - Select the current file being parsed    /*{{{*/
362
386
// ---------------------------------------------------------------------
363
387
/* This is used to select which file is to be associated with all newly
364
 
   added versions. */
365
 
bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
 
388
   added versions. The caller is responsible for setting the IMS fields. */
 
389
bool pkgCacheGenerator::SelectFile(string File,string Site,
 
390
                                   const pkgIndexFile &Index,
 
391
                                   unsigned long Flags)
366
392
{
367
 
   struct stat Buf;
368
 
   if (stat(File.c_str(),&Buf) == -1)
369
 
      return _error->Errno("stat","Couldn't stat ",File.c_str());
370
 
   
371
393
   // Get some space for the structure
372
394
   CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
373
395
   if (CurrentFile == Cache.PkgFileP)
375
397
   
376
398
   // Fill it in
377
399
   CurrentFile->FileName = Map.WriteString(File);
378
 
   CurrentFile->Size = Buf.st_size;
379
 
   CurrentFile->mtime = Buf.st_mtime;
 
400
   CurrentFile->Site = WriteUniqString(Site);
380
401
   CurrentFile->NextFile = Cache.HeaderP->FileList;
381
402
   CurrentFile->Flags = Flags;
382
403
   CurrentFile->ID = Cache.HeaderP->PackageFileCount;
 
404
   CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label);
383
405
   PkgFileName = File;
384
406
   Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
385
407
   Cache.HeaderP->PackageFileCount++;
386
 
      
 
408
 
387
409
   if (CurrentFile->FileName == 0)
388
410
      return false;
389
411
   
390
412
   if (Progress != 0)
391
 
      Progress->SubProgress(Buf.st_size);
 
413
      Progress->SubProgress(Index.Size());
392
414
   return true;
393
415
}
394
416
                                                                        /*}}}*/
443
465
}
444
466
                                                                        /*}}}*/
445
467
 
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
 
472
   any extra files. */
 
473
static bool CheckValidity(string CacheFile,pkgIndexFile **Start,
 
474
                          pkgIndexFile **End,MMap **OutMap = 0)
451
475
{
452
 
   if (_error->PendingError() == true)
453
 
      return false;
454
 
 
455
 
   string CacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
456
 
   string ListDir = _config->FindDir("Dir::State::lists");
457
 
 
458
 
   // Count the number of missing files
459
 
   int Missing = 0;
460
 
   for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
461
 
   {
462
 
      // Only cache deb source types.
463
 
      if (I->Type != pkgSourceList::Item::Deb)
464
 
      {
465
 
         Missing++;
466
 
         continue;
467
 
      }
468
 
      
469
 
      string File = ListDir + URItoFileName(I->PackagesURI());
470
 
      struct stat Buf;
471
 
      if (stat(File.c_str(),&Buf) != 0)
472
 
      {
473
 
         // Old format file name.. rename it
474
 
         if (File[0] == '_' && stat(File.c_str()+1,&Buf) == 0)
475
 
         {
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());
479
 
            continue;
480
 
         }       
481
 
         
482
 
         _error->WarningE("stat","Couldn't stat source package list '%s' (%s)",
483
 
                          I->PackagesInfo().c_str(),File.c_str());       
484
 
         Missing++;
485
 
      }      
486
 
   }
487
 
   
488
 
   // Open the source package cache
489
 
   if (FileExists(CacheFile) == false)
490
 
      return false;
491
 
   
 
476
   // No file, certainly invalid
 
477
   if (CacheFile.empty() == true || FileExists(CacheFile) == false)
 
478
      return false;
 
479
   
 
480
   // Map it
492
481
   FileFd CacheF(CacheFile,FileFd::ReadOnly);
493
 
   if (_error->PendingError() == true)
494
 
   {
495
 
      _error->Discard();
496
 
      return false;
497
 
   }
498
 
   
499
 
   MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
500
 
   if (_error->PendingError() == true || Map.Size() == 0)
501
 
   {
502
 
      _error->Discard();
503
 
      return false;
504
 
   }
505
 
   
 
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)
508
485
   {
509
486
      _error->Discard();
510
487
      return false;
511
488
   }
512
 
 
513
 
   // They are certianly out of sync
514
 
   if (Cache.Head().PackageFileCount != List.size() - Missing)
515
 
      return false;
516
489
   
517
 
   for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
518
 
   {      
519
 
      // Search for a match in the source list
520
 
      bool Bad = true;
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++)
 
495
   {
 
496
      if ((*Start)->HasPackages() == false)
 
497
         continue;
 
498
      
 
499
      if ((*Start)->Exists() == false)
523
500
      {
524
 
         // Only cache deb source types.
525
 
         if (I->Type != pkgSourceList::Item::Deb)
526
 
            continue;
527
 
         
528
 
         string File = ListDir + URItoFileName(I->PackagesURI());
529
 
         if (F.FileName() == File)
530
 
         {
531
 
            Bad = false;
532
 
            break;
533
 
         }
 
501
         _error->WarningE("stat",_("Couldn't stat source package list %s"),
 
502
                          (*Start)->Describe().c_str());
 
503
         continue;
534
504
      }
 
505
 
 
506
      // FindInCache is also expected to do an IMS check.
 
507
      pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
 
508
      if (File.end() == true)
 
509
         return false;
535
510
      
536
 
      // Check if the file matches what was cached
537
 
      Bad |= !F.IsOk();
538
 
      if (Bad == true)
 
511
      Visited[File->ID] = true;
 
512
   }
 
513
   
 
514
   for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
 
515
      if (Visited[I] == false)
539
516
         return false;
 
517
   
 
518
   if (_error->PendingError() == true)
 
519
   {
 
520
      _error->Discard();
 
521
      return false;
540
522
   }
541
523
   
 
524
   if (OutMap != 0)
 
525
      *OutMap = Map.UnGuard();
542
526
   return true;
543
527
}
544
528
                                                                        /*}}}*/
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)
549
 
{
550
 
   if (_error->PendingError() == true)
551
 
      return false;
552
 
   
553
 
   // Open the source package cache
554
 
   if (FileExists(CacheFile) == false)
555
 
      return false;
556
 
   
557
 
   FileFd CacheF(CacheFile,FileFd::ReadOnly);
558
 
   if (_error->PendingError() == true)
559
 
   {
560
 
      _error->Discard();
561
 
      return false;
562
 
   }
563
 
   
564
 
   MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
565
 
   if (_error->PendingError() == true || Map.Size() == 0)
566
 
   {
567
 
      _error->Discard();
568
 
      return false;
569
 
   }
570
 
   
571
 
   pkgCache Cache(Map);
572
 
   if (_error->PendingError() == true)
573
 
   {
574
 
      _error->Discard();
575
 
      return false;
576
 
   }
 
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
 
532
   meter */
 
533
static unsigned long ComputeSize(pkgIndexFile **Start,pkgIndexFile **End)
 
534
{
 
535
   unsigned long TotalSize = 0;
 
536
   for (; Start != End; Start++)
 
537
   {
 
538
      if ((*Start)->HasPackages() == false)
 
539
         continue;      
 
540
      TotalSize += (*Start)->Size();
 
541
   }
 
542
   return TotalSize;
 
543
}
 
544
                                                                        /*}}}*/
 
545
// BuildCache - Merge the list of index files into the cache            /*{{{*/
 
546
// ---------------------------------------------------------------------
 
547
/* */
 
548
static bool BuildCache(pkgCacheGenerator &Gen,
 
549
                       OpProgress &Progress,
 
550
                       unsigned long &CurrentSize,unsigned long TotalSize,
 
551
                       pkgIndexFile **Start,pkgIndexFile **End)
 
552
{
 
553
   for (; Start != End; Start++)
 
554
   {
 
555
      if ((*Start)->HasPackages() == false)
 
556
         continue;
 
557
      
 
558
      if ((*Start)->Exists() == false)
 
559
         continue;
577
560
 
578
 
   // Status files that must be in the cache
579
 
   string Status[3];
580
 
   Status[0] = _config->FindFile("Dir::State::xstatus");
581
 
   Status[1]= _config->FindFile("Dir::State::userstatus");
582
 
   Status[2] = _config->FindFile("Dir::State::status");
583
 
   
584
 
   // Cheack each file
585
 
   for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
586
 
   {
587
 
      if (F.IsOk() == false)
588
 
         return false;
 
561
      unsigned long Size = (*Start)->Size();
 
562
      Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists"));
 
563
      CurrentSize += Size;
589
564
      
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();
594
 
   }
595
 
   
596
 
   // Make sure all the status files are loaded.
597
 
   for (int I = 0; I != 3; I++)
598
 
   {
599
 
      if (Status[I].empty() == false && FileExists(Status[I]) == true)
 
565
      if ((*Start)->Merge(Gen,Progress) == false)
600
566
         return false;
601
567
   }   
602
568
   
603
569
   return true;
604
570
}
605
571
                                                                        /*}}}*/
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)
610
 
{
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");
615
 
   
616
 
   // Grab the sizes
617
 
   struct stat Buf;
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;
625
 
   
626
 
   return true;
627
 
}
628
 
                                                                        /*}}}*/
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)
634
 
{
635
 
   // Grab the file names   
636
 
   string Status[3];
637
 
   Status[0] = _config->FindFile("Dir::State::xstatus");
638
 
   Status[1]= _config->FindFile("Dir::State::userstatus");
639
 
   Status[2] = _config->FindFile("Dir::State::status");
640
 
   
641
 
   for (int I = 0; I != 3; I++)
642
 
   {
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)
646
 
         continue;
647
 
         
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)
 
582
{
 
583
   unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
 
584
   
 
585
   vector<pkgIndexFile *> Files(List.begin(),List.end());
 
586
   unsigned long EndOfSource = Files.size();
 
587
   if (_system->AddStatusFiles(Files) == false)
 
588
      return false;
 
589
   
 
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");
 
593
   
 
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;
 
598
   else
 
599
      if (SrcCacheFile.empty() == false)
 
600
         Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
 
601
   
 
602
   if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
 
603
      return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
 
604
   
 
605
   Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
 
606
   
 
607
   // Cache is OK, Fin.
 
608
   if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
 
609
   {
 
610
      Progress.OverallProgress(1,1,1,_("Reading Package Lists"));
 
611
      return true;
 
612
   }
 
613
   
 
614
   /* At this point we know we need to reconstruct the package cache,
 
615
      begin. */
 
616
   SPtr<FileFd> CacheF;
 
617
   SPtr<DynamicMMap> Map;
 
618
   if (Writeable == true && CacheFile.empty() == false)
 
619
   {
 
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();
 
624
         return false;
 
625
   }
 
626
   else
 
627
   {
 
628
      // Just build it in memory..
 
629
      Map = new DynamicMMap(MMap::Public,MapSize);
 
630
   }
 
631
   
 
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)
 
637
   {
 
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)
 
642
         return false;
654
643
 
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());
658
 
      
659
 
      if (Gen.MergeList(Parser) == false)
660
 
         return _error->Error("Problem with MergeList %s",File.c_str());
661
 
      Progress.Progress(Pkg.Size());
662
 
   }
663
 
   
664
 
   return true;
665
 
}
666
 
                                                                        /*}}}*/
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)
673
 
{
674
 
   string ListDir = _config->FindDir("Dir::State::lists");
675
 
   
676
 
   // Prepare the progress indicator
677
 
   TotalSize = 0;
678
 
   struct stat Buf;
679
 
   for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
680
 
   {
681
 
      string File = ListDir + URItoFileName(I->PackagesURI());
682
 
      if (stat(File.c_str(),&Buf) != 0)
683
 
         continue;
684
 
      TotalSize += Buf.st_size;
685
 
   }
686
 
   
687
 
   if (pkgAddStatusSize(TotalSize) == false)
688
 
      return false;
689
 
   
690
 
   // Generate the pkg source cache
691
 
   CurrentSize = 0;
692
 
   for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
693
 
   {
694
 
      // Only cache deb source types.
695
 
      if (I->Type != pkgSourceList::Item::Deb)
696
 
         continue;
697
 
      
698
 
      string File = ListDir + URItoFileName(I->PackagesURI());
699
 
      
700
 
      if (FileExists(File) == false)
701
 
         continue;
702
 
      
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();
709
 
      
710
 
      Progress.SubProgress(0,I->PackagesInfo());
711
 
      if (Gen.SelectFile(File) == false)
712
 
         return _error->Error("Problem with SelectFile %s",File.c_str());
713
 
      
714
 
      if (Gen.MergeList(Parser) == false)
715
 
         return _error->Error("Problem with MergeList %s",File.c_str());
716
 
      
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());
 
645
      
 
646
      // Build the status cache
 
647
      pkgCacheGenerator Gen(Map.Get(),&Progress);
 
648
      if (_error->PendingError() == true)
 
649
         return false;
 
650
      if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 
651
                     Files.begin()+EndOfSource,Files.end()) == false)
 
652
         return false;
 
653
   }
 
654
   else
 
655
   {
 
656
      TotalSize = ComputeSize(Files.begin(),Files.end());
 
657
      
 
658
      // Build the source cache
 
659
      pkgCacheGenerator Gen(Map.Get(),&Progress);
 
660
      if (_error->PendingError() == true)
 
661
         return false;
 
662
      if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 
663
                     Files.begin(),Files.begin()+EndOfSource) == false)
 
664
         return false;
 
665
      
 
666
      // Write it back
 
667
      if (Writeable == true && SrcCacheFile.empty() == false)
720
668
      {
721
 
         FileFd Rel(RFile,FileFd::ReadOnly);
 
669
         FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
722
670
         if (_error->PendingError() == true)
723
671
            return false;
724
 
         Parser.LoadReleaseInfo(Gen.GetCurFile(),Rel);
725
 
      }
726
 
   }
727
 
   
728
 
   return true;
729
 
}
730
 
                                                                        /*}}}*/
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)
736
 
{
737
 
   unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
738
 
   
739
 
   Progress.OverallProgress(0,1,1,"Reading Package Lists");
740
 
   
741
 
   string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
742
 
   bool SrcOk = pkgSrcCacheCheck(List);
743
 
   bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
744
 
 
745
 
   // Rebuild the source and package caches   
746
 
   if (SrcOk == false)
747
 
   {      
748
 
      string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
749
 
      FileFd SCacheF(SCacheFile,FileFd::WriteEmpty);
750
 
      
751
 
      /* Open the pkgcache, we want a new inode here so we do no corrupt
752
 
         existing mmaps */
753
 
      unlink(CacheFile.c_str());             
754
 
      FileFd CacheF(CacheFile,FileFd::WriteEmpty);
755
 
      DynamicMMap Map(CacheF,MMap::Public,MapSize);
756
 
      if (_error->PendingError() == true)
757
 
         return false;
758
 
 
759
 
      pkgCacheGenerator Gen(Map,Progress);
760
 
      unsigned long CurrentSize = 0;
761
 
      unsigned long TotalSize = 0;
762
 
      if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
763
 
         return false;
764
 
      
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;
770
 
      
771
 
      // Merge in the source caches
772
 
      return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
773
 
   }
774
 
 
775
 
   if (PkgOk == true)
776
 
   {
777
 
      Progress.OverallProgress(1,1,1,"Reading Package Lists");      
778
 
      return true;
779
 
   }
780
 
   
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);
784
 
   
785
 
   /* Open the pkgcache, we want a new inode here so we do no corrupt
786
 
      existing mmaps */
787
 
   unlink(CacheFile.c_str());             
788
 
   FileFd CacheF(CacheFile,FileFd::WriteEmpty);
789
 
   DynamicMMap Map(CacheF,MMap::Public,MapSize);
790
 
   if (_error->PendingError() == true)
791
 
      return false;
792
 
   
793
 
   // Preload the map with the source cache
794
 
   if (SCacheF.Read((unsigned char *)Map.Data() + Map.RawAllocate(SCacheF.Size()),
795
 
                    SCacheF.Size()) == false)
796
 
      return false;
797
 
      
798
 
   pkgCacheGenerator Gen(Map,Progress);
799
 
   
800
 
   // Compute the progress
801
 
   unsigned long TotalSize = 0;
802
 
   if (pkgAddStatusSize(TotalSize) == false)
803
 
      return false;
804
 
 
805
 
   unsigned long CurrentSize = 0;
806
 
   return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
807
 
}
808
 
                                                                        /*}}}*/
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)
815
 
{
816
 
   unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
817
 
   
818
 
   /* If the cache file is writeable this is just a wrapper for
819
 
      MakeStatusCache */
820
 
   string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
821
 
   bool Writeable = (access(CacheFile.c_str(),W_OK) == 0) ||
822
 
                    (errno == ENOENT);
823
 
 
824
 
   if (Writeable == true)
825
 
   {
826
 
      if (pkgMakeStatusCache(List,Progress) == false)
827
 
         return 0;
828
 
      
829
 
      // Open the cache file
830
 
      FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
831
 
      if (_error->PendingError() == true)
832
 
         return 0;
833
 
      
834
 
      MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
835
 
      if (_error->PendingError() == true)
836
 
      {
837
 
         delete Map;
838
 
         return 0;
839
 
      }
840
 
      return Map;
841
 
   }      
842
 
 
843
 
   // Mostly from MakeStatusCache..
844
 
   Progress.OverallProgress(0,1,1,"Reading Package Lists");
845
 
   
846
 
   bool SrcOk = pkgSrcCacheCheck(List);
847
 
   bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
848
 
                           
849
 
   // Rebuild the source and package caches   
850
 
   if (SrcOk == false)
851
 
   {
852
 
      DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize);
853
 
      if (_error->PendingError() == true)
854
 
      {
855
 
         delete Map;
856
 
         return 0;
857
 
      }
858
 
      
859
 
      pkgCacheGenerator Gen(*Map,Progress);
860
 
      unsigned long CurrentSize = 0;
861
 
      unsigned long TotalSize = 0;
862
 
      if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
863
 
      {
864
 
         delete Map;
865
 
         return 0;
866
 
      }
867
 
      
868
 
      // Merge in the source caches
869
 
      if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
870
 
      {
871
 
         delete Map;
872
 
         return 0;
873
 
      }
874
 
      
875
 
      return Map;
876
 
   }
877
 
 
878
 
   if (PkgOk == true)
879
 
   {
880
 
      Progress.OverallProgress(1,1,1,"Reading Package Lists");
881
 
      
882
 
      // Open the cache file
883
 
      FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
884
 
      if (_error->PendingError() == true)
885
 
         return 0;
886
 
      
887
 
      MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
888
 
      if (_error->PendingError() == true)
889
 
      {
890
 
         delete Map;
891
 
         return 0;
892
 
      }
893
 
      return Map;
894
 
   }
895
 
   
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)
901
 
   {
902
 
      delete Map;
903
 
      return 0;
904
 
   }
905
 
   
906
 
   // Preload the map with the source cache
907
 
   if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
908
 
                    SCacheF.Size()) == false)
909
 
   {
910
 
      delete Map;
911
 
      return 0;
912
 
   }
913
 
      
914
 
   pkgCacheGenerator Gen(*Map,Progress);
915
 
   
916
 
   // Compute the progress
917
 
   unsigned long TotalSize = 0;
918
 
   if (pkgAddStatusSize(TotalSize) == false)
919
 
   {
920
 
      delete Map;
921
 
      return 0;
922
 
   }
923
 
 
924
 
   unsigned long CurrentSize = 0;
925
 
   if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
926
 
   {
927
 
      delete Map;
928
 
      return 0;
929
 
   }
930
 
    
931
 
   return Map;
 
672
         // Write out the main data
 
673
         if (SCacheF.Write(Map->Data(),Map->Size()) == false)
 
674
            return _error->Error(_("IO Error saving source cache"));
 
675
         SCacheF.Sync();
 
676
         
 
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"));
 
682
         SCacheF.Sync();
 
683
         Gen.GetCache().HeaderP->Dirty = true;
 
684
      }
 
685
      
 
686
      // Build the status cache
 
687
      if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 
688
                     Files.begin()+EndOfSource,Files.end()) == false)
 
689
         return false;
 
690
   }
 
691
 
 
692
   if (_error->PendingError() == true)
 
693
      return false;
 
694
   if (OutMap != 0)
 
695
   {
 
696
      if (CacheF != 0)
 
697
      {
 
698
         delete Map.UnGuard();
 
699
         *OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly);
 
700
      }
 
701
      else
 
702
      {
 
703
         *OutMap = Map.UnGuard();
 
704
      }      
 
705
   }
 
706
   
 
707
   return true;
 
708
}
 
709
                                                                        /*}}}*/
 
710
// MakeOnlyStatusCache - Build a cache with just the status files       /*{{{*/
 
711
// ---------------------------------------------------------------------
 
712
/* */
 
713
bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
 
714
{
 
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)
 
719
      return false;
 
720
   
 
721
   SPtr<DynamicMMap> Map;   
 
722
   Map = new DynamicMMap(MMap::Public,MapSize);
 
723
   unsigned long CurrentSize = 0;
 
724
   unsigned long TotalSize = 0;
 
725
   
 
726
   TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
 
727
   
 
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)
 
732
      return false;
 
733
   if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
 
734
                  Files.begin()+EndOfSource,Files.end()) == false)
 
735
      return false;
 
736
   
 
737
   if (_error->PendingError() == true)
 
738
      return false;
 
739
   *OutMap = Map.UnGuard();
 
740
   
 
741
   return true;
932
742
}
933
743
                                                                        /*}}}*/