]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
move ByHash into its own function
[apt.git] / apt-pkg / pkgcachegen.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
7db98ffc 3// $Id: pkgcachegen.cc,v 1.53.2.1 2003/12/24 23:09:17 mdz Exp $
578bfd0a
AL
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 /*{{{*/
ea542140 13#include <config.h>
b2e465d6 14
094a497d
AL
15#include <apt-pkg/pkgcachegen.h>
16#include <apt-pkg/error.h>
17#include <apt-pkg/version.h>
b35d2f5f
AL
18#include <apt-pkg/progress.h>
19#include <apt-pkg/sourcelist.h>
20#include <apt-pkg/configuration.h>
cdcc6d34 21#include <apt-pkg/strutl.h>
b2e465d6
AL
22#include <apt-pkg/sptr.h>
23#include <apt-pkg/pkgsystem.h>
aea7f4c8 24#include <apt-pkg/macros.h>
472ff00e
DK
25#include <apt-pkg/metaindex.h>
26#include <apt-pkg/fileutl.h>
453b82a3
DK
27#include <apt-pkg/hashsum_template.h>
28#include <apt-pkg/indexfile.h>
29#include <apt-pkg/md5.h>
30#include <apt-pkg/mmap.h>
31#include <apt-pkg/pkgcache.h>
32#include <apt-pkg/cacheiterators.h>
33
34#include <stddef.h>
35#include <string.h>
36#include <iostream>
37#include <string>
e7b470ee 38#include <vector>
578bfd0a
AL
39#include <sys/stat.h>
40#include <unistd.h>
ea542140
DK
41
42#include <apti18n.h>
578bfd0a 43 /*}}}*/
73688d27 44typedef std::vector<pkgIndexFile *>::iterator FileIterator;
d10cef82 45template <typename Iter> std::vector<Iter*> pkgCacheGenerator::Dynamic<Iter>::toReMap;
578bfd0a 46
60683765 47static bool IsDuplicateDescription(pkgCache::DescIterator Desc,
5f4db009
DK
48 MD5SumValue const &CurMd5, std::string const &CurLang);
49
73688d27
DK
50using std::string;
51
578bfd0a
AL
52// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
53// ---------------------------------------------------------------------
25396fb0 54/* We set the dirty flag and make sure that is written to the disk */
b2e465d6 55pkgCacheGenerator::pkgCacheGenerator(DynamicMMap *pMap,OpProgress *Prog) :
45415543
AL
56 Map(*pMap), Cache(pMap,false), Progress(Prog),
57 FoundFileDeps(0)
578bfd0a 58{
ddc1d8d0 59 CurrentFile = 0;
b2e465d6 60 memset(UniqHash,0,sizeof(UniqHash));
ddc1d8d0 61
578bfd0a
AL
62 if (_error->PendingError() == true)
63 return;
b2e465d6 64
578bfd0a
AL
65 if (Map.Size() == 0)
66 {
b2e465d6
AL
67 // Setup the map interface..
68 Cache.HeaderP = (pkgCache::Header *)Map.Data();
c5f44afc
DK
69 if (Map.RawAllocate(sizeof(pkgCache::Header)) == 0 && _error->PendingError() == true)
70 return;
71
b2e465d6 72 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
c5f44afc 73
b2e465d6 74 // Starting header
578bfd0a 75 *Cache.HeaderP = pkgCache::Header();
a9fe5928 76 map_ptrloc const idxVerSysName = WriteStringInMap(_system->VS->Label);
7a223b93
DK
77 if (unlikely(idxVerSysName == 0))
78 return;
a9fe5928 79 Cache.HeaderP->VerSysName = idxVerSysName;
7ccb5efb
DK
80 // this pointer is set in ReMap, but we need it now for WriteUniqString
81 Cache.StringItemP = (pkgCache::StringItem *)Map.Data();
82 map_ptrloc const idxArchitecture = WriteUniqString(_config->Find("APT::Architecture"));
7a223b93 83 if (unlikely(idxArchitecture == 0))
a9fe5928 84 return;
7a223b93
DK
85 Cache.HeaderP->Architecture = idxArchitecture;
86
87 std::vector<std::string> archs = APT::Configuration::getArchitectures();
88 if (archs.size() > 1)
89 {
90 std::vector<std::string>::const_iterator a = archs.begin();
91 std::string list = *a;
92 for (++a; a != archs.end(); ++a)
93 list.append(",").append(*a);
94 map_ptrloc const idxArchitectures = WriteStringInMap(list);
95 if (unlikely(idxArchitectures == 0))
96 return;
97 Cache.HeaderP->Architectures = idxArchitectures;
98 }
99 else
100 Cache.HeaderP->Architectures = idxArchitecture;
101
c5f44afc 102 Cache.ReMap();
578bfd0a 103 }
b2e465d6
AL
104 else
105 {
106 // Map directly from the existing file
107 Cache.ReMap();
108 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
109 if (Cache.VS != _system->VS)
110 {
111 _error->Error(_("Cache has an incompatible versioning system"));
112 return;
113 }
114 }
115
578bfd0a
AL
116 Cache.HeaderP->Dirty = true;
117 Map.Sync(0,sizeof(pkgCache::Header));
578bfd0a
AL
118}
119 /*}}}*/
120// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
121// ---------------------------------------------------------------------
122/* We sync the data then unset the dirty flag in two steps so as to
123 advoid a problem during a crash */
124pkgCacheGenerator::~pkgCacheGenerator()
125{
126 if (_error->PendingError() == true)
127 return;
128 if (Map.Sync() == false)
129 return;
130
131 Cache.HeaderP->Dirty = false;
1dfda2ce 132 Cache.HeaderP->CacheFileSize = Map.Size();
578bfd0a
AL
133 Map.Sync(0,sizeof(pkgCache::Header));
134}
135 /*}}}*/
a9fe5928
DK
136void pkgCacheGenerator::ReMap(void const * const oldMap, void const * const newMap) {/*{{{*/
137 if (oldMap == newMap)
138 return;
139
64dda04b
MV
140 if (_config->FindB("Debug::pkgCacheGen", false))
141 std::clog << "Remaping from " << oldMap << " to " << newMap << std::endl;
142
a9fe5928
DK
143 Cache.ReMap(false);
144
cf4ff3b7 145 CurrentFile += (pkgCache::PackageFile const * const) newMap - (pkgCache::PackageFile const * const) oldMap;
a9fe5928
DK
146
147 for (size_t i = 0; i < _count(UniqHash); ++i)
148 if (UniqHash[i] != 0)
cf4ff3b7 149 UniqHash[i] += (pkgCache::StringItem const * const) newMap - (pkgCache::StringItem const * const) oldMap;
a9fe5928 150
7635093c 151 for (std::vector<pkgCache::GrpIterator*>::const_iterator i = Dynamic<pkgCache::GrpIterator>::toReMap.begin();
a9fe5928 152 i != Dynamic<pkgCache::GrpIterator>::toReMap.end(); ++i)
f7a35f2e 153 (*i)->ReMap(oldMap, newMap);
7635093c 154 for (std::vector<pkgCache::PkgIterator*>::const_iterator i = Dynamic<pkgCache::PkgIterator>::toReMap.begin();
a9fe5928 155 i != Dynamic<pkgCache::PkgIterator>::toReMap.end(); ++i)
f7a35f2e 156 (*i)->ReMap(oldMap, newMap);
7635093c 157 for (std::vector<pkgCache::VerIterator*>::const_iterator i = Dynamic<pkgCache::VerIterator>::toReMap.begin();
a9fe5928 158 i != Dynamic<pkgCache::VerIterator>::toReMap.end(); ++i)
f7a35f2e 159 (*i)->ReMap(oldMap, newMap);
7635093c 160 for (std::vector<pkgCache::DepIterator*>::const_iterator i = Dynamic<pkgCache::DepIterator>::toReMap.begin();
a9fe5928 161 i != Dynamic<pkgCache::DepIterator>::toReMap.end(); ++i)
f7a35f2e 162 (*i)->ReMap(oldMap, newMap);
7635093c 163 for (std::vector<pkgCache::DescIterator*>::const_iterator i = Dynamic<pkgCache::DescIterator>::toReMap.begin();
a9fe5928 164 i != Dynamic<pkgCache::DescIterator>::toReMap.end(); ++i)
f7a35f2e 165 (*i)->ReMap(oldMap, newMap);
7635093c 166 for (std::vector<pkgCache::PrvIterator*>::const_iterator i = Dynamic<pkgCache::PrvIterator>::toReMap.begin();
a9fe5928 167 i != Dynamic<pkgCache::PrvIterator>::toReMap.end(); ++i)
f7a35f2e 168 (*i)->ReMap(oldMap, newMap);
7635093c 169 for (std::vector<pkgCache::PkgFileIterator*>::const_iterator i = Dynamic<pkgCache::PkgFileIterator>::toReMap.begin();
a9fe5928 170 i != Dynamic<pkgCache::PkgFileIterator>::toReMap.end(); ++i)
f7a35f2e 171 (*i)->ReMap(oldMap, newMap);
a9fe5928 172} /*}}}*/
7e58ab0c 173// CacheGenerator::WriteStringInMap /*{{{*/
a9fe5928 174map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String,
7e58ab0c 175 const unsigned long &Len) {
a9fe5928
DK
176 void const * const oldMap = Map.Data();
177 map_ptrloc const index = Map.WriteString(String, Len);
178 if (index != 0)
179 ReMap(oldMap, Map.Data());
180 return index;
7e58ab0c
DK
181}
182 /*}}}*/
183// CacheGenerator::WriteStringInMap /*{{{*/
a9fe5928
DK
184map_ptrloc pkgCacheGenerator::WriteStringInMap(const char *String) {
185 void const * const oldMap = Map.Data();
186 map_ptrloc const index = Map.WriteString(String);
187 if (index != 0)
188 ReMap(oldMap, Map.Data());
189 return index;
7e58ab0c
DK
190}
191 /*}}}*/
a9fe5928
DK
192map_ptrloc pkgCacheGenerator::AllocateInMap(const unsigned long &size) {/*{{{*/
193 void const * const oldMap = Map.Data();
194 map_ptrloc const index = Map.Allocate(size);
195 if (index != 0)
196 ReMap(oldMap, Map.Data());
197 return index;
7e58ab0c
DK
198}
199 /*}}}*/
578bfd0a
AL
200// CacheGenerator::MergeList - Merge the package list /*{{{*/
201// ---------------------------------------------------------------------
202/* This provides the generation of the entries in the cache. Each loop
203 goes through a single package record from the underlying parse engine. */
ddc1d8d0
AL
204bool pkgCacheGenerator::MergeList(ListParser &List,
205 pkgCache::VerIterator *OutVer)
578bfd0a
AL
206{
207 List.Owner = this;
0149949b 208
f9eec0e7 209 unsigned int Counter = 0;
0149949b 210 while (List.Step() == true)
578bfd0a 211 {
5bf15716 212 string const PackageName = List.Package();
65a1e968
AL
213 if (PackageName.empty() == true)
214 return false;
5bf15716 215
99a2ea5a
DK
216 Counter++;
217 if (Counter % 100 == 0 && Progress != 0)
218 Progress->Progress(List.Offset());
219
220 string Arch = List.Architecture();
221 string const Version = List.Version();
222 if (Version.empty() == true && Arch.empty() == true)
223 {
8ec00880 224 // package descriptions
99a2ea5a
DK
225 if (MergeListGroup(List, PackageName) == false)
226 return false;
8ec00880 227 continue;
99a2ea5a
DK
228 }
229
230 if (Arch.empty() == true)
c919ad6e
DK
231 {
232 // use the pseudo arch 'none' for arch-less packages
233 Arch = "none";
234 /* We might built a SingleArchCache here, which we don't want to blow up
235 just for these :none packages to a proper MultiArchCache, so just ensure
236 that we have always a native package structure first for SingleArch */
237 pkgCache::PkgIterator NP;
9abb2283 238 Dynamic<pkgCache::PkgIterator> DynPkg(NP);
c919ad6e
DK
239 if (NewPackage(NP, PackageName, _config->Find("APT::Architecture")) == false)
240 // TRANSLATOR: The first placeholder is a package name,
241 // the other two should be copied verbatim as they include debug info
242 return _error->Error(_("Error occurred while processing %s (%s%d)"),
243 PackageName.c_str(), "NewPackage", 0);
244 }
99a2ea5a 245
8b32e920 246 // Get a pointer to the package structure
9ddf7030 247 pkgCache::PkgIterator Pkg;
a9fe5928 248 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
28166356 249 if (NewPackage(Pkg, PackageName, Arch) == false)
79e9003c
DK
250 // TRANSLATOR: The first placeholder is a package name,
251 // the other two should be copied verbatim as they include debug info
252 return _error->Error(_("Error occurred while processing %s (%s%d)"),
253 PackageName.c_str(), "NewPackage", 1);
8ce4327b 254
99a2ea5a 255
f55a958f
AL
256 if (Version.empty() == true)
257 {
99a2ea5a
DK
258 if (MergeListPackage(List, Pkg) == false)
259 return false;
260 }
261 else
262 {
263 if (MergeListVersion(List, Pkg, Version, OutVer) == false)
264 return false;
265 }
770c32ec 266
99a2ea5a
DK
267 if (OutVer != 0)
268 {
269 FoundFileDeps |= List.HasFileDeps();
270 return true;
f55a958f 271 }
99a2ea5a
DK
272 }
273
274 if (Cache.HeaderP->PackageCount >= (1ULL<<sizeof(Cache.PkgP->ID)*8)-1)
275 return _error->Error(_("Wow, you exceeded the number of package "
276 "names this APT is capable of."));
277 if (Cache.HeaderP->VersionCount >= (1ULL<<(sizeof(Cache.VerP->ID)*8))-1)
278 return _error->Error(_("Wow, you exceeded the number of versions "
279 "this APT is capable of."));
280 if (Cache.HeaderP->DescriptionCount >= (1ULL<<(sizeof(Cache.DescP->ID)*8))-1)
281 return _error->Error(_("Wow, you exceeded the number of descriptions "
282 "this APT is capable of."));
283 if (Cache.HeaderP->DependsCount >= (1ULL<<(sizeof(Cache.DepP->ID)*8))-1ULL)
284 return _error->Error(_("Wow, you exceeded the number of dependencies "
285 "this APT is capable of."));
286
287 FoundFileDeps |= List.HasFileDeps();
288 return true;
289}
290// CacheGenerator::MergeListGroup /*{{{*/
291bool pkgCacheGenerator::MergeListGroup(ListParser &List, std::string const &GrpName)
292{
293 pkgCache::GrpIterator Grp = Cache.FindGrp(GrpName);
5f4db009
DK
294 // a group has no data on it's own, only packages have it but these
295 // stanzas like this come from Translation- files to add descriptions,
296 // but without a version we don't need a description for it…
99a2ea5a 297 if (Grp.end() == true)
5f4db009 298 return true;
99a2ea5a
DK
299 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
300
301 pkgCache::PkgIterator Pkg;
302 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
303 for (Pkg = Grp.PackageList(); Pkg.end() == false; Pkg = Grp.NextPkg(Pkg))
304 if (MergeListPackage(List, Pkg) == false)
305 return false;
306
307 return true;
308}
309 /*}}}*/
310// CacheGenerator::MergeListPackage /*{{{*/
311bool pkgCacheGenerator::MergeListPackage(ListParser &List, pkgCache::PkgIterator &Pkg)
312{
313 // we first process the package, then the descriptions
314 // (for deb this package processing is in fact a no-op)
315 pkgCache::VerIterator Ver(Cache);
316 Dynamic<pkgCache::VerIterator> DynVer(Ver);
317 if (List.UsePackage(Pkg, Ver) == false)
79e9003c
DK
318 return _error->Error(_("Error occurred while processing %s (%s%d)"),
319 Pkg.Name(), "UsePackage", 1);
99a2ea5a
DK
320
321 // Find the right version to write the description
322 MD5SumValue CurMd5 = List.Description_md5();
ffe3c68e 323 if (CurMd5.Value().empty() == true && List.Description("").empty() == true)
99359751 324 return true;
ffe3c68e 325 std::vector<std::string> availDesc = List.AvailableDescriptionLanguages();
99a2ea5a
DK
326 for (Ver = Pkg.VersionList(); Ver.end() == false; ++Ver)
327 {
a65e22c6 328 pkgCache::DescIterator VerDesc = Ver.DescriptionList();
22f07fc5
DK
329
330 // a version can only have one md5 describing it
a65e22c6 331 if (VerDesc.end() == true || MD5SumValue(VerDesc.md5()) != CurMd5)
22f07fc5 332 continue;
99a2ea5a 333
ffe3c68e
DK
334 map_ptrloc md5idx = VerDesc->md5sum;
335 for (std::vector<std::string>::const_iterator CurLang = availDesc.begin(); CurLang != availDesc.end(); ++CurLang)
336 {
337 // don't add a new description if we have one for the given
338 // md5 && language
339 if (IsDuplicateDescription(VerDesc, CurMd5, *CurLang) == true)
340 continue;
a65e22c6 341
ffe3c68e
DK
342 AddNewDescription(List, Ver, *CurLang, CurMd5, md5idx);
343 }
22f07fc5
DK
344
345 // we can stop here as all "same" versions will share the description
346 break;
99a2ea5a
DK
347 }
348
349 return true;
350}
351 /*}}}*/
352// CacheGenerator::MergeListVersion /*{{{*/
353bool pkgCacheGenerator::MergeListVersion(ListParser &List, pkgCache::PkgIterator &Pkg,
354 std::string const &Version, pkgCache::VerIterator* &OutVer)
355{
356 pkgCache::VerIterator Ver = Pkg.VersionList();
357 Dynamic<pkgCache::VerIterator> DynVer(Ver);
358 map_ptrloc *LastVer = &Pkg->VersionList;
359 void const * oldMap = Map.Data();
360
68134bda 361 unsigned short const Hash = List.VersionHash();
99a2ea5a
DK
362 if (Ver.end() == false)
363 {
364 /* We know the list is sorted so we use that fact in the search.
365 Insertion of new versions is done with correct sorting */
2246928b 366 int Res = 1;
9ee47c29 367 for (; Ver.end() == false; LastVer = &Ver->NextVer, Ver++)
578bfd0a 368 {
c24972cb 369 Res = Cache.VS->CmpVersion(Version,Ver.VerStr());
7e2b56a3
DK
370 // Version is higher as current version - insert here
371 if (Res > 0)
578bfd0a 372 break;
7e2b56a3 373 // Versionstrings are equal - is hash also equal?
68134bda 374 if (Res == 0 && List.SameVersion(Hash, Ver) == true)
7e2b56a3
DK
375 break;
376 // proceed with the next till we have either the right
377 // or we found another version (which will be lower)
578bfd0a 378 }
7e2b56a3
DK
379
380 /* We already have a version for this item, record that we saw it */
e426a5ff 381 if (Res == 0 && Ver.end() == false && Ver->Hash == Hash)
578bfd0a 382 {
f55a958f 383 if (List.UsePackage(Pkg,Ver) == false)
79e9003c
DK
384 return _error->Error(_("Error occurred while processing %s (%s%d)"),
385 Pkg.Name(), "UsePackage", 2);
f78439bf 386
578bfd0a 387 if (NewFileVer(Ver,List) == false)
79e9003c
DK
388 return _error->Error(_("Error occurred while processing %s (%s%d)"),
389 Pkg.Name(), "NewFileVer", 1);
99a2ea5a 390
ddc1d8d0
AL
391 // Read only a single record and return
392 if (OutVer != 0)
393 {
394 *OutVer = Ver;
395 return true;
396 }
99a2ea5a
DK
397
398 return true;
204fbdcc 399 }
99a2ea5a 400 }
204fbdcc 401
99a2ea5a 402 // Add a new version
885594fc 403 map_ptrloc const verindex = NewVersion(Ver, Version, Pkg.Index(), Hash, *LastVer);
99a2ea5a 404 if (verindex == 0 && _error->PendingError())
79e9003c
DK
405 return _error->Error(_("Error occurred while processing %s (%s%d)"),
406 Pkg.Name(), "NewVersion", 1);
a9fe5928 407
99a2ea5a 408 if (oldMap != Map.Data())
cf4ff3b7 409 LastVer += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
99a2ea5a 410 *LastVer = verindex;
a52f938b 411
79e9003c
DK
412 if (unlikely(List.NewVersion(Ver) == false))
413 return _error->Error(_("Error occurred while processing %s (%s%d)"),
414 Pkg.Name(), "NewVersion", 2);
a9fe5928 415
79e9003c
DK
416 if (unlikely(List.UsePackage(Pkg,Ver) == false))
417 return _error->Error(_("Error occurred while processing %s (%s%d)"),
418 Pkg.Name(), "UsePackage", 3);
419
420 if (unlikely(NewFileVer(Ver,List) == false))
421 return _error->Error(_("Error occurred while processing %s (%s%d)"),
422 Pkg.Name(), "NewFileVer", 2);
a52f938b 423
5a8e963b
DK
424 pkgCache::GrpIterator Grp = Pkg.Group();
425 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
426
427 /* If it is the first version of this package we need to add implicit
428 Multi-Arch dependencies to all other package versions in the group now -
429 otherwise we just add them for this new version */
430 if (Pkg.VersionList()->NextVer == 0)
431 {
432 pkgCache::PkgIterator P = Grp.PackageList();
433 Dynamic<pkgCache::PkgIterator> DynP(P);
434 for (; P.end() != true; P = Grp.NextPkg(P))
435 {
436 if (P->ID == Pkg->ID)
437 continue;
438 pkgCache::VerIterator V = P.VersionList();
439 Dynamic<pkgCache::VerIterator> DynV(V);
440 for (; V.end() != true; ++V)
441 if (unlikely(AddImplicitDepends(V, Pkg) == false))
442 return _error->Error(_("Error occurred while processing %s (%s%d)"),
443 Pkg.Name(), "AddImplicitDepends", 1);
444 }
c919ad6e
DK
445 /* :none packages are packages without an architecture. They are forbidden by
446 debian-policy, so usually they will only be in (old) dpkg status files -
447 and dpkg will complain about them - and are pretty rare. We therefore do
448 usually not create conflicts while the parent is created, but only if a :none
449 package (= the target) appears. This creates incorrect dependencies on :none
450 for architecture-specific dependencies on the package we copy from, but we
451 will ignore this bug as architecture-specific dependencies are only allowed
452 in jessie and until then the :none packages should be extinct (hopefully).
453 In other words: This should work long enough to allow graceful removal of
454 these packages, it is not supposed to allow users to keep using them … */
455 if (strcmp(Pkg.Arch(), "none") == 0)
456 {
457 pkgCache::PkgIterator M = Grp.FindPreferredPkg();
458 if (M.end() == false && Pkg != M)
459 {
460 pkgCache::DepIterator D = M.RevDependsList();
461 Dynamic<pkgCache::DepIterator> DynD(D);
462 for (; D.end() == false; ++D)
463 {
464 if ((D->Type != pkgCache::Dep::Conflicts &&
465 D->Type != pkgCache::Dep::DpkgBreaks &&
466 D->Type != pkgCache::Dep::Replaces) ||
467 D.ParentPkg().Group() == Grp)
468 continue;
469
470 map_ptrloc *OldDepLast = NULL;
471 pkgCache::VerIterator ConVersion = D.ParentVer();
9abb2283 472 Dynamic<pkgCache::VerIterator> DynV(ConVersion);
c919ad6e 473 // duplicate the Conflicts/Breaks/Replaces for :none arch
9c44383f
DK
474 NewDepends(Pkg, ConVersion, D->Version,
475 D->CompareOp, D->Type, OldDepLast);
c919ad6e
DK
476 }
477 }
478 }
5a8e963b
DK
479 }
480 if (unlikely(AddImplicitDepends(Grp, Pkg, Ver) == false))
481 return _error->Error(_("Error occurred while processing %s (%s%d)"),
482 Pkg.Name(), "AddImplicitDepends", 2);
a52f938b 483
99a2ea5a
DK
484 // Read only a single record and return
485 if (OutVer != 0)
486 {
487 *OutVer = Ver;
488 return true;
578bfd0a 489 }
0149949b 490
ffe3c68e 491 /* Record the Description(s) based on their master md5sum */
5f4db009 492 MD5SumValue CurMd5 = List.Description_md5();
ffe3c68e 493 if (CurMd5.Value().empty() == true && List.Description("").empty() == true)
5f4db009 494 return true;
5f4db009
DK
495
496 /* Before we add a new description we first search in the group for
497 a version with a description of the same MD5 - if so we reuse this
498 description group instead of creating our own for this version */
5f4db009
DK
499 for (pkgCache::PkgIterator P = Grp.PackageList();
500 P.end() == false; P = Grp.NextPkg(P))
501 {
502 for (pkgCache::VerIterator V = P.VersionList();
503 V.end() == false; ++V)
504 {
ffe3c68e 505 if (V->DescriptionList == 0 || MD5SumValue(V.DescriptionList().md5()) != CurMd5)
5f4db009
DK
506 continue;
507 Ver->DescriptionList = V->DescriptionList;
5f4db009
DK
508 }
509 }
510
ffe3c68e
DK
511 // We haven't found reusable descriptions, so add the first description(s)
512 map_ptrloc md5idx = Ver->DescriptionList == 0 ? 0 : Ver.DescriptionList()->md5sum;
513 std::vector<std::string> availDesc = List.AvailableDescriptionLanguages();
514 for (std::vector<std::string>::const_iterator CurLang = availDesc.begin(); CurLang != availDesc.end(); ++CurLang)
515 if (AddNewDescription(List, Ver, *CurLang, CurMd5, md5idx) == false)
516 return false;
517 return true;
518}
519 /*}}}*/
520bool pkgCacheGenerator::AddNewDescription(ListParser &List, pkgCache::VerIterator &Ver, std::string const &lang, MD5SumValue const &CurMd5, map_ptrloc &md5idx) /*{{{*/
521{
522 pkgCache::DescIterator Desc;
99a2ea5a 523 Dynamic<pkgCache::DescIterator> DynDesc(Desc);
99a2ea5a 524
ffe3c68e 525 map_ptrloc const descindex = NewDescription(Desc, lang, CurMd5, md5idx);
5954d4d2
DK
526 if (unlikely(descindex == 0 && _error->PendingError()))
527 return _error->Error(_("Error occurred while processing %s (%s%d)"),
ffe3c68e
DK
528 Ver.ParentPkg().Name(), "NewDescription", 1);
529
530 md5idx = Desc->md5sum;
531 Desc->ParentPkg = Ver.ParentPkg().Index();
a65e22c6 532
ffe3c68e
DK
533 // we add at the end, so that the start is constant as we need
534 // that to be able to efficiently share these lists
535 pkgCache::DescIterator VerDesc = Ver.DescriptionList(); // old value might be invalid after ReMap
536 for (;VerDesc.end() == false && VerDesc->NextDesc != 0; ++VerDesc);
537 map_ptrloc * const LastNextDesc = (VerDesc.end() == true) ? &Ver->DescriptionList : &VerDesc->NextDesc;
538 *LastNextDesc = descindex;
99a2ea5a 539
a65e22c6 540 if (NewFileDesc(Desc,List) == false)
79e9003c 541 return _error->Error(_("Error occurred while processing %s (%s%d)"),
ffe3c68e 542 Ver.ParentPkg().Name(), "NewFileDesc", 1);
45415543 543
578bfd0a
AL
544 return true;
545}
546 /*}}}*/
99a2ea5a 547 /*}}}*/
45415543
AL
548// CacheGenerator::MergeFileProvides - Merge file provides /*{{{*/
549// ---------------------------------------------------------------------
550/* If we found any file depends while parsing the main list we need to
551 resolve them. Since it is undesired to load the entire list of files
552 into the cache as virtual packages we do a two stage effort. MergeList
553 identifies the file depends and this creates Provdies for them by
554 re-parsing all the indexs. */
555bool pkgCacheGenerator::MergeFileProvides(ListParser &List)
556{
557 List.Owner = this;
558
559 unsigned int Counter = 0;
560 while (List.Step() == true)
561 {
562 string PackageName = List.Package();
563 if (PackageName.empty() == true)
564 return false;
565 string Version = List.Version();
566 if (Version.empty() == true)
567 continue;
568
569 pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
a9fe5928 570 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
45415543 571 if (Pkg.end() == true)
79e9003c
DK
572 return _error->Error(_("Error occurred while processing %s (%s%d)"),
573 PackageName.c_str(), "FindPkg", 1);
45415543
AL
574 Counter++;
575 if (Counter % 100 == 0 && Progress != 0)
576 Progress->Progress(List.Offset());
577
68134bda 578 unsigned short Hash = List.VersionHash();
45415543 579 pkgCache::VerIterator Ver = Pkg.VersionList();
a9fe5928 580 Dynamic<pkgCache::VerIterator> DynVer(Ver);
f7f0d6c7 581 for (; Ver.end() == false; ++Ver)
45415543 582 {
68134bda 583 if (List.SameVersion(Hash, Ver) == true && Version == Ver.VerStr())
45415543
AL
584 {
585 if (List.CollectFileProvides(Cache,Ver) == false)
79e9003c
DK
586 return _error->Error(_("Error occurred while processing %s (%s%d)"),
587 PackageName.c_str(), "CollectFileProvides", 1);
45415543
AL
588 break;
589 }
590 }
591
592 if (Ver.end() == true)
593 _error->Warning(_("Package %s %s was not found while processing file dependencies"),PackageName.c_str(),Version.c_str());
594 }
595
596 return true;
597}
598 /*}}}*/
5bf15716
DK
599// CacheGenerator::NewGroup - Add a new group /*{{{*/
600// ---------------------------------------------------------------------
601/* This creates a new group structure and adds it to the hash table */
33dd02e3
DK
602bool pkgCacheGenerator::NewGroup(pkgCache::GrpIterator &Grp, const string &Name)
603{
604 Grp = Cache.FindGrp(Name);
605 if (Grp.end() == false)
606 return true;
5bf15716 607
33dd02e3 608 // Get a structure
a9fe5928 609 map_ptrloc const Group = AllocateInMap(sizeof(pkgCache::Group));
33dd02e3
DK
610 if (unlikely(Group == 0))
611 return false;
5bf15716 612
33dd02e3 613 Grp = pkgCache::GrpIterator(Cache, Cache.GrpP + Group);
a9fe5928
DK
614 map_ptrloc const idxName = WriteStringInMap(Name);
615 if (unlikely(idxName == 0))
33dd02e3 616 return false;
a9fe5928 617 Grp->Name = idxName;
5bf15716 618
33dd02e3
DK
619 // Insert it into the hash table
620 unsigned long const Hash = Cache.Hash(Name);
aa0fe657
DK
621 map_ptrloc *insertAt = &Cache.HeaderP->GrpHashTable[Hash];
622 while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + *insertAt)->Name) > 0)
623 insertAt = &(Cache.GrpP + *insertAt)->Next;
624 Grp->Next = *insertAt;
625 *insertAt = Group;
5bf15716 626
52c41485 627 Grp->ID = Cache.HeaderP->GroupCount++;
33dd02e3 628 return true;
5bf15716
DK
629}
630 /*}}}*/
578bfd0a
AL
631// CacheGenerator::NewPackage - Add a new package /*{{{*/
632// ---------------------------------------------------------------------
633/* This creates a new package structure and adds it to the hash table */
5bf15716
DK
634bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,const string &Name,
635 const string &Arch) {
636 pkgCache::GrpIterator Grp;
a9fe5928 637 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
5bf15716
DK
638 if (unlikely(NewGroup(Grp, Name) == false))
639 return false;
640
641 Pkg = Grp.FindPkg(Arch);
642 if (Pkg.end() == false)
643 return true;
a52f938b 644
578bfd0a 645 // Get a structure
a9fe5928 646 map_ptrloc const Package = AllocateInMap(sizeof(pkgCache::Package));
5bf15716 647 if (unlikely(Package == 0))
578bfd0a 648 return false;
f55a958f 649 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
5bf15716 650
c408e01e
DK
651 // Insert the package into our package list
652 if (Grp->FirstPackage == 0) // the group is new
653 {
aa0fe657 654 Grp->FirstPackage = Package;
c408e01e
DK
655 // Insert it into the hash table
656 unsigned long const Hash = Cache.Hash(Name);
aa0fe657
DK
657 map_ptrloc *insertAt = &Cache.HeaderP->PkgHashTable[Hash];
658 while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.PkgP + *insertAt)->Name) > 0)
659 insertAt = &(Cache.PkgP + *insertAt)->NextPackage;
660 Pkg->NextPackage = *insertAt;
661 *insertAt = Package;
c408e01e
DK
662 }
663 else // Group the Packages together
664 {
665 // this package is the new last package
666 pkgCache::PkgIterator LastPkg(Cache, Cache.PkgP + Grp->LastPackage);
667 Pkg->NextPackage = LastPkg->NextPackage;
668 LastPkg->NextPackage = Package;
669 }
670 Grp->LastPackage = Package;
5bf15716
DK
671
672 // Set the name, arch and the ID
673 Pkg->Name = Grp->Name;
674 Pkg->Group = Grp.Index();
959470da
DK
675 // all is mapped to the native architecture
676 map_ptrloc const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : WriteUniqString(Arch.c_str());
a9fe5928 677 if (unlikely(idxArch == 0))
578bfd0a 678 return false;
a9fe5928 679 Pkg->Arch = idxArch;
578bfd0a 680 Pkg->ID = Cache.HeaderP->PackageCount++;
5bf15716 681
578bfd0a
AL
682 return true;
683}
5a8e963b
DK
684 /*}}}*/
685// CacheGenerator::AddImplicitDepends /*{{{*/
686bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator &G,
687 pkgCache::PkgIterator &P,
688 pkgCache::VerIterator &V)
689{
690 // copy P.Arch() into a string here as a cache remap
691 // in NewDepends() later may alter the pointer location
692 string Arch = P.Arch() == NULL ? "" : P.Arch();
693 map_ptrloc *OldDepLast = NULL;
694 /* MultiArch handling introduces a lot of implicit Dependencies:
695 - MultiArch: same → Co-Installable if they have the same version
696 - All others conflict with all other group members */
697 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
698 pkgCache::PkgIterator D = G.PackageList();
699 Dynamic<pkgCache::PkgIterator> DynD(D);
9c44383f 700 map_ptrloc const VerStrIdx = V->VerStr;
5a8e963b
DK
701 for (; D.end() != true; D = G.NextPkg(D))
702 {
703 if (Arch == D.Arch() || D->VersionList == 0)
704 continue;
705 /* We allow only one installed arch at the time
706 per group, therefore each group member conflicts
707 with all other group members */
708 if (coInstall == true)
709 {
710 // Replaces: ${self}:other ( << ${binary:Version})
9c44383f 711 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
712 pkgCache::Dep::Less, pkgCache::Dep::Replaces,
713 OldDepLast);
714 // Breaks: ${self}:other (!= ${binary:Version})
9c44383f 715 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
716 pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks,
717 OldDepLast);
718 } else {
719 // Conflicts: ${self}:other
9c44383f 720 NewDepends(D, V, 0,
5a8e963b
DK
721 pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
722 OldDepLast);
723 }
724 }
725 return true;
726}
727bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator &V,
728 pkgCache::PkgIterator &D)
729{
730 /* MultiArch handling introduces a lot of implicit Dependencies:
731 - MultiArch: same → Co-Installable if they have the same version
732 - All others conflict with all other group members */
733 map_ptrloc *OldDepLast = NULL;
734 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
735 if (coInstall == true)
736 {
9c44383f 737 map_ptrloc const VerStrIdx = V->VerStr;
5a8e963b 738 // Replaces: ${self}:other ( << ${binary:Version})
9c44383f 739 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
740 pkgCache::Dep::Less, pkgCache::Dep::Replaces,
741 OldDepLast);
742 // Breaks: ${self}:other (!= ${binary:Version})
9c44383f 743 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
744 pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks,
745 OldDepLast);
746 } else {
747 // Conflicts: ${self}:other
9c44383f 748 NewDepends(D, V, 0,
5a8e963b
DK
749 pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
750 OldDepLast);
751 }
752 return true;
753}
754
578bfd0a
AL
755 /*}}}*/
756// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
757// ---------------------------------------------------------------------
758/* */
f55a958f 759bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
578bfd0a
AL
760 ListParser &List)
761{
ddc1d8d0
AL
762 if (CurrentFile == 0)
763 return true;
764
dcb79bae 765 // Get a structure
a9fe5928 766 map_ptrloc const VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
dcb79bae
AL
767 if (VerFile == 0)
768 return 0;
769
770 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
771 VF->File = CurrentFile - Cache.PkgFileP;
03e39e59
AL
772
773 // Link it to the end of the list
349cd3b8 774 map_ptrloc *Last = &Ver->FileList;
f7f0d6c7 775 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; ++V)
03e39e59
AL
776 Last = &V->NextFile;
777 VF->NextFile = *Last;
778 *Last = VF.Index();
779
dcb79bae
AL
780 VF->Offset = List.Offset();
781 VF->Size = List.Size();
ad00ae81
AL
782 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
783 Cache.HeaderP->MaxVerFileSize = VF->Size;
a7e66b17
AL
784 Cache.HeaderP->VerFileCount++;
785
f55a958f 786 return true;
578bfd0a
AL
787}
788 /*}}}*/
789// CacheGenerator::NewVersion - Create a new Version /*{{{*/
790// ---------------------------------------------------------------------
f55a958f 791/* This puts a version structure in the linked list */
578bfd0a 792unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
171c75f1 793 const string &VerStr,
885594fc
DK
794 map_ptrloc const ParentPkg,
795 unsigned long const Hash,
578bfd0a
AL
796 unsigned long Next)
797{
f55a958f 798 // Get a structure
a9fe5928 799 map_ptrloc const Version = AllocateInMap(sizeof(pkgCache::Version));
f55a958f 800 if (Version == 0)
0149949b 801 return 0;
f55a958f
AL
802
803 // Fill it in
804 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
dfe45e1f 805 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
f55a958f 806 Ver->NextVer = Next;
885594fc
DK
807 Ver->ParentPkg = ParentPkg;
808 Ver->Hash = Hash;
f55a958f 809 Ver->ID = Cache.HeaderP->VersionCount++;
885594fc
DK
810
811 // try to find the version string in the group for reuse
812 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
813 pkgCache::GrpIterator Grp = Pkg.Group();
814 if (Pkg.end() == false && Grp.end() == false)
815 {
816 for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
817 {
818 if (Pkg == P)
819 continue;
820 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
821 {
822 int const cmp = strcmp(V.VerStr(), VerStr.c_str());
823 if (cmp == 0)
824 {
825 Ver->VerStr = V->VerStr;
826 return Version;
827 }
828 else if (cmp < 0)
829 break;
830 }
831 }
832 }
833 // haven't found the version string, so create
a9fe5928
DK
834 map_ptrloc const idxVerStr = WriteStringInMap(VerStr);
835 if (unlikely(idxVerStr == 0))
0149949b 836 return 0;
a9fe5928 837 Ver->VerStr = idxVerStr;
0149949b 838 return Version;
578bfd0a
AL
839}
840 /*}}}*/
a52f938b
OS
841// CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
842// ---------------------------------------------------------------------
843/* */
844bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
845 ListParser &List)
846{
847 if (CurrentFile == 0)
848 return true;
849
850 // Get a structure
a9fe5928 851 map_ptrloc const DescFile = AllocateInMap(sizeof(pkgCache::DescFile));
a52f938b 852 if (DescFile == 0)
c5f44afc 853 return false;
770c32ec 854
a52f938b
OS
855 pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
856 DF->File = CurrentFile - Cache.PkgFileP;
770c32ec 857
a52f938b
OS
858 // Link it to the end of the list
859 map_ptrloc *Last = &Desc->FileList;
f7f0d6c7 860 for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; ++D)
a52f938b 861 Last = &D->NextFile;
770c32ec 862
a52f938b
OS
863 DF->NextFile = *Last;
864 *Last = DF.Index();
865
866 DF->Offset = List.Offset();
867 DF->Size = List.Size();
868 if (Cache.HeaderP->MaxDescFileSize < DF->Size)
869 Cache.HeaderP->MaxDescFileSize = DF->Size;
870 Cache.HeaderP->DescFileCount++;
871
872 return true;
873}
874 /*}}}*/
875// CacheGenerator::NewDescription - Create a new Description /*{{{*/
876// ---------------------------------------------------------------------
877/* This puts a description structure in the linked list */
878map_ptrloc pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
a65e22c6
DK
879 const string &Lang,
880 const MD5SumValue &md5sum,
881 map_ptrloc idxmd5str)
a52f938b
OS
882{
883 // Get a structure
a9fe5928 884 map_ptrloc const Description = AllocateInMap(sizeof(pkgCache::Description));
a52f938b
OS
885 if (Description == 0)
886 return 0;
887
888 // Fill it in
889 Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
a52f938b 890 Desc->ID = Cache.HeaderP->DescriptionCount++;
734b7c81 891 map_ptrloc const idxlanguage_code = WriteUniqString(Lang);
a65e22c6 892 if (unlikely(idxlanguage_code == 0))
c5f44afc 893 return 0;
a9fe5928 894 Desc->language_code = idxlanguage_code;
a65e22c6
DK
895
896 if (idxmd5str != 0)
897 Desc->md5sum = idxmd5str;
898 else
899 {
900 map_ptrloc const idxmd5sum = WriteStringInMap(md5sum.Value());
901 if (unlikely(idxmd5sum == 0))
902 return 0;
903 Desc->md5sum = idxmd5sum;
904 }
a52f938b
OS
905
906 return Description;
907}
908 /*}}}*/
25396fb0 909// CacheGenerator::NewDepends - Create a dependency element /*{{{*/
dcb79bae
AL
910// ---------------------------------------------------------------------
911/* This creates a dependency element in the tree. It is linked to the
912 version and to the package that it is pointing to. */
25396fb0
DK
913bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
914 pkgCache::VerIterator &Ver,
915 string const &Version,
916 unsigned int const &Op,
917 unsigned int const &Type,
64dda04b 918 map_ptrloc* &OldDepLast)
9c44383f
DK
919{
920 map_ptrloc index = 0;
921 if (Version.empty() == false)
922 {
b8a884c0
DK
923 int const CmpOp = Op & 0x0F;
924 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
925 if (CmpOp == pkgCache::Dep::Equals && strcmp(Version.c_str(), Ver.VerStr()) == 0)
926 index = Ver->VerStr;
927
928 if (index == 0)
929 {
930 void const * const oldMap = Map.Data();
931 index = WriteStringInMap(Version);
932 if (unlikely(index == 0))
933 return false;
885594fc 934 if (OldDepLast != 0 && oldMap != Map.Data())
cf4ff3b7 935 OldDepLast += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
b8a884c0 936 }
9c44383f
DK
937 }
938 return NewDepends(Pkg, Ver, index, Op, Type, OldDepLast);
939}
940bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
941 pkgCache::VerIterator &Ver,
942 map_ptrloc const Version,
943 unsigned int const &Op,
944 unsigned int const &Type,
945 map_ptrloc* &OldDepLast)
dcb79bae 946{
a9fe5928 947 void const * const oldMap = Map.Data();
dcb79bae 948 // Get a structure
a9fe5928 949 map_ptrloc const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
5bf15716 950 if (unlikely(Dependency == 0))
dcb79bae 951 return false;
9c44383f 952
dcb79bae
AL
953 // Fill it in
954 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
a9fe5928 955 Dynamic<pkgCache::DepIterator> DynDep(Dep);
dcb79bae
AL
956 Dep->ParentVer = Ver.Index();
957 Dep->Type = Type;
958 Dep->CompareOp = Op;
9c44383f 959 Dep->Version = Version;
dcb79bae 960 Dep->ID = Cache.HeaderP->DependsCount++;
5bf15716 961
dcb79bae
AL
962 // Link it to the package
963 Dep->Package = Pkg.Index();
964 Dep->NextRevDepends = Pkg->RevDepends;
965 Pkg->RevDepends = Dep.Index();
25396fb0
DK
966
967 // Do we know where to link the Dependency to?
968 if (OldDepLast == NULL)
c1a22377 969 {
f9eec0e7 970 OldDepLast = &Ver->DependsList;
f7f0d6c7 971 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
f9eec0e7 972 OldDepLast = &D->NextDepends;
a9fe5928 973 } else if (oldMap != Map.Data())
cf4ff3b7 974 OldDepLast += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
45415543 975
f9eec0e7
AL
976 Dep->NextDepends = *OldDepLast;
977 *OldDepLast = Dep.Index();
978 OldDepLast = &Dep->NextDepends;
c1a22377 979
dcb79bae
AL
980 return true;
981}
982 /*}}}*/
25396fb0
DK
983// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
984// ---------------------------------------------------------------------
985/* This creates a Group and the Package to link this dependency to if
986 needed and handles also the caching of the old endpoint */
32b9a14c 987bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver,
25396fb0
DK
988 const string &PackageName,
989 const string &Arch,
990 const string &Version,
991 unsigned int Op,
992 unsigned int Type)
993{
994 pkgCache::GrpIterator Grp;
a9fe5928 995 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
25396fb0
DK
996 if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
997 return false;
998
999 // Locate the target package
1000 pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
c919ad6e 1001 // we don't create 'none' packages and their dependencies if we can avoid it …
7605509f 1002 if (Pkg.end() == true && Arch == "none" && strcmp(Ver.ParentPkg().Arch(), "none") != 0)
c919ad6e 1003 return true;
a9fe5928 1004 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
25396fb0
DK
1005 if (Pkg.end() == true) {
1006 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
1007 return false;
1008 }
1009
1010 // Is it a file dependency?
1011 if (unlikely(PackageName[0] == '/'))
1012 FoundFileDeps = true;
1013
1014 /* Caching the old end point speeds up generation substantially */
1015 if (OldDepVer != Ver) {
1016 OldDepLast = NULL;
1017 OldDepVer = Ver;
1018 }
1019
1020 return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
1021}
1022 /*}}}*/
dcb79bae
AL
1023// ListParser::NewProvides - Create a Provides element /*{{{*/
1024// ---------------------------------------------------------------------
1025/* */
32b9a14c 1026bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
67e0766f
DK
1027 const string &PkgName,
1028 const string &PkgArch,
171c75f1 1029 const string &Version)
dcb79bae
AL
1030{
1031 pkgCache &Cache = Owner->Cache;
8efa2a3b
AL
1032
1033 // We do not add self referencing provides
566046f4 1034 if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
959470da 1035 (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
8efa2a3b 1036 return true;
dcb79bae
AL
1037
1038 // Get a structure
a9fe5928 1039 map_ptrloc const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
5bf15716 1040 if (unlikely(Provides == 0))
dcb79bae 1041 return false;
a7e66b17 1042 Cache.HeaderP->ProvidesCount++;
dcb79bae
AL
1043
1044 // Fill it in
1045 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
a9fe5928 1046 Dynamic<pkgCache::PrvIterator> DynPrv(Prv);
dcb79bae
AL
1047 Prv->Version = Ver.Index();
1048 Prv->NextPkgProv = Ver->ProvidesList;
1049 Ver->ProvidesList = Prv.Index();
27cae771
MV
1050 if (Version.empty() == false) {
1051 map_ptrloc const idxProvideVersion = WriteString(Version);
1052 Prv->ProvideVersion = idxProvideVersion;
1053 if (unlikely(idxProvideVersion == 0))
1054 return false;
1055 }
dcb79bae
AL
1056
1057 // Locate the target package
8efa2a3b 1058 pkgCache::PkgIterator Pkg;
a9fe5928 1059 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
67e0766f 1060 if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
8efa2a3b 1061 return false;
dcb79bae
AL
1062
1063 // Link it to the package
1064 Prv->ParentPkg = Pkg.Index();
1065 Prv->NextProvides = Pkg->ProvidesList;
1066 Pkg->ProvidesList = Prv.Index();
1067
1068 return true;
1069}
1070 /*}}}*/
68134bda
DK
1071bool pkgCacheGenerator::ListParser::SameVersion(unsigned short const Hash,/*{{{*/
1072 pkgCache::VerIterator const &Ver)
1073{
1074 return Hash == Ver->Hash;
1075}
1076 /*}}}*/
578bfd0a
AL
1077// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1078// ---------------------------------------------------------------------
1079/* This is used to select which file is to be associated with all newly
b2e465d6 1080 added versions. The caller is responsible for setting the IMS fields. */
171c75f1 1081bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
b2e465d6
AL
1082 const pkgIndexFile &Index,
1083 unsigned long Flags)
578bfd0a 1084{
578bfd0a 1085 // Get some space for the structure
a9fe5928
DK
1086 map_ptrloc const idxFile = AllocateInMap(sizeof(*CurrentFile));
1087 if (unlikely(idxFile == 0))
578bfd0a 1088 return false;
a9fe5928
DK
1089 CurrentFile = Cache.PkgFileP + idxFile;
1090
578bfd0a 1091 // Fill it in
a9fe5928
DK
1092 map_ptrloc const idxFileName = WriteStringInMap(File);
1093 map_ptrloc const idxSite = WriteUniqString(Site);
1094 if (unlikely(idxFileName == 0 || idxSite == 0))
1095 return false;
1096 CurrentFile->FileName = idxFileName;
1097 CurrentFile->Site = idxSite;
578bfd0a
AL
1098 CurrentFile->NextFile = Cache.HeaderP->FileList;
1099 CurrentFile->Flags = Flags;
e1b74f61 1100 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
a9fe5928
DK
1101 map_ptrloc const idxIndexType = WriteUniqString(Index.GetType()->Label);
1102 if (unlikely(idxIndexType == 0))
1103 return false;
1104 CurrentFile->IndexType = idxIndexType;
578bfd0a 1105 PkgFileName = File;
ad00ae81 1106 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
b35d2f5f 1107 Cache.HeaderP->PackageFileCount++;
b2e465d6 1108
ddc1d8d0 1109 if (Progress != 0)
b2e465d6 1110 Progress->SubProgress(Index.Size());
8efa2a3b 1111 return true;
578bfd0a
AL
1112}
1113 /*}}}*/
f55a958f
AL
1114// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1115// ---------------------------------------------------------------------
1116/* This is used to create handles to strings. Given the same text it
1117 always returns the same number */
1118unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
1119 unsigned int Size)
1120{
f9eec0e7
AL
1121 /* We use a very small transient hash table here, this speeds up generation
1122 by a fair amount on slower machines */
1123 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
1124 if (Bucket != 0 &&
1125 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
1126 return Bucket->String;
1127
f55a958f
AL
1128 // Search for an insertion point
1129 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
1130 int Res = 1;
349cd3b8 1131 map_ptrloc *Last = &Cache.HeaderP->StringList;
f55a958f
AL
1132 for (; I != Cache.StringItemP; Last = &I->NextItem,
1133 I = Cache.StringItemP + I->NextItem)
1134 {
9c14e3d6 1135 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
f55a958f
AL
1136 if (Res >= 0)
1137 break;
1138 }
1139
1140 // Match
1141 if (Res == 0)
f9eec0e7
AL
1142 {
1143 Bucket = I;
0149949b 1144 return I->String;
f9eec0e7 1145 }
f55a958f
AL
1146
1147 // Get a structure
a9fe5928
DK
1148 void const * const oldMap = Map.Data();
1149 map_ptrloc const Item = AllocateInMap(sizeof(pkgCache::StringItem));
f55a958f 1150 if (Item == 0)
0149949b
AL
1151 return 0;
1152
a9fe5928
DK
1153 map_ptrloc const idxString = WriteStringInMap(S,Size);
1154 if (unlikely(idxString == 0))
1155 return 0;
1156 if (oldMap != Map.Data()) {
cf4ff3b7
DK
1157 Last += (map_ptrloc const * const) Map.Data() - (map_ptrloc const * const) oldMap;
1158 I += (pkgCache::StringItem const * const) Map.Data() - (pkgCache::StringItem const * const) oldMap;
a9fe5928
DK
1159 }
1160 *Last = Item;
1161
f55a958f
AL
1162 // Fill in the structure
1163 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
1164 ItemP->NextItem = I - Cache.StringItemP;
a9fe5928
DK
1165 ItemP->String = idxString;
1166
f9eec0e7 1167 Bucket = ItemP;
0149949b 1168 return ItemP->String;
f55a958f
AL
1169}
1170 /*}}}*/
b2e465d6 1171// CheckValidity - Check that a cache is up-to-date /*{{{*/
b35d2f5f 1172// ---------------------------------------------------------------------
b2e465d6
AL
1173/* This just verifies that each file in the list of index files exists,
1174 has matching attributes with the cache and the cache does not have
1175 any extra files. */
2ec858bc
MV
1176static bool CheckValidity(const string &CacheFile,
1177 pkgSourceList &List,
1178 FileIterator Start,
1179 FileIterator End,
1180 MMap **OutMap = 0)
b35d2f5f 1181{
c8e572e3 1182 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
b2e465d6
AL
1183 // No file, certainly invalid
1184 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
c8e572e3
MV
1185 {
1186 if (Debug == true)
1187 std::clog << "CacheFile doesn't exist" << std::endl;
b35d2f5f 1188 return false;
c8e572e3
MV
1189 }
1190
96d14a91 1191 if (List.GetLastModifiedTime() > GetModificationTime(CacheFile))
2ec858bc
MV
1192 {
1193 if (Debug == true)
1194 std::clog << "sources.list is newer than the cache" << std::endl;
1195 return false;
1196 }
1197
b2e465d6 1198 // Map it
b35d2f5f 1199 FileFd CacheF(CacheFile,FileFd::ReadOnly);
eb162ff7 1200 SPtr<MMap> Map = new MMap(CacheF,0);
b35d2f5f 1201 pkgCache Cache(Map);
b2e465d6 1202 if (_error->PendingError() == true || Map->Size() == 0)
b35d2f5f 1203 {
c8e572e3
MV
1204 if (Debug == true)
1205 std::clog << "Errors are pending or Map is empty()" << std::endl;
b35d2f5f
AL
1206 _error->Discard();
1207 return false;
1208 }
b35d2f5f 1209
b2e465d6
AL
1210 /* Now we check every index file, see if it is in the cache,
1211 verify the IMS data and check that it is on the disk too.. */
1212 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
1213 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
f7f0d6c7 1214 for (; Start != End; ++Start)
c8e572e3
MV
1215 {
1216 if (Debug == true)
1217 std::clog << "Checking PkgFile " << (*Start)->Describe() << ": ";
b2e465d6 1218 if ((*Start)->HasPackages() == false)
c8e572e3
MV
1219 {
1220 if (Debug == true)
1221 std::clog << "Has NO packages" << std::endl;
b2e465d6 1222 continue;
c8e572e3 1223 }
a77ad7c3 1224
b2e465d6 1225 if ((*Start)->Exists() == false)
b35d2f5f 1226 {
a791a450 1227#if 0 // mvo: we no longer give a message here (Default Sources spec)
b2e465d6
AL
1228 _error->WarningE("stat",_("Couldn't stat source package list %s"),
1229 (*Start)->Describe().c_str());
a791a450 1230#endif
c8e572e3
MV
1231 if (Debug == true)
1232 std::clog << "file doesn't exist" << std::endl;
b2e465d6 1233 continue;
b35d2f5f 1234 }
b2e465d6
AL
1235
1236 // FindInCache is also expected to do an IMS check.
1237 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
1238 if (File.end() == true)
c8e572e3
MV
1239 {
1240 if (Debug == true)
1241 std::clog << "FindInCache returned end-Pointer" << std::endl;
b35d2f5f 1242 return false;
c8e572e3 1243 }
a52f938b 1244
b2e465d6 1245 Visited[File->ID] = true;
c8e572e3
MV
1246 if (Debug == true)
1247 std::clog << "with ID " << File->ID << " is valid" << std::endl;
b35d2f5f
AL
1248 }
1249
b2e465d6
AL
1250 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
1251 if (Visited[I] == false)
c8e572e3
MV
1252 {
1253 if (Debug == true)
1254 std::clog << "File with ID" << I << " wasn't visited" << std::endl;
b2e465d6 1255 return false;
c8e572e3 1256 }
b35d2f5f 1257
b35d2f5f
AL
1258 if (_error->PendingError() == true)
1259 {
c8e572e3
MV
1260 if (Debug == true)
1261 {
1262 std::clog << "Validity failed because of pending errors:" << std::endl;
1263 _error->DumpErrors();
1264 }
b35d2f5f
AL
1265 _error->Discard();
1266 return false;
1267 }
b35d2f5f 1268
b2e465d6
AL
1269 if (OutMap != 0)
1270 *OutMap = Map.UnGuard();
b35d2f5f
AL
1271 return true;
1272}
1273 /*}}}*/
b2e465d6 1274// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 1275// ---------------------------------------------------------------------
b2e465d6
AL
1276/* Size is kind of an abstract notion that is only used for the progress
1277 meter */
e7b470ee 1278static unsigned long ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 1279{
b2e465d6 1280 unsigned long TotalSize = 0;
ef74268b 1281 for (; Start < End; ++Start)
b35d2f5f 1282 {
b2e465d6 1283 if ((*Start)->HasPackages() == false)
ef74268b 1284 continue;
b2e465d6 1285 TotalSize += (*Start)->Size();
b35d2f5f 1286 }
b2e465d6 1287 return TotalSize;
2d11135a
AL
1288}
1289 /*}}}*/
b2e465d6 1290// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 1291// ---------------------------------------------------------------------
b2e465d6
AL
1292/* */
1293static bool BuildCache(pkgCacheGenerator &Gen,
2e5f4e45 1294 OpProgress *Progress,
b2e465d6 1295 unsigned long &CurrentSize,unsigned long TotalSize,
e7b470ee 1296 FileIterator Start, FileIterator End)
2d11135a 1297{
45415543 1298 FileIterator I;
f7f0d6c7 1299 for (I = Start; I != End; ++I)
2d11135a 1300 {
45415543 1301 if ((*I)->HasPackages() == false)
2d11135a
AL
1302 continue;
1303
45415543 1304 if ((*I)->Exists() == false)
2d11135a 1305 continue;
b2e465d6 1306
45415543 1307 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
a77ad7c3
AL
1308 {
1309 _error->Warning("Duplicate sources.list entry %s",
45415543 1310 (*I)->Describe().c_str());
a77ad7c3
AL
1311 continue;
1312 }
1313
45415543 1314 unsigned long Size = (*I)->Size();
2e5f4e45
DK
1315 if (Progress != NULL)
1316 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
b2e465d6 1317 CurrentSize += Size;
2d11135a 1318
45415543 1319 if ((*I)->Merge(Gen,Progress) == false)
b2e465d6
AL
1320 return false;
1321 }
45415543
AL
1322
1323 if (Gen.HasFileDeps() == true)
1324 {
2e5f4e45
DK
1325 if (Progress != NULL)
1326 Progress->Done();
45415543
AL
1327 TotalSize = ComputeSize(Start, End);
1328 CurrentSize = 0;
f7f0d6c7 1329 for (I = Start; I != End; ++I)
45415543
AL
1330 {
1331 unsigned long Size = (*I)->Size();
2e5f4e45
DK
1332 if (Progress != NULL)
1333 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
45415543
AL
1334 CurrentSize += Size;
1335 if ((*I)->MergeFileProvides(Gen,Progress) == false)
1336 return false;
1337 }
1338 }
2d11135a 1339
b35d2f5f
AL
1340 return true;
1341}
1342 /*}}}*/
dd13742e 1343// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
dcdf1ef1
DK
1344DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) {
1345 unsigned long const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1346 unsigned long const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1347 unsigned long const MapLimit = _config->FindI("APT::Cache-Limit", 0);
1348 Flags |= MMap::Moveable;
1349 if (_config->FindB("APT::Cache-Fallback", false) == true)
1350 Flags |= MMap::Fallback;
1351 if (CacheF != NULL)
1352 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1353 else
1354 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1355}
dd13742e 1356 /*}}}*/
2e5f4e45 1357// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 1358// ---------------------------------------------------------------------
b2e465d6
AL
1359/* This makes sure that the status cache (the cache that has all
1360 index files from the sources list and all local ones) is ready
1361 to be mmaped. If OutMap is not zero then a MMap object representing
1362 the cache will be stored there. This is pretty much mandetory if you
1363 are using AllowMem. AllowMem lets the function be run as non-root
1364 where it builds the cache 'fast' into a memory buffer. */
453b82a3 1365APT_DEPRECATED bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
2e5f4e45
DK
1366 MMap **OutMap, bool AllowMem)
1367 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1368bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
b2e465d6 1369 MMap **OutMap,bool AllowMem)
b35d2f5f 1370{
c8e572e3 1371 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
73688d27
DK
1372
1373 std::vector<pkgIndexFile *> Files;
1374 for (std::vector<metaIndex *>::const_iterator i = List.begin();
7db98ffc 1375 i != List.end();
f7f0d6c7 1376 ++i)
7db98ffc 1377 {
73688d27
DK
1378 std::vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1379 for (std::vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
7db98ffc 1380 j != Indexes->end();
f7f0d6c7 1381 ++j)
7db98ffc
MZ
1382 Files.push_back (*j);
1383 }
1384
c8e572e3 1385 unsigned long const EndOfSource = Files.size();
b2e465d6
AL
1386 if (_system->AddStatusFiles(Files) == false)
1387 return false;
c5f44afc 1388
b2e465d6 1389 // Decide if we can write to the files..
c8e572e3
MV
1390 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1391 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1cd1c398
DK
1392
1393 // ensure the cache directory exists
1394 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1395 {
1396 string dir = _config->FindDir("Dir::Cache");
1397 size_t const len = dir.size();
1398 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1399 dir = dir.substr(0, len - 5);
1400 if (CacheFile.empty() == false)
1401 CreateDirectory(dir, flNotFile(CacheFile));
1402 if (SrcCacheFile.empty() == false)
1403 CreateDirectory(dir, flNotFile(SrcCacheFile));
1404 }
1405
b2e465d6
AL
1406 // Decide if we can write to the cache
1407 bool Writeable = false;
1408 if (CacheFile.empty() == false)
1409 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1410 else
1411 if (SrcCacheFile.empty() == false)
1412 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
c8e572e3
MV
1413 if (Debug == true)
1414 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1415
b2e465d6
AL
1416 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
1417 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
2e5f4e45
DK
1418
1419 if (Progress != NULL)
1420 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1421
b2e465d6 1422 // Cache is OK, Fin.
2ec858bc 1423 if (CheckValidity(CacheFile, List, Files.begin(),Files.end(),OutMap) == true)
b2e465d6 1424 {
2e5f4e45
DK
1425 if (Progress != NULL)
1426 Progress->OverallProgress(1,1,1,_("Reading package lists"));
c8e572e3
MV
1427 if (Debug == true)
1428 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
b2e465d6
AL
1429 return true;
1430 }
c8e572e3
MV
1431 else if (Debug == true)
1432 std::clog << "pkgcache.bin is NOT valid" << std::endl;
b2e465d6
AL
1433
1434 /* At this point we know we need to reconstruct the package cache,
1435 begin. */
1436 SPtr<FileFd> CacheF;
1437 SPtr<DynamicMMap> Map;
1438 if (Writeable == true && CacheFile.empty() == false)
1439 {
41b4dee4 1440 _error->PushToStack();
b2e465d6 1441 unlink(CacheFile.c_str());
22041bd2 1442 CacheF = new FileFd(CacheFile,FileFd::WriteAtomic);
7a3c2ab0 1443 fchmod(CacheF->Fd(),0644);
dcdf1ef1 1444 Map = CreateDynamicMMap(CacheF, MMap::Public);
b35d2f5f 1445 if (_error->PendingError() == true)
41b4dee4
DK
1446 {
1447 delete CacheF.UnGuard();
1448 delete Map.UnGuard();
1449 if (Debug == true)
1450 std::clog << "Open filebased MMap FAILED" << std::endl;
1451 Writeable = false;
1452 if (AllowMem == false)
1453 {
1454 _error->MergeWithStack();
1455 return false;
1456 }
1457 _error->RevertToStack();
1458 }
0952aee6 1459 else
41b4dee4
DK
1460 {
1461 _error->MergeWithStack();
0952aee6
DH
1462 if (Debug == true)
1463 std::clog << "Open filebased MMap" << std::endl;
41b4dee4 1464 }
b35d2f5f 1465 }
41b4dee4 1466 if (Writeable == false || CacheFile.empty() == true)
8ce4327b 1467 {
b2e465d6 1468 // Just build it in memory..
dcdf1ef1 1469 Map = CreateDynamicMMap(NULL);
c8e572e3
MV
1470 if (Debug == true)
1471 std::clog << "Open memory Map (not filebased)" << std::endl;
8ce4327b 1472 }
b35d2f5f 1473
b2e465d6 1474 // Lets try the source cache.
b35d2f5f 1475 unsigned long CurrentSize = 0;
b2e465d6 1476 unsigned long TotalSize = 0;
2ec858bc 1477 if (CheckValidity(SrcCacheFile, List, Files.begin(),
b2e465d6 1478 Files.begin()+EndOfSource) == true)
2d11135a 1479 {
c8e572e3
MV
1480 if (Debug == true)
1481 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
b2e465d6
AL
1482 // Preload the map with the source cache
1483 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
c8e572e3 1484 unsigned long const alloc = Map->RawAllocate(SCacheF.Size());
eb162ff7
DK
1485 if ((alloc == 0 && _error->PendingError())
1486 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
1487 SCacheF.Size()) == false)
b2e465d6
AL
1488 return false;
1489
1490 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
c8e572e3 1491
b2e465d6 1492 // Build the status cache
2e5f4e45 1493 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1494 if (_error->PendingError() == true)
b2e465d6
AL
1495 return false;
1496 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1497 Files.begin()+EndOfSource,Files.end()) == false)
1498 return false;
1499 }
1500 else
2d11135a 1501 {
c8e572e3
MV
1502 if (Debug == true)
1503 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
b2e465d6 1504 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 1505
b2e465d6 1506 // Build the source cache
2e5f4e45 1507 pkgCacheGenerator Gen(Map.Get(),Progress);
b2e465d6
AL
1508 if (_error->PendingError() == true)
1509 return false;
1510 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1511 Files.begin(),Files.begin()+EndOfSource) == false)
1512 return false;
2d11135a 1513
b2e465d6
AL
1514 // Write it back
1515 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 1516 {
22041bd2 1517 FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic);
b2e465d6
AL
1518 if (_error->PendingError() == true)
1519 return false;
7a3c2ab0
AL
1520
1521 fchmod(SCacheF.Fd(),0644);
1522
b2e465d6
AL
1523 // Write out the main data
1524 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1525 return _error->Error(_("IO Error saving source cache"));
1526 SCacheF.Sync();
1527
1528 // Write out the proper header
1529 Gen.GetCache().HeaderP->Dirty = false;
1530 if (SCacheF.Seek(0) == false ||
1531 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
1532 return _error->Error(_("IO Error saving source cache"));
b2e465d6 1533 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 1534 SCacheF.Sync();
2d11135a
AL
1535 }
1536
b2e465d6
AL
1537 // Build the status cache
1538 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1539 Files.begin()+EndOfSource,Files.end()) == false)
1540 return false;
2d11135a 1541 }
c8e572e3
MV
1542 if (Debug == true)
1543 std::clog << "Caches are ready for shipping" << std::endl;
2d11135a 1544
b2e465d6
AL
1545 if (_error->PendingError() == true)
1546 return false;
1547 if (OutMap != 0)
2d11135a 1548 {
b2e465d6 1549 if (CacheF != 0)
2d11135a 1550 {
b2e465d6 1551 delete Map.UnGuard();
eb162ff7 1552 *OutMap = new MMap(*CacheF,0);
2d11135a 1553 }
b2e465d6
AL
1554 else
1555 {
1556 *OutMap = Map.UnGuard();
1557 }
2d11135a
AL
1558 }
1559
b2e465d6
AL
1560 return true;
1561}
1562 /*}}}*/
2e5f4e45 1563// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
b2e465d6
AL
1564// ---------------------------------------------------------------------
1565/* */
453b82a3 1566APT_DEPRECATED bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
2e5f4e45
DK
1567 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1568bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
b2e465d6 1569{
73688d27 1570 std::vector<pkgIndexFile *> Files;
b2e465d6
AL
1571 unsigned long EndOfSource = Files.size();
1572 if (_system->AddStatusFiles(Files) == false)
1573 return false;
dcdf1ef1
DK
1574
1575 SPtr<DynamicMMap> Map = CreateDynamicMMap(NULL);
b2e465d6
AL
1576 unsigned long CurrentSize = 0;
1577 unsigned long TotalSize = 0;
1578
1579 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1580
1581 // Build the status cache
2e5f4e45
DK
1582 if (Progress != NULL)
1583 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1584 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1585 if (_error->PendingError() == true)
b2e465d6
AL
1586 return false;
1587 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1588 Files.begin()+EndOfSource,Files.end()) == false)
1589 return false;
25396fb0 1590
b2e465d6
AL
1591 if (_error->PendingError() == true)
1592 return false;
1593 *OutMap = Map.UnGuard();
2d11135a 1594
b2e465d6 1595 return true;
2d11135a
AL
1596}
1597 /*}}}*/
5f4db009 1598// IsDuplicateDescription /*{{{*/
60683765 1599static bool IsDuplicateDescription(pkgCache::DescIterator Desc,
5f4db009
DK
1600 MD5SumValue const &CurMd5, std::string const &CurLang)
1601{
22f07fc5 1602 // Descriptions in the same link-list have all the same md5
7f5aab82 1603 if (Desc.end() == true || MD5SumValue(Desc.md5()) != CurMd5)
22f07fc5
DK
1604 return false;
1605 for (; Desc.end() == false; ++Desc)
1606 if (Desc.LanguageCode() == CurLang)
5f4db009
DK
1607 return true;
1608 return false;
1609}
1610 /*}}}*/
5a8e963b 1611// CacheGenerator::FinishCache /*{{{*/
65512241 1612bool pkgCacheGenerator::FinishCache(OpProgress * /*Progress*/)
5a8e963b
DK
1613{
1614 return true;
1615}
1616 /*}}}*/