]> git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
Increase the range of the ID type for deps
[apt.git] / apt-pkg / pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: pkgcachegen.cc,v 1.50 2001/07/01 22:28:24 jgg Exp $
4 /* ######################################################################
5
6 Package Cache Generator - Generator for the cache structure.
7
8 This builds the cache structure from the abstract package list parser.
9
10 ##################################################################### */
11 /*}}}*/
12 // Include Files /*{{{*/
13 #ifdef __GNUG__
14 #pragma implementation "apt-pkg/pkgcachegen.h"
15 #endif
16
17 #define APT_COMPATIBILITY 986
18
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>
28
29 #include <apti18n.h>
30
31 #include <vector>
32
33 #include <sys/stat.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <stdio.h>
37 #include <system.h>
38 /*}}}*/
39 typedef vector<pkgIndexFile *>::iterator FileIterator;
40
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)
46 {
47 CurrentFile = 0;
48 memset(UniqHash,0,sizeof(UniqHash));
49
50 if (_error->PendingError() == true)
51 return;
52
53 if (Map.Size() == 0)
54 {
55 // Setup the map interface..
56 Cache.HeaderP = (pkgCache::Header *)Map.Data();
57 Map.RawAllocate(sizeof(pkgCache::Header));
58 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
59
60 // Starting header
61 *Cache.HeaderP = pkgCache::Header();
62 Cache.HeaderP->VerSysName = Map.WriteString(_system->VS->Label);
63 Cache.HeaderP->Architecture = Map.WriteString(_config->Find("APT::Architecture"));
64 Cache.ReMap();
65 }
66 else
67 {
68 // Map directly from the existing file
69 Cache.ReMap();
70 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
71 if (Cache.VS != _system->VS)
72 {
73 _error->Error(_("Cache has an incompatible versioning system"));
74 return;
75 }
76 }
77
78 Cache.HeaderP->Dirty = true;
79 Map.Sync(0,sizeof(pkgCache::Header));
80 }
81 /*}}}*/
82 // CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
83 // ---------------------------------------------------------------------
84 /* We sync the data then unset the dirty flag in two steps so as to
85 advoid a problem during a crash */
86 pkgCacheGenerator::~pkgCacheGenerator()
87 {
88 if (_error->PendingError() == true)
89 return;
90 if (Map.Sync() == false)
91 return;
92
93 Cache.HeaderP->Dirty = false;
94 Map.Sync(0,sizeof(pkgCache::Header));
95 }
96 /*}}}*/
97 // CacheGenerator::MergeList - Merge the package list /*{{{*/
98 // ---------------------------------------------------------------------
99 /* This provides the generation of the entries in the cache. Each loop
100 goes through a single package record from the underlying parse engine. */
101 bool pkgCacheGenerator::MergeList(ListParser &List,
102 pkgCache::VerIterator *OutVer)
103 {
104 List.Owner = this;
105
106 unsigned int Counter = 0;
107 while (List.Step() == true)
108 {
109 // Get a pointer to the package structure
110 string PackageName = List.Package();
111 if (PackageName.empty() == true)
112 return false;
113
114 pkgCache::PkgIterator Pkg;
115 if (NewPackage(Pkg,PackageName) == false)
116 return _error->Error(_("Error occured while processing %s (NewPackage)"),PackageName.c_str());
117 Counter++;
118 if (Counter % 100 == 0 && Progress != 0)
119 Progress->Progress(List.Offset());
120
121 /* Get a pointer to the version structure. We know the list is sorted
122 so we use that fact in the search. Insertion of new versions is
123 done with correct sorting */
124 string Version = List.Version();
125 if (Version.empty() == true)
126 {
127 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
128 return _error->Error(_("Error occured while processing %s (UsePackage1)"),PackageName.c_str());
129 continue;
130 }
131
132 pkgCache::VerIterator Ver = Pkg.VersionList();
133 map_ptrloc *Last = &Pkg->VersionList;
134 int Res = 1;
135 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
136 {
137 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
138 if (Res >= 0)
139 break;
140 }
141
142 /* We already have a version for this item, record that we
143 saw it */
144 unsigned long Hash = List.VersionHash();
145 if (Res == 0 && Ver->Hash == Hash)
146 {
147 if (List.UsePackage(Pkg,Ver) == false)
148 return _error->Error(_("Error occured while processing %s (UsePackage2)"),PackageName.c_str());
149
150 if (NewFileVer(Ver,List) == false)
151 return _error->Error(_("Error occured while processing %s (NewFileVer1)"),PackageName.c_str());
152
153 // Read only a single record and return
154 if (OutVer != 0)
155 {
156 *OutVer = Ver;
157 return true;
158 }
159
160 continue;
161 }
162
163 // Skip to the end of the same version set.
164 if (Res == 0)
165 {
166 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
167 {
168 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
169 if (Res != 0)
170 break;
171 }
172 }
173
174 // Add a new version
175 *Last = NewVersion(Ver,Version,*Last);
176 Ver->ParentPkg = Pkg.Index();
177 Ver->Hash = Hash;
178 if (List.NewVersion(Ver) == false)
179 return _error->Error(_("Error occured while processing %s (NewVersion1)"),PackageName.c_str());
180
181 if (List.UsePackage(Pkg,Ver) == false)
182 return _error->Error(_("Error occured while processing %s (UsePackage3)"),PackageName.c_str());
183
184 if (NewFileVer(Ver,List) == false)
185 return _error->Error(_("Error occured while processing %s (NewVersion2)"),PackageName.c_str());
186
187 // Read only a single record and return
188 if (OutVer != 0)
189 {
190 *OutVer = Ver;
191 return true;
192 }
193 }
194
195 if (Cache.HeaderP->PackageCount >= (1ULL<<sizeof(Cache.PkgP->ID)*8)-1)
196 return _error->Error(_("Wow, you exceeded the number of package "
197 "names this APT is capable of."));
198 if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
199 return _error->Error(_("Wow, you exceeded the number of versions "
200 "this APT is capable of."));
201 if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
202 return _error->Error(_("Wow, you exceeded the number of dependencies "
203 "this APT is capable of."));
204 return true;
205 }
206 /*}}}*/
207 // CacheGenerator::NewPackage - Add a new package /*{{{*/
208 // ---------------------------------------------------------------------
209 /* This creates a new package structure and adds it to the hash table */
210 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
211 {
212 Pkg = Cache.FindPkg(Name);
213 if (Pkg.end() == false)
214 return true;
215
216 // Get a structure
217 unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
218 if (Package == 0)
219 return false;
220
221 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
222
223 // Insert it into the hash table
224 unsigned long Hash = Cache.Hash(Name);
225 Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
226 Cache.HeaderP->HashTable[Hash] = Package;
227
228 // Set the name and the ID
229 Pkg->Name = Map.WriteString(Name);
230 if (Pkg->Name == 0)
231 return false;
232 Pkg->ID = Cache.HeaderP->PackageCount++;
233
234 return true;
235 }
236 /*}}}*/
237 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
238 // ---------------------------------------------------------------------
239 /* */
240 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
241 ListParser &List)
242 {
243 if (CurrentFile == 0)
244 return true;
245
246 // Get a structure
247 unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
248 if (VerFile == 0)
249 return 0;
250
251 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
252 VF->File = CurrentFile - Cache.PkgFileP;
253
254 // Link it to the end of the list
255 map_ptrloc *Last = &Ver->FileList;
256 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++)
257 Last = &V->NextFile;
258 VF->NextFile = *Last;
259 *Last = VF.Index();
260
261 VF->Offset = List.Offset();
262 VF->Size = List.Size();
263 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
264 Cache.HeaderP->MaxVerFileSize = VF->Size;
265 Cache.HeaderP->VerFileCount++;
266
267 return true;
268 }
269 /*}}}*/
270 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
271 // ---------------------------------------------------------------------
272 /* This puts a version structure in the linked list */
273 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
274 string VerStr,
275 unsigned long Next)
276 {
277 // Get a structure
278 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
279 if (Version == 0)
280 return 0;
281
282 // Fill it in
283 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
284 Ver->NextVer = Next;
285 Ver->ID = Cache.HeaderP->VersionCount++;
286 Ver->VerStr = Map.WriteString(VerStr);
287 if (Ver->VerStr == 0)
288 return 0;
289
290 return Version;
291 }
292 /*}}}*/
293 // ListParser::NewDepends - Create a dependency element /*{{{*/
294 // ---------------------------------------------------------------------
295 /* This creates a dependency element in the tree. It is linked to the
296 version and to the package that it is pointing to. */
297 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
298 string PackageName,
299 string Version,
300 unsigned int Op,
301 unsigned int Type)
302 {
303 pkgCache &Cache = Owner->Cache;
304
305 // Get a structure
306 unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
307 if (Dependency == 0)
308 return false;
309
310 // Fill it in
311 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
312 Dep->ParentVer = Ver.Index();
313 Dep->Type = Type;
314 Dep->CompareOp = Op;
315 Dep->ID = Cache.HeaderP->DependsCount++;
316
317 // Locate the target package
318 pkgCache::PkgIterator Pkg;
319 if (Owner->NewPackage(Pkg,PackageName) == false)
320 return false;
321
322 // Probe the reverse dependency list for a version string that matches
323 if (Version.empty() == false)
324 {
325 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
326 if (I->Version != 0 && I.TargetVer() == Version)
327 Dep->Version = I->Version;*/
328 if (Dep->Version == 0)
329 if ((Dep->Version = WriteString(Version)) == 0)
330 return false;
331 }
332
333 // Link it to the package
334 Dep->Package = Pkg.Index();
335 Dep->NextRevDepends = Pkg->RevDepends;
336 Pkg->RevDepends = Dep.Index();
337
338 /* Link it to the version (at the end of the list)
339 Caching the old end point speeds up generation substantially */
340 if (OldDepVer != Ver)
341 {
342 OldDepLast = &Ver->DependsList;
343 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
344 OldDepLast = &D->NextDepends;
345 OldDepVer = Ver;
346 }
347
348 Dep->NextDepends = *OldDepLast;
349 *OldDepLast = Dep.Index();
350 OldDepLast = &Dep->NextDepends;
351
352 return true;
353 }
354 /*}}}*/
355 // ListParser::NewProvides - Create a Provides element /*{{{*/
356 // ---------------------------------------------------------------------
357 /* */
358 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
359 string PackageName,
360 string Version)
361 {
362 pkgCache &Cache = Owner->Cache;
363
364 // We do not add self referencing provides
365 if (Ver.ParentPkg().Name() == PackageName)
366 return true;
367
368 // Get a structure
369 unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
370 if (Provides == 0)
371 return false;
372 Cache.HeaderP->ProvidesCount++;
373
374 // Fill it in
375 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
376 Prv->Version = Ver.Index();
377 Prv->NextPkgProv = Ver->ProvidesList;
378 Ver->ProvidesList = Prv.Index();
379 if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
380 return false;
381
382 // Locate the target package
383 pkgCache::PkgIterator Pkg;
384 if (Owner->NewPackage(Pkg,PackageName) == false)
385 return false;
386
387 // Link it to the package
388 Prv->ParentPkg = Pkg.Index();
389 Prv->NextProvides = Pkg->ProvidesList;
390 Pkg->ProvidesList = Prv.Index();
391
392 return true;
393 }
394 /*}}}*/
395 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
396 // ---------------------------------------------------------------------
397 /* This is used to select which file is to be associated with all newly
398 added versions. The caller is responsible for setting the IMS fields. */
399 bool pkgCacheGenerator::SelectFile(string File,string Site,
400 const pkgIndexFile &Index,
401 unsigned long Flags)
402 {
403 // Get some space for the structure
404 CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
405 if (CurrentFile == Cache.PkgFileP)
406 return false;
407
408 // Fill it in
409 CurrentFile->FileName = Map.WriteString(File);
410 CurrentFile->Site = WriteUniqString(Site);
411 CurrentFile->NextFile = Cache.HeaderP->FileList;
412 CurrentFile->Flags = Flags;
413 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
414 CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label);
415 PkgFileName = File;
416 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
417 Cache.HeaderP->PackageFileCount++;
418
419 if (CurrentFile->FileName == 0)
420 return false;
421
422 if (Progress != 0)
423 Progress->SubProgress(Index.Size());
424 return true;
425 }
426 /*}}}*/
427 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
428 // ---------------------------------------------------------------------
429 /* This is used to create handles to strings. Given the same text it
430 always returns the same number */
431 unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
432 unsigned int Size)
433 {
434 /* We use a very small transient hash table here, this speeds up generation
435 by a fair amount on slower machines */
436 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
437 if (Bucket != 0 &&
438 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
439 return Bucket->String;
440
441 // Search for an insertion point
442 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
443 int Res = 1;
444 map_ptrloc *Last = &Cache.HeaderP->StringList;
445 for (; I != Cache.StringItemP; Last = &I->NextItem,
446 I = Cache.StringItemP + I->NextItem)
447 {
448 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
449 if (Res >= 0)
450 break;
451 }
452
453 // Match
454 if (Res == 0)
455 {
456 Bucket = I;
457 return I->String;
458 }
459
460 // Get a structure
461 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
462 if (Item == 0)
463 return 0;
464
465 // Fill in the structure
466 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
467 ItemP->NextItem = I - Cache.StringItemP;
468 *Last = Item;
469 ItemP->String = Map.WriteString(S,Size);
470 if (ItemP->String == 0)
471 return 0;
472
473 Bucket = ItemP;
474 return ItemP->String;
475 }
476 /*}}}*/
477
478 // CheckValidity - Check that a cache is up-to-date /*{{{*/
479 // ---------------------------------------------------------------------
480 /* This just verifies that each file in the list of index files exists,
481 has matching attributes with the cache and the cache does not have
482 any extra files. */
483 static bool CheckValidity(string CacheFile, FileIterator Start,
484 FileIterator End,MMap **OutMap = 0)
485 {
486 // No file, certainly invalid
487 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
488 return false;
489
490 // Map it
491 FileFd CacheF(CacheFile,FileFd::ReadOnly);
492 SPtr<MMap> Map = new MMap(CacheF,MMap::Public | MMap::ReadOnly);
493 pkgCache Cache(Map);
494 if (_error->PendingError() == true || Map->Size() == 0)
495 {
496 _error->Discard();
497 return false;
498 }
499
500 /* Now we check every index file, see if it is in the cache,
501 verify the IMS data and check that it is on the disk too.. */
502 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
503 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
504 for (; Start != End; Start++)
505 {
506 if ((*Start)->HasPackages() == false)
507 continue;
508
509 if ((*Start)->Exists() == false)
510 {
511 _error->WarningE("stat",_("Couldn't stat source package list %s"),
512 (*Start)->Describe().c_str());
513 continue;
514 }
515
516 // FindInCache is also expected to do an IMS check.
517 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
518 if (File.end() == true)
519 return false;
520
521 Visited[File->ID] = true;
522 }
523
524 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
525 if (Visited[I] == false)
526 return false;
527
528 if (_error->PendingError() == true)
529 {
530 _error->Discard();
531 return false;
532 }
533
534 if (OutMap != 0)
535 *OutMap = Map.UnGuard();
536 return true;
537 }
538 /*}}}*/
539 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
540 // ---------------------------------------------------------------------
541 /* Size is kind of an abstract notion that is only used for the progress
542 meter */
543 static unsigned long ComputeSize(FileIterator Start,FileIterator End)
544 {
545 unsigned long TotalSize = 0;
546 for (; Start != End; Start++)
547 {
548 if ((*Start)->HasPackages() == false)
549 continue;
550 TotalSize += (*Start)->Size();
551 }
552 return TotalSize;
553 }
554 /*}}}*/
555 // BuildCache - Merge the list of index files into the cache /*{{{*/
556 // ---------------------------------------------------------------------
557 /* */
558 static bool BuildCache(pkgCacheGenerator &Gen,
559 OpProgress &Progress,
560 unsigned long &CurrentSize,unsigned long TotalSize,
561 FileIterator Start, FileIterator End)
562 {
563 for (; Start != End; Start++)
564 {
565 if ((*Start)->HasPackages() == false)
566 continue;
567
568 if ((*Start)->Exists() == false)
569 continue;
570
571 if ((*Start)->FindInCache(Gen.GetCache()).end() == false)
572 {
573 _error->Warning("Duplicate sources.list entry %s",
574 (*Start)->Describe().c_str());
575 continue;
576 }
577
578 unsigned long Size = (*Start)->Size();
579 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists"));
580 CurrentSize += Size;
581
582 if ((*Start)->Merge(Gen,Progress) == false)
583 return false;
584 }
585
586 return true;
587 }
588 /*}}}*/
589 // MakeStatusCache - Construct the status cache /*{{{*/
590 // ---------------------------------------------------------------------
591 /* This makes sure that the status cache (the cache that has all
592 index files from the sources list and all local ones) is ready
593 to be mmaped. If OutMap is not zero then a MMap object representing
594 the cache will be stored there. This is pretty much mandetory if you
595 are using AllowMem. AllowMem lets the function be run as non-root
596 where it builds the cache 'fast' into a memory buffer. */
597 bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
598 MMap **OutMap,bool AllowMem)
599 {
600 unsigned long MapSize = _config->FindI("APT::Cache-Limit",6*1024*1024);
601
602 vector<pkgIndexFile *> Files(List.begin(),List.end());
603 unsigned long EndOfSource = Files.size();
604 if (_system->AddStatusFiles(Files) == false)
605 return false;
606
607 // Decide if we can write to the files..
608 string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
609 string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
610
611 // Decide if we can write to the cache
612 bool Writeable = false;
613 if (CacheFile.empty() == false)
614 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
615 else
616 if (SrcCacheFile.empty() == false)
617 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
618
619 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
620 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
621
622 Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
623
624 // Cache is OK, Fin.
625 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
626 {
627 Progress.OverallProgress(1,1,1,_("Reading Package Lists"));
628 return true;
629 }
630
631 /* At this point we know we need to reconstruct the package cache,
632 begin. */
633 SPtr<FileFd> CacheF;
634 SPtr<DynamicMMap> Map;
635 if (Writeable == true && CacheFile.empty() == false)
636 {
637 unlink(CacheFile.c_str());
638 CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
639 Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
640 if (_error->PendingError() == true)
641 return false;
642 }
643 else
644 {
645 // Just build it in memory..
646 Map = new DynamicMMap(MMap::Public,MapSize);
647 }
648
649 // Lets try the source cache.
650 unsigned long CurrentSize = 0;
651 unsigned long TotalSize = 0;
652 if (CheckValidity(SrcCacheFile,Files.begin(),
653 Files.begin()+EndOfSource) == true)
654 {
655 // Preload the map with the source cache
656 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
657 if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
658 SCacheF.Size()) == false)
659 return false;
660
661 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
662
663 // Build the status cache
664 pkgCacheGenerator Gen(Map.Get(),&Progress);
665 if (_error->PendingError() == true)
666 return false;
667 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
668 Files.begin()+EndOfSource,Files.end()) == false)
669 return false;
670 }
671 else
672 {
673 TotalSize = ComputeSize(Files.begin(),Files.end());
674
675 // Build the source cache
676 pkgCacheGenerator Gen(Map.Get(),&Progress);
677 if (_error->PendingError() == true)
678 return false;
679 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
680 Files.begin(),Files.begin()+EndOfSource) == false)
681 return false;
682
683 // Write it back
684 if (Writeable == true && SrcCacheFile.empty() == false)
685 {
686 FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
687 if (_error->PendingError() == true)
688 return false;
689 // Write out the main data
690 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
691 return _error->Error(_("IO Error saving source cache"));
692 SCacheF.Sync();
693
694 // Write out the proper header
695 Gen.GetCache().HeaderP->Dirty = false;
696 if (SCacheF.Seek(0) == false ||
697 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
698 return _error->Error(_("IO Error saving source cache"));
699 SCacheF.Sync();
700 Gen.GetCache().HeaderP->Dirty = true;
701 }
702
703 // Build the status cache
704 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
705 Files.begin()+EndOfSource,Files.end()) == false)
706 return false;
707 }
708
709 if (_error->PendingError() == true)
710 return false;
711 if (OutMap != 0)
712 {
713 if (CacheF != 0)
714 {
715 delete Map.UnGuard();
716 *OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly);
717 }
718 else
719 {
720 *OutMap = Map.UnGuard();
721 }
722 }
723
724 return true;
725 }
726 /*}}}*/
727 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
728 // ---------------------------------------------------------------------
729 /* */
730 bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
731 {
732 unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
733 vector<pkgIndexFile *> Files;
734 unsigned long EndOfSource = Files.size();
735 if (_system->AddStatusFiles(Files) == false)
736 return false;
737
738 SPtr<DynamicMMap> Map;
739 Map = new DynamicMMap(MMap::Public,MapSize);
740 unsigned long CurrentSize = 0;
741 unsigned long TotalSize = 0;
742
743 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
744
745 // Build the status cache
746 Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
747 pkgCacheGenerator Gen(Map.Get(),&Progress);
748 if (_error->PendingError() == true)
749 return false;
750 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
751 Files.begin()+EndOfSource,Files.end()) == false)
752 return false;
753
754 if (_error->PendingError() == true)
755 return false;
756 *OutMap = Map.UnGuard();
757
758 return true;
759 }
760 /*}}}*/