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