reorder includes: add <config.h> if needed and include it at first
[ntk/apt.git] / apt-pkg / pkgcachegen.cc
... / ...
CommitLineData
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
3// $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz 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#define APT_COMPATIBILITY 986
14#include <config.h>
15
16#include <apt-pkg/pkgcachegen.h>
17#include <apt-pkg/error.h>
18#include <apt-pkg/version.h>
19#include <apt-pkg/progress.h>
20#include <apt-pkg/sourcelist.h>
21#include <apt-pkg/configuration.h>
22#include <apt-pkg/aptconfiguration.h>
23#include <apt-pkg/strutl.h>
24#include <apt-pkg/sptr.h>
25#include <apt-pkg/pkgsystem.h>
26#include <apt-pkg/macros.h>
27#include <apt-pkg/tagfile.h>
28
29#include <vector>
30#include <sys/stat.h>
31#include <unistd.h>
32#include <errno.h>
33#include <stdio.h>
34
35#include <apti18n.h>
36 /*}}}*/
37typedef vector<pkgIndexFile *>::iterator FileIterator;
38template <typename Iter> std::vector<Iter*> pkgCacheGenerator::Dynamic<Iter>::toReMap;
39
40// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
41// ---------------------------------------------------------------------
42/* We set the dirty flag and make sure that is written to the disk */
43pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
44 Map(*pMap), Cache(pMap,false), Progress(Prog),
45 FoundFileDeps(0)
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 if (Map.RawAllocate(sizeof(pkgCache::Header)) == 0 && _error->PendingError() == true)
58 return;
59
60 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
61
62 // Starting header
63 *Cache.HeaderP = pkgCache::Header();
64 map_ptrloc const idxVerSysName = WriteStringInMap(_system->VS->Label);
65 Cache.HeaderP->VerSysName = idxVerSysName;
66 map_ptrloc const idxArchitecture = WriteStringInMap(_config->Find("APT::Architecture"));
67 Cache.HeaderP->Architecture = idxArchitecture;
68 if (unlikely(idxVerSysName == 0 || idxArchitecture == 0))
69 return;
70 Cache.ReMap();
71 }
72 else
73 {
74 // Map directly from the existing file
75 Cache.ReMap();
76 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
77 if (Cache.VS != _system->VS)
78 {
79 _error->Error(_("Cache has an incompatible versioning system"));
80 return;
81 }
82 }
83
84 Cache.HeaderP->Dirty = true;
85 Map.Sync(0,sizeof(pkgCache::Header));
86}
87 /*}}}*/
88// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
89// ---------------------------------------------------------------------
90/* We sync the data then unset the dirty flag in two steps so as to
91 advoid a problem during a crash */
92pkgCacheGenerator::~pkgCacheGenerator()
93{
94 if (_error->PendingError() == true)
95 return;
96 if (Map.Sync() == false)
97 return;
98
99 Cache.HeaderP->Dirty = false;
100 Map.Sync(0,sizeof(pkgCache::Header));
101}
102 /*}}}*/
103void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newMap) {/*{{{*/
104 if (oldMap == newMap)
105 return;
106
107 Cache.ReMap(false);
108
109 CurrentFile += (pkgCache::PackageFile*) newMap - (pkgCache::PackageFile*) oldMap;
110
111 for (size_t i = 0; i < _count(UniqHash); ++i)
112 if (UniqHash[i] != 0)
113 UniqHash[i] += (pkgCache::StringItem*) newMap - (pkgCache::StringItem*) oldMap;
114
115 for (std::vector<pkgCache::GrpIterator*>::const_iterator i = Dynamic<pkgCache::GrpIterator>::toReMap.begin();
116 i != Dynamic<pkgCache::GrpIterator>::toReMap.end(); ++i)
117 (*i)->ReMap(oldMap, newMap);
118 for (std::vector<pkgCache::PkgIterator*>::const_iterator i = Dynamic<pkgCache::PkgIterator>::toReMap.begin();
119 i != Dynamic<pkgCache::PkgIterator>::toReMap.end(); ++i)
120 (*i)->ReMap(oldMap, newMap);
121 for (std::vector<pkgCache::VerIterator*>::const_iterator i = Dynamic<pkgCache::VerIterator>::toReMap.begin();
122 i != Dynamic<pkgCache::VerIterator>::toReMap.end(); ++i)
123 (*i)->ReMap(oldMap, newMap);
124 for (std::vector<pkgCache::DepIterator*>::const_iterator i = Dynamic<pkgCache::DepIterator>::toReMap.begin();
125 i != Dynamic<pkgCache::DepIterator>::toReMap.end(); ++i)
126 (*i)->ReMap(oldMap, newMap);
127 for (std::vector<pkgCache::DescIterator*>::const_iterator i = Dynamic<pkgCache::DescIterator>::toReMap.begin();
128 i != Dynamic<pkgCache::DescIterator>::toReMap.end(); ++i)
129 (*i)->ReMap(oldMap, newMap);
130 for (std::vector<pkgCache::PrvIterator*>::const_iterator i = Dynamic<pkgCache::PrvIterator>::toReMap.begin();
131 i != Dynamic<pkgCache::PrvIterator>::toReMap.end(); ++i)
132 (*i)->ReMap(oldMap, newMap);
133 for (std::vector<pkgCache::PkgFileIterator*>::const_iterator i = Dynamic<pkgCache::PkgFileIterator>::toReMap.begin();
134 i != Dynamic<pkgCache::PkgFileIterator>::toReMap.end(); ++i)
135 (*i)->ReMap(oldMap, newMap);
136} /*}}}*/
137// CacheGenerator::WriteStringInMap /*{{{*/
138map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String,
139 const unsigned long &Len) {
140 void const * const oldMap = Map.Data();
141 map_ptrloc const index = Map.WriteString(String, Len);
142 if (index != 0)
143 ReMap(oldMap, Map.Data());
144 return index;
145}
146 /*}}}*/
147// CacheGenerator::WriteStringInMap /*{{{*/
148map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String) {
149 void const * const oldMap = Map.Data();
150 map_ptrloc const index = Map.WriteString(String);
151 if (index != 0)
152 ReMap(oldMap, Map.Data());
153 return index;
154}
155 /*}}}*/
156map_ptrloc pkgCacheGenerator::AllocateInMap(const unsigned long &size) {/*{{{*/
157 void const * const oldMap = Map.Data();
158 map_ptrloc const index = Map.Allocate(size);
159 if (index != 0)
160 ReMap(oldMap, Map.Data());
161 return index;
162}
163 /*}}}*/
164// CacheGenerator::MergeList - Merge the package list /*{{{*/
165// ---------------------------------------------------------------------
166/* This provides the generation of the entries in the cache. Each loop
167 goes through a single package record from the underlying parse engine. */
168bool pkgCacheGenerator::MergeList(ListParser &List,
169 pkgCache::VerIterator *OutVer)
170{
171 List.Owner = this;
172
173 unsigned int Counter = 0;
174 while (List.Step() == true)
175 {
176 string const PackageName = List.Package();
177 if (PackageName.empty() == true)
178 return false;
179
180 string const Arch = List.Architecture();
181
182 // Get a pointer to the package structure
183 pkgCache::PkgIterator Pkg;
184 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
185 if (NewPackage(Pkg, PackageName, Arch) == false)
186 return _error->Error(_("Error occurred while processing %s (NewPackage)"),PackageName.c_str());
187 Counter++;
188 if (Counter % 100 == 0 && Progress != 0)
189 Progress->Progress(List.Offset());
190
191 /* Get a pointer to the version structure. We know the list is sorted
192 so we use that fact in the search. Insertion of new versions is
193 done with correct sorting */
194 string Version = List.Version();
195 if (Version.empty() == true)
196 {
197 // we first process the package, then the descriptions
198 // (this has the bonus that we get MMap error when we run out
199 // of MMap space)
200 pkgCache::VerIterator Ver(Cache);
201 Dynamic<pkgCache::VerIterator> DynVer(Ver);
202 if (List.UsePackage(Pkg, Ver) == false)
203 return _error->Error(_("Error occurred while processing %s (UsePackage1)"),
204 PackageName.c_str());
205
206 // Find the right version to write the description
207 MD5SumValue CurMd5 = List.Description_md5();
208 Ver = Pkg.VersionList();
209
210 for (; Ver.end() == false; ++Ver)
211 {
212 pkgCache::DescIterator Desc = Ver.DescriptionList();
213 Dynamic<pkgCache::DescIterator> DynDesc(Desc);
214 map_ptrloc *LastDesc = &Ver->DescriptionList;
215 bool duplicate=false;
216
217 // don't add a new description if we have one for the given
218 // md5 && language
219 for ( ; Desc.end() == false; Desc++)
220 if (MD5SumValue(Desc.md5()) == CurMd5 &&
221 Desc.LanguageCode() == List.DescriptionLanguage())
222 duplicate=true;
223 if(duplicate)
224 continue;
225
226 for (Desc = Ver.DescriptionList();
227 Desc.end() == false;
228 LastDesc = &Desc->NextDesc, Desc++)
229 {
230 if (MD5SumValue(Desc.md5()) == CurMd5)
231 {
232 // Add new description
233 void const * const oldMap = Map.Data();
234 map_ptrloc const descindex = NewDescription(Desc, List.DescriptionLanguage(), CurMd5, *LastDesc);
235 if (oldMap != Map.Data())
236 LastDesc += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap;
237 *LastDesc = descindex;
238 Desc->ParentPkg = Pkg.Index();
239
240 if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false)
241 return _error->Error(_("Error occurred while processing %s (NewFileDesc1)"),PackageName.c_str());
242 break;
243 }
244 }
245 }
246
247 continue;
248 }
249
250 pkgCache::VerIterator Ver = Pkg.VersionList();
251 Dynamic<pkgCache::VerIterator> DynVer(Ver);
252 map_ptrloc *LastVer = &Pkg->VersionList;
253 void const * oldMap = Map.Data();
254 int Res = 1;
255 unsigned long const Hash = List.VersionHash();
256 for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
257 {
258 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
259 // Version is higher as current version - insert here
260 if (Res > 0)
261 break;
262 // Versionstrings are equal - is hash also equal?
263 if (Res == 0 && Ver->Hash == Hash)
264 break;
265 // proceed with the next till we have either the right
266 // or we found another version (which will be lower)
267 }
268
269 /* We already have a version for this item, record that we saw it */
270 if (Res == 0 && Ver.end() == false && Ver->Hash == Hash)
271 {
272 if (List.UsePackage(Pkg,Ver) == false)
273 return _error->Error(_("Error occurred while processing %s (UsePackage2)"),
274 PackageName.c_str());
275
276 if (NewFileVer(Ver,List) == false)
277 return _error->Error(_("Error occurred while processing %s (NewFileVer1)"),
278 PackageName.c_str());
279
280 // Read only a single record and return
281 if (OutVer != 0)
282 {
283 *OutVer = Ver;
284 FoundFileDeps |= List.HasFileDeps();
285 return true;
286 }
287
288 continue;
289 }
290
291 // Add a new version
292 map_ptrloc const verindex = NewVersion(Ver,Version,*LastVer);
293 if (verindex == 0 && _error->PendingError())
294 return _error->Error(_("Error occurred while processing %s (NewVersion%d)"),
295 PackageName.c_str(), 1);
296
297 if (oldMap != Map.Data())
298 LastVer += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap;
299 *LastVer = verindex;
300 Ver->ParentPkg = Pkg.Index();
301 Ver->Hash = Hash;
302
303 if (List.NewVersion(Ver) == false)
304 return _error->Error(_("Error occurred while processing %s (NewVersion%d)"),
305 PackageName.c_str(), 2);
306
307 if (List.UsePackage(Pkg,Ver) == false)
308 return _error->Error(_("Error occurred while processing %s (UsePackage3)"),
309 PackageName.c_str());
310
311 if (NewFileVer(Ver,List) == false)
312 return _error->Error(_("Error occurred while processing %s (NewVersion%d)"),
313 PackageName.c_str(), 3);
314
315 // Read only a single record and return
316 if (OutVer != 0)
317 {
318 *OutVer = Ver;
319 FoundFileDeps |= List.HasFileDeps();
320 return true;
321 }
322
323 /* Record the Description data. Description data always exist in
324 Packages and Translation-* files. */
325 pkgCache::DescIterator Desc = Ver.DescriptionList();
326 Dynamic<pkgCache::DescIterator> DynDesc(Desc);
327 map_ptrloc *LastDesc = &Ver->DescriptionList;
328
329 // Skip to the end of description set
330 for (; Desc.end() == false; LastDesc = &Desc->NextDesc, Desc++);
331
332 // Add new description
333 oldMap = Map.Data();
334 map_ptrloc const descindex = NewDescription(Desc, List.DescriptionLanguage(), List.Description_md5(), *LastDesc);
335 if (oldMap != Map.Data())
336 LastDesc += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap;
337 *LastDesc = descindex;
338 Desc->ParentPkg = Pkg.Index();
339
340 if ((*LastDesc == 0 && _error->PendingError()) || NewFileDesc(Desc,List) == false)
341 return _error->Error(_("Error occurred while processing %s (NewFileDesc2)"),PackageName.c_str());
342 }
343
344 FoundFileDeps |= List.HasFileDeps();
345
346 if (Cache.HeaderP->PackageCount >= (1ULL<<sizeof(Cache.PkgP->ID)*8)-1)
347 return _error->Error(_("Wow, you exceeded the number of package "
348 "names this APT is capable of."));
349 if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
350 return _error->Error(_("Wow, you exceeded the number of versions "
351 "this APT is capable of."));
352 if (Cache.HeaderP->DescriptionCount >= (1ULL<<(sizeof(Cache.DescP->ID)*8))-1)
353 return _error->Error(_("Wow, you exceeded the number of descriptions "
354 "this APT is capable of."));
355 if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
356 return _error->Error(_("Wow, you exceeded the number of dependencies "
357 "this APT is capable of."));
358 return true;
359}
360 /*}}}*/
361// CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
362// ---------------------------------------------------------------------
363/* If we found any file depends while parsing the main list we need to
364 resolve them. Since it is undesired to load the entire list of files
365 into the cache as virtual packages we do a two stage effort. MergeList
366 identifies the file depends and this creates Provdies for them by
367 re-parsing all the indexs. */
368bool pkgCacheGenerator::MergeFileProvides(ListParser &List)
369{
370 List.Owner = this;
371
372 unsigned int Counter = 0;
373 while (List.Step() == true)
374 {
375 string PackageName = List.Package();
376 if (PackageName.empty() == true)
377 return false;
378 string Version = List.Version();
379 if (Version.empty() == true)
380 continue;
381
382 pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
383 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
384 if (Pkg.end() == true)
385 return _error->Error(_("Error occurred while processing %s (FindPkg)"),
386 PackageName.c_str());
387 Counter++;
388 if (Counter % 100 == 0 && Progress != 0)
389 Progress->Progress(List.Offset());
390
391 unsigned long Hash = List.VersionHash();
392 pkgCache::VerIterator Ver = Pkg.VersionList();
393 Dynamic<pkgCache::VerIterator> DynVer(Ver);
394 for (; Ver.end() == false; Ver++)
395 {
396 if (Ver->Hash == Hash && Version.c_str() == Ver.VerStr())
397 {
398 if (List.CollectFileProvides(Cache,Ver) == false)
399 return _error->Error(_("Error occurred while processing %s (CollectFileProvides)"),PackageName.c_str());
400 break;
401 }
402 }
403
404 if (Ver.end() == true)
405 _error->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName.c_str(),Version.c_str());
406 }
407
408 return true;
409}
410 /*}}}*/
411// CacheGenerator::NewGroup - Add a new group /*{{{*/
412// ---------------------------------------------------------------------
413/* This creates a new group structure and adds it to the hash table */
414bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name)
415{
416 Grp = Cache.FindGrp(Name);
417 if (Grp.end() == false)
418 return true;
419
420 // Get a structure
421 map_ptrloc const Group = AllocateInMap(sizeof(pkgCache::Group));
422 if (unlikely(Group == 0))
423 return false;
424
425 Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
426 map_ptrloc const idxName = WriteStringInMap(Name);
427 if (unlikely(idxName == 0))
428 return false;
429 Grp->Name = idxName;
430
431 // Insert it into the hash table
432 unsigned long const Hash = Cache.Hash(Name);
433 Grp->Next = Cache.HeaderP->GrpHashTable[Hash];
434 Cache.HeaderP->GrpHashTable[Hash] = Group;
435
436 Grp->ID = Cache.HeaderP->GroupCount++;
437 return true;
438}
439 /*}}}*/
440// CacheGenerator::NewPackage - Add a new package /*{{{*/
441// ---------------------------------------------------------------------
442/* This creates a new package structure and adds it to the hash table */
443bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name,
444 const string &Arch) {
445 pkgCache::GrpIterator Grp;
446 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
447 if (unlikely(NewGroup(Grp, Name) == false))
448 return false;
449
450 Pkg = Grp.FindPkg(Arch);
451 if (Pkg.end() == false)
452 return true;
453
454 // Get a structure
455 map_ptrloc const Package = AllocateInMap(sizeof(pkgCache::Package));
456 if (unlikely(Package == 0))
457 return false;
458 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
459
460 // Insert the package into our package list
461 if (Grp->FirstPackage == 0) // the group is new
462 {
463 // Insert it into the hash table
464 unsigned long const Hash = Cache.Hash(Name);
465 Pkg->NextPackage = Cache.HeaderP->PkgHashTable[Hash];
466 Cache.HeaderP->PkgHashTable[Hash] = Package;
467 Grp->FirstPackage = Package;
468 }
469 else // Group the Packages together
470 {
471 // this package is the new last package
472 pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
473 Pkg->NextPackage = LastPkg->NextPackage;
474 LastPkg->NextPackage = Package;
475 }
476 Grp->LastPackage = Package;
477
478 // Set the name, arch and the ID
479 Pkg->Name = Grp->Name;
480 Pkg->Group = Grp.Index();
481 // all is mapped to the native architecture
482 map_ptrloc const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : WriteUniqString(Arch.c_str());
483 if (unlikely(idxArch == 0))
484 return false;
485 Pkg->Arch = idxArch;
486 Pkg->ID = Cache.HeaderP->PackageCount++;
487
488 return true;
489}
490 /*}}}*/
491// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
492// ---------------------------------------------------------------------
493/* */
494bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
495 ListParser &List)
496{
497 if (CurrentFile == 0)
498 return true;
499
500 // Get a structure
501 map_ptrloc const VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
502 if (VerFile == 0)
503 return 0;
504
505 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
506 VF->File = CurrentFile - Cache.PkgFileP;
507
508 // Link it to the end of the list
509 map_ptrloc *Last = &Ver->FileList;
510 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++)
511 Last = &V->NextFile;
512 VF->NextFile = *Last;
513 *Last = VF.Index();
514
515 VF->Offset = List.Offset();
516 VF->Size = List.Size();
517 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
518 Cache.HeaderP->MaxVerFileSize = VF->Size;
519 Cache.HeaderP->VerFileCount++;
520
521 return true;
522}
523 /*}}}*/
524// CacheGenerator::NewVersion - Create a new Version /*{{{*/
525// ---------------------------------------------------------------------
526/* This puts a version structure in the linked list */
527unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
528 const string &VerStr,
529 unsigned long Next)
530{
531 // Get a structure
532 map_ptrloc const Version = AllocateInMap(sizeof(pkgCache::Version));
533 if (Version == 0)
534 return 0;
535
536 // Fill it in
537 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
538 Ver->NextVer = Next;
539 Ver->ID = Cache.HeaderP->VersionCount++;
540 map_ptrloc const idxVerStr = WriteStringInMap(VerStr);
541 if (unlikely(idxVerStr == 0))
542 return 0;
543 Ver->VerStr = idxVerStr;
544
545 return Version;
546}
547 /*}}}*/
548// CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
549// ---------------------------------------------------------------------
550/* */
551bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
552 ListParser &List)
553{
554 if (CurrentFile == 0)
555 return true;
556
557 // Get a structure
558 map_ptrloc const DescFile = AllocateInMap(sizeof(pkgCache::DescFile));
559 if (DescFile == 0)
560 return false;
561
562 pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
563 DF->File = CurrentFile - Cache.PkgFileP;
564
565 // Link it to the end of the list
566 map_ptrloc *Last = &Desc->FileList;
567 for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; D++)
568 Last = &D->NextFile;
569
570 DF->NextFile = *Last;
571 *Last = DF.Index();
572
573 DF->Offset = List.Offset();
574 DF->Size = List.Size();
575 if (Cache.HeaderP->MaxDescFileSize < DF->Size)
576 Cache.HeaderP->MaxDescFileSize = DF->Size;
577 Cache.HeaderP->DescFileCount++;
578
579 return true;
580}
581 /*}}}*/
582// CacheGenerator::NewDescription - Create a new Description /*{{{*/
583// ---------------------------------------------------------------------
584/* This puts a description structure in the linked list */
585map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
586 const string &Lang,
587 const MD5SumValue &md5sum,
588 map_ptrloc Next)
589{
590 // Get a structure
591 map_ptrloc const Description = AllocateInMap(sizeof(pkgCache::Description));
592 if (Description == 0)
593 return 0;
594
595 // Fill it in
596 Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
597 Desc->NextDesc = Next;
598 Desc->ID = Cache.HeaderP->DescriptionCount++;
599 map_ptrloc const idxlanguage_code = WriteStringInMap(Lang);
600 map_ptrloc const idxmd5sum = WriteStringInMap(md5sum.Value());
601 if (unlikely(idxlanguage_code == 0 || idxmd5sum == 0))
602 return 0;
603 Desc->language_code = idxlanguage_code;
604 Desc->md5sum = idxmd5sum;
605
606 return Description;
607}
608 /*}}}*/
609// CacheGenerator::FinishCache - do various finish operations /*{{{*/
610// ---------------------------------------------------------------------
611/* This prepares the Cache for delivery */
612bool pkgCacheGenerator::FinishCache(OpProgress *Progress)
613{
614 // FIXME: add progress reporting for this operation
615 // Do we have different architectures in your groups ?
616 vector<string> archs = APT::Configuration::getArchitectures();
617 if (archs.size() > 1)
618 {
619 // Create Conflicts in between the group
620 pkgCache::GrpIterator G = GetCache().GrpBegin();
621 Dynamic<pkgCache::GrpIterator> DynG(G);
622 for (; G.end() != true; G++)
623 {
624 string const PkgName = G.Name();
625 pkgCache::PkgIterator P = G.PackageList();
626 Dynamic<pkgCache::PkgIterator> DynP(P);
627 for (; P.end() != true; P = G.NextPkg(P))
628 {
629 pkgCache::PkgIterator allPkg;
630 Dynamic<pkgCache::PkgIterator> DynallPkg(allPkg);
631 pkgCache::VerIterator V = P.VersionList();
632 Dynamic<pkgCache::VerIterator> DynV(V);
633 for (; V.end() != true; V++)
634 {
635 char const * const Arch = P.Arch();
636 map_ptrloc *OldDepLast = NULL;
637 /* MultiArch handling introduces a lot of implicit Dependencies:
638 - MultiArch: same → Co-Installable if they have the same version
639 - Architecture: all → Need to be Co-Installable for internal reasons
640 - All others conflict with all other group members */
641 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
642 for (vector<string>::const_iterator A = archs.begin(); A != archs.end(); ++A)
643 {
644 if (Arch == 0 || *A == Arch)
645 continue;
646 /* We allow only one installed arch at the time
647 per group, therefore each group member conflicts
648 with all other group members */
649 pkgCache::PkgIterator D = G.FindPkg(*A);
650 Dynamic<pkgCache::PkgIterator> DynD(D);
651 if (D.end() == true)
652 continue;
653 if (coInstall == true)
654 {
655 // Replaces: ${self}:other ( << ${binary:Version})
656 NewDepends(D, V, V.VerStr(),
657 pkgCache::Dep::Less, pkgCache::Dep::Replaces,
658 OldDepLast);
659 // Breaks: ${self}:other (!= ${binary:Version})
660 NewDepends(D, V, V.VerStr(),
661 pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks,
662 OldDepLast);
663 } else {
664 // Conflicts: ${self}:other
665 NewDepends(D, V, "",
666 pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
667 OldDepLast);
668 }
669 }
670 }
671 }
672 }
673 }
674 return true;
675}
676 /*}}}*/
677// CacheGenerator::NewDepends - Create a dependency element /*{{{*/
678// ---------------------------------------------------------------------
679/* This creates a dependency element in the tree. It is linked to the
680 version and to the package that it is pointing to. */
681bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
682 pkgCache::VerIterator &Ver,
683 string const &Version,
684 unsigned int const &Op,
685 unsigned int const &Type,
686 map_ptrloc *OldDepLast)
687{
688 void const * const oldMap = Map.Data();
689 // Get a structure
690 map_ptrloc const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
691 if (unlikely(Dependency == 0))
692 return false;
693
694 // Fill it in
695 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
696 Dynamic<pkgCache::DepIterator> DynDep(Dep);
697 Dep->ParentVer = Ver.Index();
698 Dep->Type = Type;
699 Dep->CompareOp = Op;
700 Dep->ID = Cache.HeaderP->DependsCount++;
701
702 // Probe the reverse dependency list for a version string that matches
703 if (Version.empty() == false)
704 {
705/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
706 if (I->Version != 0 && I.TargetVer() == Version)
707 Dep->Version = I->Version;*/
708 if (Dep->Version == 0) {
709 map_ptrloc const index = WriteStringInMap(Version);
710 if (unlikely(index == 0))
711 return false;
712 Dep->Version = index;
713 }
714 }
715
716 // Link it to the package
717 Dep->Package = Pkg.Index();
718 Dep->NextRevDepends = Pkg->RevDepends;
719 Pkg->RevDepends = Dep.Index();
720
721 // Do we know where to link the Dependency to?
722 if (OldDepLast == NULL)
723 {
724 OldDepLast = &Ver->DependsList;
725 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
726 OldDepLast = &D->NextDepends;
727 } else if (oldMap != Map.Data())
728 OldDepLast += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap;
729
730 Dep->NextDepends = *OldDepLast;
731 *OldDepLast = Dep.Index();
732 OldDepLast = &Dep->NextDepends;
733
734 return true;
735}
736 /*}}}*/
737// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
738// ---------------------------------------------------------------------
739/* This creates a Group and the Package to link this dependency to if
740 needed and handles also the caching of the old endpoint */
741bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver,
742 const string &PackageName,
743 const string &Arch,
744 const string &Version,
745 unsigned int Op,
746 unsigned int Type)
747{
748 pkgCache::GrpIterator Grp;
749 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
750 if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
751 return false;
752
753 // Locate the target package
754 pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
755 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
756 if (Pkg.end() == true) {
757 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
758 return false;
759 }
760
761 // Is it a file dependency?
762 if (unlikely(PackageName[0] == '/'))
763 FoundFileDeps = true;
764
765 /* Caching the old end point speeds up generation substantially */
766 if (OldDepVer != Ver) {
767 OldDepLast = NULL;
768 OldDepVer = Ver;
769 }
770
771 return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
772}
773 /*}}}*/
774// ListParser::NewProvides - Create a Provides element /*{{{*/
775// ---------------------------------------------------------------------
776/* */
777bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
778 const string &PkgName,
779 const string &PkgArch,
780 const string &Version)
781{
782 pkgCache &Cache = Owner->Cache;
783
784 // We do not add self referencing provides
785 if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
786 (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
787 return true;
788
789 // Get a structure
790 map_ptrloc const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
791 if (unlikely(Provides == 0))
792 return false;
793 Cache.HeaderP->ProvidesCount++;
794
795 // Fill it in
796 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
797 Dynamic<pkgCache::PrvIterator> DynPrv(Prv);
798 Prv->Version = Ver.Index();
799 Prv->NextPkgProv = Ver->ProvidesList;
800 Ver->ProvidesList = Prv.Index();
801 if (Version.empty() == false && unlikely((Prv->ProvideVersion = WriteString(Version)) == 0))
802 return false;
803
804 // Locate the target package
805 pkgCache::PkgIterator Pkg;
806 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
807 if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
808 return false;
809
810 // Link it to the package
811 Prv->ParentPkg = Pkg.Index();
812 Prv->NextProvides = Pkg->ProvidesList;
813 Pkg->ProvidesList = Prv.Index();
814
815 return true;
816}
817 /*}}}*/
818// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
819// ---------------------------------------------------------------------
820/* This is used to select which file is to be associated with all newly
821 added versions. The caller is responsible for setting the IMS fields. */
822bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
823 const pkgIndexFile &Index,
824 unsigned long Flags)
825{
826 // Get some space for the structure
827 map_ptrloc const idxFile = AllocateInMap(sizeof(*CurrentFile));
828 if (unlikely(idxFile == 0))
829 return false;
830 CurrentFile = Cache.PkgFileP + idxFile;
831
832 // Fill it in
833 map_ptrloc const idxFileName = WriteStringInMap(File);
834 map_ptrloc const idxSite = WriteUniqString(Site);
835 if (unlikely(idxFileName == 0 || idxSite == 0))
836 return false;
837 CurrentFile->FileName = idxFileName;
838 CurrentFile->Site = idxSite;
839 CurrentFile->NextFile = Cache.HeaderP->FileList;
840 CurrentFile->Flags = Flags;
841 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
842 map_ptrloc const idxIndexType = WriteUniqString(Index.GetType()->Label);
843 if (unlikely(idxIndexType == 0))
844 return false;
845 CurrentFile->IndexType = idxIndexType;
846 PkgFileName = File;
847 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
848 Cache.HeaderP->PackageFileCount++;
849
850 if (Progress != 0)
851 Progress->SubProgress(Index.Size());
852 return true;
853}
854 /*}}}*/
855// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
856// ---------------------------------------------------------------------
857/* This is used to create handles to strings. Given the same text it
858 always returns the same number */
859unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
860 unsigned int Size)
861{
862 /* We use a very small transient hash table here, this speeds up generation
863 by a fair amount on slower machines */
864 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
865 if (Bucket != 0 &&
866 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
867 return Bucket->String;
868
869 // Search for an insertion point
870 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
871 int Res = 1;
872 map_ptrloc *Last = &Cache.HeaderP->StringList;
873 for (; I != Cache.StringItemP; Last = &I->NextItem,
874 I = Cache.StringItemP + I->NextItem)
875 {
876 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
877 if (Res >= 0)
878 break;
879 }
880
881 // Match
882 if (Res == 0)
883 {
884 Bucket = I;
885 return I->String;
886 }
887
888 // Get a structure
889 void const * const oldMap = Map.Data();
890 map_ptrloc const Item = AllocateInMap(sizeof(pkgCache::StringItem));
891 if (Item == 0)
892 return 0;
893
894 map_ptrloc const idxString = WriteStringInMap(S,Size);
895 if (unlikely(idxString == 0))
896 return 0;
897 if (oldMap != Map.Data()) {
898 Last += (map_ptrloc*) Map.Data() - (map_ptrloc*) oldMap;
899 I += (pkgCache::StringItem*) Map.Data() - (pkgCache::StringItem*) oldMap;
900 }
901 *Last = Item;
902
903 // Fill in the structure
904 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
905 ItemP->NextItem = I - Cache.StringItemP;
906 ItemP->String = idxString;
907
908 Bucket = ItemP;
909 return ItemP->String;
910}
911 /*}}}*/
912// CheckValidity - Check that a cache is up-to-date /*{{{*/
913// ---------------------------------------------------------------------
914/* This just verifies that each file in the list of index files exists,
915 has matching attributes with the cache and the cache does not have
916 any extra files. */
917static bool CheckValidity(const string &CacheFile, FileIterator Start,
918 FileIterator End,MMap **OutMap = 0)
919{
920 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
921 // No file, certainly invalid
922 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
923 {
924 if (Debug == true)
925 std::clog << "CacheFile doesn't exist" << std::endl;
926 return false;
927 }
928
929 // Map it
930 FileFd CacheF(CacheFile,FileFd::ReadOnly);
931 SPtr<MMap> Map = new MMap(CacheF,0);
932 pkgCache Cache(Map);
933 if (_error->PendingError() == true || Map->Size() == 0)
934 {
935 if (Debug == true)
936 std::clog << "Errors are pending or Map is empty()" << std::endl;
937 _error->Discard();
938 return false;
939 }
940
941 /* Now we check every index file, see if it is in the cache,
942 verify the IMS data and check that it is on the disk too.. */
943 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
944 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
945 for (; Start != End; Start++)
946 {
947 if (Debug == true)
948 std::clog << "Checking PkgFile " << (*Start)->Describe() << ": ";
949 if ((*Start)->HasPackages() == false)
950 {
951 if (Debug == true)
952 std::clog << "Has NO packages" << std::endl;
953 continue;
954 }
955
956 if ((*Start)->Exists() == false)
957 {
958#if 0 // mvo: we no longer give a message here (Default Sources spec)
959 _error->WarningE("stat",_("Couldn't stat source package list %s"),
960 (*Start)->Describe().c_str());
961#endif
962 if (Debug == true)
963 std::clog << "file doesn't exist" << std::endl;
964 continue;
965 }
966
967 // FindInCache is also expected to do an IMS check.
968 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
969 if (File.end() == true)
970 {
971 if (Debug == true)
972 std::clog << "FindInCache returned end-Pointer" << std::endl;
973 return false;
974 }
975
976 Visited[File->ID] = true;
977 if (Debug == true)
978 std::clog << "with ID " << File->ID << " is valid" << std::endl;
979 }
980
981 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
982 if (Visited[I] == false)
983 {
984 if (Debug == true)
985 std::clog << "File with ID" << I << " wasn't visited" << std::endl;
986 return false;
987 }
988
989 if (_error->PendingError() == true)
990 {
991 if (Debug == true)
992 {
993 std::clog << "Validity failed because of pending errors:" << std::endl;
994 _error->DumpErrors();
995 }
996 _error->Discard();
997 return false;
998 }
999
1000 if (OutMap != 0)
1001 *OutMap = Map.UnGuard();
1002 return true;
1003}
1004 /*}}}*/
1005// ComputeSize - Compute the total size of a bunch of files /*{{{*/
1006// ---------------------------------------------------------------------
1007/* Size is kind of an abstract notion that is only used for the progress
1008 meter */
1009static unsigned long ComputeSize(FileIterator Start,FileIterator End)
1010{
1011 unsigned long TotalSize = 0;
1012 for (; Start != End; Start++)
1013 {
1014 if ((*Start)->HasPackages() == false)
1015 continue;
1016 TotalSize += (*Start)->Size();
1017 }
1018 return TotalSize;
1019}
1020 /*}}}*/
1021// BuildCache - Merge the list of index files into the cache /*{{{*/
1022// ---------------------------------------------------------------------
1023/* */
1024static bool BuildCache(pkgCacheGenerator &Gen,
1025 OpProgress *Progress,
1026 unsigned long &CurrentSize,unsigned long TotalSize,
1027 FileIterator Start, FileIterator End)
1028{
1029 FileIterator I;
1030 for (I = Start; I != End; I++)
1031 {
1032 if ((*I)->HasPackages() == false)
1033 continue;
1034
1035 if ((*I)->Exists() == false)
1036 continue;
1037
1038 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
1039 {
1040 _error->Warning("Duplicate sources.list entry %s",
1041 (*I)->Describe().c_str());
1042 continue;
1043 }
1044
1045 unsigned long Size = (*I)->Size();
1046 if (Progress != NULL)
1047 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
1048 CurrentSize += Size;
1049
1050 if ((*I)->Merge(Gen,Progress) == false)
1051 return false;
1052 }
1053
1054 if (Gen.HasFileDeps() == true)
1055 {
1056 if (Progress != NULL)
1057 Progress->Done();
1058 TotalSize = ComputeSize(Start, End);
1059 CurrentSize = 0;
1060 for (I = Start; I != End; I++)
1061 {
1062 unsigned long Size = (*I)->Size();
1063 if (Progress != NULL)
1064 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
1065 CurrentSize += Size;
1066 if ((*I)->MergeFileProvides(Gen,Progress) == false)
1067 return false;
1068 }
1069 }
1070
1071 return true;
1072}
1073 /*}}}*/
1074// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
1075DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) {
1076 unsigned long const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1077 unsigned long const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1078 unsigned long const MapLimit = _config->FindI("APT::Cache-Limit", 0);
1079 Flags |= MMap::Moveable;
1080 if (_config->FindB("APT::Cache-Fallback", false) == true)
1081 Flags |= MMap::Fallback;
1082 if (CacheF != NULL)
1083 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1084 else
1085 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1086}
1087 /*}}}*/
1088// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
1089// ---------------------------------------------------------------------
1090/* This makes sure that the status cache (the cache that has all
1091 index files from the sources list and all local ones) is ready
1092 to be mmaped. If OutMap is not zero then a MMap object representing
1093 the cache will be stored there. This is pretty much mandetory if you
1094 are using AllowMem. AllowMem lets the function be run as non-root
1095 where it builds the cache 'fast' into a memory buffer. */
1096__deprecated bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
1097 MMap **OutMap, bool AllowMem)
1098 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1099bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
1100 MMap **OutMap,bool AllowMem)
1101{
1102 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
1103
1104 vector<pkgIndexFile *> Files;
1105 for (vector<metaIndex *>::const_iterator i = List.begin();
1106 i != List.end();
1107 i++)
1108 {
1109 vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1110 for (vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
1111 j != Indexes->end();
1112 j++)
1113 Files.push_back (*j);
1114 }
1115
1116 unsigned long const EndOfSource = Files.size();
1117 if (_system->AddStatusFiles(Files) == false)
1118 return false;
1119
1120 // Decide if we can write to the files..
1121 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1122 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1123
1124 // ensure the cache directory exists
1125 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1126 {
1127 string dir = _config->FindDir("Dir::Cache");
1128 size_t const len = dir.size();
1129 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1130 dir = dir.substr(0, len - 5);
1131 if (CacheFile.empty() == false)
1132 CreateDirectory(dir, flNotFile(CacheFile));
1133 if (SrcCacheFile.empty() == false)
1134 CreateDirectory(dir, flNotFile(SrcCacheFile));
1135 }
1136
1137 // Decide if we can write to the cache
1138 bool Writeable = false;
1139 if (CacheFile.empty() == false)
1140 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1141 else
1142 if (SrcCacheFile.empty() == false)
1143 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
1144 if (Debug == true)
1145 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1146
1147 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
1148 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
1149
1150 if (Progress != NULL)
1151 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1152
1153 // Cache is OK, Fin.
1154 if (CheckValidity(CacheFile,Files.begin(),Files.end(),OutMap) == true)
1155 {
1156 if (Progress != NULL)
1157 Progress->OverallProgress(1,1,1,_("Reading package lists"));
1158 if (Debug == true)
1159 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
1160 return true;
1161 }
1162 else if (Debug == true)
1163 std::clog << "pkgcache.bin is NOT valid" << std::endl;
1164
1165 /* At this point we know we need to reconstruct the package cache,
1166 begin. */
1167 SPtr<FileFd> CacheF;
1168 SPtr<DynamicMMap> Map;
1169 if (Writeable == true && CacheFile.empty() == false)
1170 {
1171 _error->PushToStack();
1172 unlink(CacheFile.c_str());
1173 CacheF = new FileFd(CacheFile,FileFd::WriteAtomic);
1174 fchmod(CacheF->Fd(),0644);
1175 Map = CreateDynamicMMap(CacheF, MMap::Public);
1176 if (_error->PendingError() == true)
1177 {
1178 delete CacheF.UnGuard();
1179 delete Map.UnGuard();
1180 if (Debug == true)
1181 std::clog << "Open filebased MMap FAILED" << std::endl;
1182 Writeable = false;
1183 if (AllowMem == false)
1184 {
1185 _error->MergeWithStack();
1186 return false;
1187 }
1188 _error->RevertToStack();
1189 }
1190 else if (Debug == true)
1191 {
1192 _error->MergeWithStack();
1193 std::clog << "Open filebased MMap" << std::endl;
1194 }
1195 }
1196 if (Writeable == false || CacheFile.empty() == true)
1197 {
1198 // Just build it in memory..
1199 Map = CreateDynamicMMap(NULL);
1200 if (Debug == true)
1201 std::clog << "Open memory Map (not filebased)" << std::endl;
1202 }
1203
1204 // Lets try the source cache.
1205 unsigned long CurrentSize = 0;
1206 unsigned long TotalSize = 0;
1207 if (CheckValidity(SrcCacheFile,Files.begin(),
1208 Files.begin()+EndOfSource) == true)
1209 {
1210 if (Debug == true)
1211 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
1212 // Preload the map with the source cache
1213 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
1214 unsigned long const alloc = Map->RawAllocate(SCacheF.Size());
1215 if ((alloc == 0 && _error->PendingError())
1216 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
1217 SCacheF.Size()) == false)
1218 return false;
1219
1220 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1221
1222 // Build the status cache
1223 pkgCacheGenerator Gen(Map.Get(),Progress);
1224 if (_error->PendingError() == true)
1225 return false;
1226 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1227 Files.begin()+EndOfSource,Files.end()) == false)
1228 return false;
1229
1230 // FIXME: move me to a better place
1231 Gen.FinishCache(Progress);
1232 }
1233 else
1234 {
1235 if (Debug == true)
1236 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
1237 TotalSize = ComputeSize(Files.begin(),Files.end());
1238
1239 // Build the source cache
1240 pkgCacheGenerator Gen(Map.Get(),Progress);
1241 if (_error->PendingError() == true)
1242 return false;
1243 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1244 Files.begin(),Files.begin()+EndOfSource) == false)
1245 return false;
1246
1247 // Write it back
1248 if (Writeable == true && SrcCacheFile.empty() == false)
1249 {
1250 FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic);
1251 if (_error->PendingError() == true)
1252 return false;
1253
1254 fchmod(SCacheF.Fd(),0644);
1255
1256 // Write out the main data
1257 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1258 return _error->Error(_("IO Error saving source cache"));
1259 SCacheF.Sync();
1260
1261 // Write out the proper header
1262 Gen.GetCache().HeaderP->Dirty = false;
1263 if (SCacheF.Seek(0) == false ||
1264 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
1265 return _error->Error(_("IO Error saving source cache"));
1266 Gen.GetCache().HeaderP->Dirty = true;
1267 SCacheF.Sync();
1268 }
1269
1270 // Build the status cache
1271 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1272 Files.begin()+EndOfSource,Files.end()) == false)
1273 return false;
1274
1275 // FIXME: move me to a better place
1276 Gen.FinishCache(Progress);
1277 }
1278 if (Debug == true)
1279 std::clog << "Caches are ready for shipping" << std::endl;
1280
1281 if (_error->PendingError() == true)
1282 return false;
1283 if (OutMap != 0)
1284 {
1285 if (CacheF != 0)
1286 {
1287 delete Map.UnGuard();
1288 *OutMap = new MMap(*CacheF,0);
1289 }
1290 else
1291 {
1292 *OutMap = Map.UnGuard();
1293 }
1294 }
1295
1296 return true;
1297}
1298 /*}}}*/
1299// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
1300// ---------------------------------------------------------------------
1301/* */
1302__deprecated bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
1303 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1304bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
1305{
1306 vector<pkgIndexFile *> Files;
1307 unsigned long EndOfSource = Files.size();
1308 if (_system->AddStatusFiles(Files) == false)
1309 return false;
1310
1311 SPtr<DynamicMMap> Map = CreateDynamicMMap(NULL);
1312 unsigned long CurrentSize = 0;
1313 unsigned long TotalSize = 0;
1314
1315 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1316
1317 // Build the status cache
1318 if (Progress != NULL)
1319 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1320 pkgCacheGenerator Gen(Map.Get(),Progress);
1321 if (_error->PendingError() == true)
1322 return false;
1323 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1324 Files.begin()+EndOfSource,Files.end()) == false)
1325 return false;
1326
1327 // FIXME: move me to a better place
1328 Gen.FinishCache(Progress);
1329
1330 if (_error->PendingError() == true)
1331 return false;
1332 *OutMap = Map.UnGuard();
1333
1334 return true;
1335}
1336 /*}}}*/