]> git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
Fixed -- argument bug
[apt.git] / apt-pkg / pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: pkgcachegen.cc,v 1.49 2001/05/27 05:55:27 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 return true;
196 }
197 /*}}}*/
198 // CacheGenerator::NewPackage - Add a new package /*{{{*/
199 // ---------------------------------------------------------------------
200 /* This creates a new package structure and adds it to the hash table */
201 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
202 {
203 Pkg = Cache.FindPkg(Name);
204 if (Pkg.end() == false)
205 return true;
206
207 // Get a structure
208 unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
209 if (Package == 0)
210 return false;
211
212 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
213
214 // Insert it into the hash table
215 unsigned long Hash = Cache.Hash(Name);
216 Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
217 Cache.HeaderP->HashTable[Hash] = Package;
218
219 // Set the name and the ID
220 Pkg->Name = Map.WriteString(Name);
221 if (Pkg->Name == 0)
222 return false;
223 Pkg->ID = Cache.HeaderP->PackageCount++;
224
225 return true;
226 }
227 /*}}}*/
228 // CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
229 // ---------------------------------------------------------------------
230 /* */
231 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
232 ListParser &List)
233 {
234 if (CurrentFile == 0)
235 return true;
236
237 // Get a structure
238 unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
239 if (VerFile == 0)
240 return 0;
241
242 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
243 VF->File = CurrentFile - Cache.PkgFileP;
244
245 // Link it to the end of the list
246 map_ptrloc *Last = &Ver->FileList;
247 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++)
248 Last = &V->NextFile;
249 VF->NextFile = *Last;
250 *Last = VF.Index();
251
252 VF->Offset = List.Offset();
253 VF->Size = List.Size();
254 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
255 Cache.HeaderP->MaxVerFileSize = VF->Size;
256 Cache.HeaderP->VerFileCount++;
257
258 return true;
259 }
260 /*}}}*/
261 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
262 // ---------------------------------------------------------------------
263 /* This puts a version structure in the linked list */
264 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
265 string VerStr,
266 unsigned long Next)
267 {
268 // Get a structure
269 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
270 if (Version == 0)
271 return 0;
272
273 // Fill it in
274 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
275 Ver->NextVer = Next;
276 Ver->ID = Cache.HeaderP->VersionCount++;
277 Ver->VerStr = Map.WriteString(VerStr);
278 if (Ver->VerStr == 0)
279 return 0;
280
281 return Version;
282 }
283 /*}}}*/
284 // ListParser::NewDepends - Create a dependency element /*{{{*/
285 // ---------------------------------------------------------------------
286 /* This creates a dependency element in the tree. It is linked to the
287 version and to the package that it is pointing to. */
288 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
289 string PackageName,
290 string Version,
291 unsigned int Op,
292 unsigned int Type)
293 {
294 pkgCache &Cache = Owner->Cache;
295
296 // Get a structure
297 unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
298 if (Dependency == 0)
299 return false;
300
301 // Fill it in
302 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
303 Dep->ParentVer = Ver.Index();
304 Dep->Type = Type;
305 Dep->CompareOp = Op;
306 Dep->ID = Cache.HeaderP->DependsCount++;
307
308 // Locate the target package
309 pkgCache::PkgIterator Pkg;
310 if (Owner->NewPackage(Pkg,PackageName) == false)
311 return false;
312
313 // Probe the reverse dependency list for a version string that matches
314 if (Version.empty() == false)
315 {
316 /* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
317 if (I->Version != 0 && I.TargetVer() == Version)
318 Dep->Version = I->Version;*/
319 if (Dep->Version == 0)
320 if ((Dep->Version = WriteString(Version)) == 0)
321 return false;
322 }
323
324 // Link it to the package
325 Dep->Package = Pkg.Index();
326 Dep->NextRevDepends = Pkg->RevDepends;
327 Pkg->RevDepends = Dep.Index();
328
329 /* Link it to the version (at the end of the list)
330 Caching the old end point speeds up generation substantially */
331 if (OldDepVer != Ver)
332 {
333 OldDepLast = &Ver->DependsList;
334 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
335 OldDepLast = &D->NextDepends;
336 OldDepVer = Ver;
337 }
338
339 Dep->NextDepends = *OldDepLast;
340 *OldDepLast = Dep.Index();
341 OldDepLast = &Dep->NextDepends;
342
343 return true;
344 }
345 /*}}}*/
346 // ListParser::NewProvides - Create a Provides element /*{{{*/
347 // ---------------------------------------------------------------------
348 /* */
349 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
350 string PackageName,
351 string Version)
352 {
353 pkgCache &Cache = Owner->Cache;
354
355 // We do not add self referencing provides
356 if (Ver.ParentPkg().Name() == PackageName)
357 return true;
358
359 // Get a structure
360 unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
361 if (Provides == 0)
362 return false;
363 Cache.HeaderP->ProvidesCount++;
364
365 // Fill it in
366 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
367 Prv->Version = Ver.Index();
368 Prv->NextPkgProv = Ver->ProvidesList;
369 Ver->ProvidesList = Prv.Index();
370 if (Version.empty() == false && (Prv->ProvideVersion = WriteString(Version)) == 0)
371 return false;
372
373 // Locate the target package
374 pkgCache::PkgIterator Pkg;
375 if (Owner->NewPackage(Pkg,PackageName) == false)
376 return false;
377
378 // Link it to the package
379 Prv->ParentPkg = Pkg.Index();
380 Prv->NextProvides = Pkg->ProvidesList;
381 Pkg->ProvidesList = Prv.Index();
382
383 return true;
384 }
385 /*}}}*/
386 // CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
387 // ---------------------------------------------------------------------
388 /* This is used to select which file is to be associated with all newly
389 added versions. The caller is responsible for setting the IMS fields. */
390 bool pkgCacheGenerator::SelectFile(string File,string Site,
391 const pkgIndexFile &Index,
392 unsigned long Flags)
393 {
394 // Get some space for the structure
395 CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
396 if (CurrentFile == Cache.PkgFileP)
397 return false;
398
399 // Fill it in
400 CurrentFile->FileName = Map.WriteString(File);
401 CurrentFile->Site = WriteUniqString(Site);
402 CurrentFile->NextFile = Cache.HeaderP->FileList;
403 CurrentFile->Flags = Flags;
404 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
405 CurrentFile->IndexType = WriteUniqString(Index.GetType()->Label);
406 PkgFileName = File;
407 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
408 Cache.HeaderP->PackageFileCount++;
409
410 if (CurrentFile->FileName == 0)
411 return false;
412
413 if (Progress != 0)
414 Progress->SubProgress(Index.Size());
415 return true;
416 }
417 /*}}}*/
418 // CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
419 // ---------------------------------------------------------------------
420 /* This is used to create handles to strings. Given the same text it
421 always returns the same number */
422 unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
423 unsigned int Size)
424 {
425 /* We use a very small transient hash table here, this speeds up generation
426 by a fair amount on slower machines */
427 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
428 if (Bucket != 0 &&
429 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
430 return Bucket->String;
431
432 // Search for an insertion point
433 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
434 int Res = 1;
435 map_ptrloc *Last = &Cache.HeaderP->StringList;
436 for (; I != Cache.StringItemP; Last = &I->NextItem,
437 I = Cache.StringItemP + I->NextItem)
438 {
439 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
440 if (Res >= 0)
441 break;
442 }
443
444 // Match
445 if (Res == 0)
446 {
447 Bucket = I;
448 return I->String;
449 }
450
451 // Get a structure
452 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
453 if (Item == 0)
454 return 0;
455
456 // Fill in the structure
457 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
458 ItemP->NextItem = I - Cache.StringItemP;
459 *Last = Item;
460 ItemP->String = Map.WriteString(S,Size);
461 if (ItemP->String == 0)
462 return 0;
463
464 Bucket = ItemP;
465 return ItemP->String;
466 }
467 /*}}}*/
468
469 // CheckValidity - Check that a cache is up-to-date /*{{{*/
470 // ---------------------------------------------------------------------
471 /* This just verifies that each file in the list of index files exists,
472 has matching attributes with the cache and the cache does not have
473 any extra files. */
474 static bool CheckValidity(string CacheFile, FileIterator Start,
475 FileIterator End,MMap **OutMap = 0)
476 {
477 // No file, certainly invalid
478 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
479 return false;
480
481 // Map it
482 FileFd CacheF(CacheFile,FileFd::ReadOnly);
483 SPtr<MMap> Map = new MMap(CacheF,MMap::Public | MMap::ReadOnly);
484 pkgCache Cache(Map);
485 if (_error->PendingError() == true || Map->Size() == 0)
486 {
487 _error->Discard();
488 return false;
489 }
490
491 /* Now we check every index file, see if it is in the cache,
492 verify the IMS data and check that it is on the disk too.. */
493 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
494 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
495 for (; Start != End; Start++)
496 {
497 if ((*Start)->HasPackages() == false)
498 continue;
499
500 if ((*Start)->Exists() == false)
501 {
502 _error->WarningE("stat",_("Couldn't stat source package list %s"),
503 (*Start)->Describe().c_str());
504 continue;
505 }
506
507 // FindInCache is also expected to do an IMS check.
508 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
509 if (File.end() == true)
510 return false;
511
512 Visited[File->ID] = true;
513 }
514
515 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
516 if (Visited[I] == false)
517 return false;
518
519 if (_error->PendingError() == true)
520 {
521 _error->Discard();
522 return false;
523 }
524
525 if (OutMap != 0)
526 *OutMap = Map.UnGuard();
527 return true;
528 }
529 /*}}}*/
530 // ComputeSize - Compute the total size of a bunch of files /*{{{*/
531 // ---------------------------------------------------------------------
532 /* Size is kind of an abstract notion that is only used for the progress
533 meter */
534 static unsigned long ComputeSize(FileIterator Start,FileIterator End)
535 {
536 unsigned long TotalSize = 0;
537 for (; Start != End; Start++)
538 {
539 if ((*Start)->HasPackages() == false)
540 continue;
541 TotalSize += (*Start)->Size();
542 }
543 return TotalSize;
544 }
545 /*}}}*/
546 // BuildCache - Merge the list of index files into the cache /*{{{*/
547 // ---------------------------------------------------------------------
548 /* */
549 static bool BuildCache(pkgCacheGenerator &Gen,
550 OpProgress &Progress,
551 unsigned long &CurrentSize,unsigned long TotalSize,
552 FileIterator Start, FileIterator End)
553 {
554 for (; Start != End; Start++)
555 {
556 if ((*Start)->HasPackages() == false)
557 continue;
558
559 if ((*Start)->Exists() == false)
560 continue;
561
562 if ((*Start)->FindInCache(Gen.GetCache()).end() == false)
563 {
564 _error->Warning("Duplicate sources.list entry %s",
565 (*Start)->Describe().c_str());
566 continue;
567 }
568
569 unsigned long Size = (*Start)->Size();
570 Progress.OverallProgress(CurrentSize,TotalSize,Size,_("Reading Package Lists"));
571 CurrentSize += Size;
572
573 if ((*Start)->Merge(Gen,Progress) == false)
574 return false;
575 }
576
577 return true;
578 }
579 /*}}}*/
580 // MakeStatusCache - Construct the status cache /*{{{*/
581 // ---------------------------------------------------------------------
582 /* This makes sure that the status cache (the cache that has all
583 index files from the sources list and all local ones) is ready
584 to be mmaped. If OutMap is not zero then a MMap object representing
585 the cache will be stored there. This is pretty much mandetory if you
586 are using AllowMem. AllowMem lets the function be run as non-root
587 where it builds the cache 'fast' into a memory buffer. */
588 bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
589 MMap **OutMap,bool AllowMem)
590 {
591 unsigned long MapSize = _config->FindI("APT::Cache-Limit",6*1024*1024);
592
593 vector<pkgIndexFile *> Files(List.begin(),List.end());
594 unsigned long EndOfSource = Files.size();
595 if (_system->AddStatusFiles(Files) == false)
596 return false;
597
598 // Decide if we can write to the files..
599 string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
600 string SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
601
602 // Decide if we can write to the cache
603 bool Writeable = false;
604 if (CacheFile.empty() == false)
605 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
606 else
607 if (SrcCacheFile.empty() == false)
608 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
609
610 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
611 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
612
613 Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
614
615 // Cache is OK, Fin.
616 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
617 {
618 Progress.OverallProgress(1,1,1,_("Reading Package Lists"));
619 return true;
620 }
621
622 /* At this point we know we need to reconstruct the package cache,
623 begin. */
624 SPtr<FileFd> CacheF;
625 SPtr<DynamicMMap> Map;
626 if (Writeable == true && CacheFile.empty() == false)
627 {
628 unlink(CacheFile.c_str());
629 CacheF = new FileFd(CacheFile,FileFd::WriteEmpty);
630 Map = new DynamicMMap(*CacheF,MMap::Public,MapSize);
631 if (_error->PendingError() == true)
632 return false;
633 }
634 else
635 {
636 // Just build it in memory..
637 Map = new DynamicMMap(MMap::Public,MapSize);
638 }
639
640 // Lets try the source cache.
641 unsigned long CurrentSize = 0;
642 unsigned long TotalSize = 0;
643 if (CheckValidity(SrcCacheFile,Files.begin(),
644 Files.begin()+EndOfSource) == true)
645 {
646 // Preload the map with the source cache
647 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
648 if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
649 SCacheF.Size()) == false)
650 return false;
651
652 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
653
654 // Build the status cache
655 pkgCacheGenerator Gen(Map.Get(),&Progress);
656 if (_error->PendingError() == true)
657 return false;
658 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
659 Files.begin()+EndOfSource,Files.end()) == false)
660 return false;
661 }
662 else
663 {
664 TotalSize = ComputeSize(Files.begin(),Files.end());
665
666 // Build the source cache
667 pkgCacheGenerator Gen(Map.Get(),&Progress);
668 if (_error->PendingError() == true)
669 return false;
670 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
671 Files.begin(),Files.begin()+EndOfSource) == false)
672 return false;
673
674 // Write it back
675 if (Writeable == true && SrcCacheFile.empty() == false)
676 {
677 FileFd SCacheF(SrcCacheFile,FileFd::WriteEmpty);
678 if (_error->PendingError() == true)
679 return false;
680 // Write out the main data
681 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
682 return _error->Error(_("IO Error saving source cache"));
683 SCacheF.Sync();
684
685 // Write out the proper header
686 Gen.GetCache().HeaderP->Dirty = false;
687 if (SCacheF.Seek(0) == false ||
688 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
689 return _error->Error(_("IO Error saving source cache"));
690 SCacheF.Sync();
691 Gen.GetCache().HeaderP->Dirty = true;
692 }
693
694 // Build the status cache
695 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
696 Files.begin()+EndOfSource,Files.end()) == false)
697 return false;
698 }
699
700 if (_error->PendingError() == true)
701 return false;
702 if (OutMap != 0)
703 {
704 if (CacheF != 0)
705 {
706 delete Map.UnGuard();
707 *OutMap = new MMap(*CacheF,MMap::Public | MMap::ReadOnly);
708 }
709 else
710 {
711 *OutMap = Map.UnGuard();
712 }
713 }
714
715 return true;
716 }
717 /*}}}*/
718 // MakeOnlyStatusCache - Build a cache with just the status files /*{{{*/
719 // ---------------------------------------------------------------------
720 /* */
721 bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
722 {
723 unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
724 vector<pkgIndexFile *> Files;
725 unsigned long EndOfSource = Files.size();
726 if (_system->AddStatusFiles(Files) == false)
727 return false;
728
729 SPtr<DynamicMMap> Map;
730 Map = new DynamicMMap(MMap::Public,MapSize);
731 unsigned long CurrentSize = 0;
732 unsigned long TotalSize = 0;
733
734 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
735
736 // Build the status cache
737 Progress.OverallProgress(0,1,1,_("Reading Package Lists"));
738 pkgCacheGenerator Gen(Map.Get(),&Progress);
739 if (_error->PendingError() == true)
740 return false;
741 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
742 Files.begin()+EndOfSource,Files.end()) == false)
743 return false;
744
745 if (_error->PendingError() == true)
746 return false;
747 *OutMap = Map.UnGuard();
748
749 return true;
750 }
751 /*}}}*/