]> git.saurik.com Git - apt.git/blame - apt-pkg/pkgcachegen.cc
fix 'Source' to 'Package' rename in apt-ftparchive
[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
32ab4bd0 77 if (Map.RawAllocate(2 * (Cache.HeaderP->GetHashTableSize() * 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;
32ab4bd0 99 Cache.HeaderP->SetArchitectures(idxArchitectures);
7a223b93
DK
100 }
101 else
32ab4bd0 102 Cache.HeaderP->SetArchitectures(idxArchitecture);
7a223b93 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;
804de19f 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);
b13ce62c 612 map_stringitem_t const idxName = StoreString(PKGNAME, 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);
32ab4bd0 619 map_pointer_t *insertAt = &Cache.HeaderP->GrpHashTableP()[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 654 map_id_t const Hash = Cache.Hash(Name);
32ab4bd0 655 map_pointer_t *insertAt = &Cache.HeaderP->PkgHashTableP()[Hash];
fe86debb 656 while (*insertAt != 0 && strcasecmp(Name.c_str(), Cache.StrP + (Cache.GrpP + (Cache.PkgP + *insertAt)->Group)->Name) > 0)
32ab4bd0
DK
657 insertAt = &(Cache.PkgP + *insertAt)->NextPackage;
658 Pkg->NextPackage = *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);
32ab4bd0
DK
665 Pkg->NextPackage = LastPkg->NextPackage;
666 LastPkg->NextPackage = Package;
c408e01e
DK
667 }
668 Grp->LastPackage = Package;
5bf15716
DK
669
670 // Set the name, arch and the ID
586d8704 671 APT_IGNORE_DEPRECATED(Pkg->Name = Grp->Name;)
5bf15716 672 Pkg->Group = Grp.Index();
959470da 673 // all is mapped to the native architecture
78a5476f 674 map_stringitem_t const idxArch = (Arch == "all") ? Cache.HeaderP->Architecture : StoreString(MIXED, Arch);
a9fe5928 675 if (unlikely(idxArch == 0))
578bfd0a 676 return false;
a9fe5928 677 Pkg->Arch = idxArch;
578bfd0a 678 Pkg->ID = Cache.HeaderP->PackageCount++;
5bf15716 679
578bfd0a
AL
680 return true;
681}
5a8e963b
DK
682 /*}}}*/
683// CacheGenerator::AddImplicitDepends /*{{{*/
684bool pkgCacheGenerator::AddImplicitDepends(pkgCache::GrpIterator &G,
685 pkgCache::PkgIterator &P,
686 pkgCache::VerIterator &V)
687{
688 // copy P.Arch() into a string here as a cache remap
689 // in NewDepends() later may alter the pointer location
690 string Arch = P.Arch() == NULL ? "" : P.Arch();
4ad8619b 691 map_pointer_t *OldDepLast = NULL;
5a8e963b
DK
692 /* MultiArch handling introduces a lot of implicit Dependencies:
693 - MultiArch: same → Co-Installable if they have the same version
694 - All others conflict with all other group members */
695 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
696 pkgCache::PkgIterator D = G.PackageList();
697 Dynamic<pkgCache::PkgIterator> DynD(D);
4ad8619b 698 map_stringitem_t const VerStrIdx = V->VerStr;
5a8e963b
DK
699 for (; D.end() != true; D = G.NextPkg(D))
700 {
701 if (Arch == D.Arch() || D->VersionList == 0)
702 continue;
703 /* We allow only one installed arch at the time
704 per group, therefore each group member conflicts
705 with all other group members */
706 if (coInstall == true)
707 {
708 // Replaces: ${self}:other ( << ${binary:Version})
9c44383f 709 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
710 pkgCache::Dep::Less, pkgCache::Dep::Replaces,
711 OldDepLast);
712 // Breaks: ${self}:other (!= ${binary:Version})
9c44383f 713 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
714 pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks,
715 OldDepLast);
716 } else {
717 // Conflicts: ${self}:other
9c44383f 718 NewDepends(D, V, 0,
5a8e963b
DK
719 pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
720 OldDepLast);
721 }
722 }
723 return true;
724}
725bool pkgCacheGenerator::AddImplicitDepends(pkgCache::VerIterator &V,
726 pkgCache::PkgIterator &D)
727{
728 /* MultiArch handling introduces a lot of implicit Dependencies:
729 - MultiArch: same → Co-Installable if they have the same version
730 - All others conflict with all other group members */
4ad8619b 731 map_pointer_t *OldDepLast = NULL;
5a8e963b
DK
732 bool const coInstall = ((V->MultiArch & pkgCache::Version::Same) == pkgCache::Version::Same);
733 if (coInstall == true)
734 {
4ad8619b 735 map_stringitem_t const VerStrIdx = V->VerStr;
5a8e963b 736 // Replaces: ${self}:other ( << ${binary:Version})
9c44383f 737 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
738 pkgCache::Dep::Less, pkgCache::Dep::Replaces,
739 OldDepLast);
740 // Breaks: ${self}:other (!= ${binary:Version})
9c44383f 741 NewDepends(D, V, VerStrIdx,
5a8e963b
DK
742 pkgCache::Dep::NotEquals, pkgCache::Dep::DpkgBreaks,
743 OldDepLast);
744 } else {
745 // Conflicts: ${self}:other
9c44383f 746 NewDepends(D, V, 0,
5a8e963b
DK
747 pkgCache::Dep::NoOp, pkgCache::Dep::Conflicts,
748 OldDepLast);
749 }
750 return true;
751}
752
578bfd0a
AL
753 /*}}}*/
754// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
755// ---------------------------------------------------------------------
756/* */
f55a958f 757bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
578bfd0a
AL
758 ListParser &List)
759{
ddc1d8d0
AL
760 if (CurrentFile == 0)
761 return true;
762
dcb79bae 763 // Get a structure
4ad8619b 764 map_pointer_t const VerFile = AllocateInMap(sizeof(pkgCache::VerFile));
dcb79bae 765 if (VerFile == 0)
ac2c559b 766 return false;
dcb79bae
AL
767
768 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
769 VF->File = CurrentFile - Cache.PkgFileP;
03e39e59
AL
770
771 // Link it to the end of the list
4ad8619b 772 map_pointer_t *Last = &Ver->FileList;
f7f0d6c7 773 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; ++V)
03e39e59
AL
774 Last = &V->NextFile;
775 VF->NextFile = *Last;
776 *Last = VF.Index();
777
dcb79bae
AL
778 VF->Offset = List.Offset();
779 VF->Size = List.Size();
ad00ae81
AL
780 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
781 Cache.HeaderP->MaxVerFileSize = VF->Size;
a7e66b17
AL
782 Cache.HeaderP->VerFileCount++;
783
f55a958f 784 return true;
578bfd0a
AL
785}
786 /*}}}*/
787// CacheGenerator::NewVersion - Create a new Version /*{{{*/
788// ---------------------------------------------------------------------
f55a958f 789/* This puts a version structure in the linked list */
4ad8619b 790map_pointer_t pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
171c75f1 791 const string &VerStr,
4ad8619b
DK
792 map_pointer_t const ParentPkg,
793 unsigned short const Hash,
794 map_pointer_t const Next)
578bfd0a 795{
f55a958f 796 // Get a structure
4ad8619b 797 map_pointer_t const Version = AllocateInMap(sizeof(pkgCache::Version));
f55a958f 798 if (Version == 0)
0149949b 799 return 0;
f55a958f
AL
800
801 // Fill it in
802 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
dfe45e1f 803 //Dynamic<pkgCache::VerIterator> DynV(Ver); // caller MergeListVersion already takes care of it
f55a958f 804 Ver->NextVer = Next;
885594fc
DK
805 Ver->ParentPkg = ParentPkg;
806 Ver->Hash = Hash;
f55a958f 807 Ver->ID = Cache.HeaderP->VersionCount++;
885594fc
DK
808
809 // try to find the version string in the group for reuse
810 pkgCache::PkgIterator Pkg = Ver.ParentPkg();
811 pkgCache::GrpIterator Grp = Pkg.Group();
812 if (Pkg.end() == false && Grp.end() == false)
813 {
814 for (pkgCache::PkgIterator P = Grp.PackageList(); P.end() == false; P = Grp.NextPkg(P))
815 {
816 if (Pkg == P)
817 continue;
818 for (pkgCache::VerIterator V = P.VersionList(); V.end() == false; ++V)
819 {
820 int const cmp = strcmp(V.VerStr(), VerStr.c_str());
821 if (cmp == 0)
822 {
823 Ver->VerStr = V->VerStr;
824 return Version;
825 }
826 else if (cmp < 0)
827 break;
828 }
829 }
830 }
831 // haven't found the version string, so create
30b45652 832 map_stringitem_t const idxVerStr = StoreString(VERSIONNUMBER, VerStr);
a9fe5928 833 if (unlikely(idxVerStr == 0))
0149949b 834 return 0;
a9fe5928 835 Ver->VerStr = idxVerStr;
0149949b 836 return Version;
578bfd0a
AL
837}
838 /*}}}*/
a52f938b
OS
839// CacheGenerator::NewFileDesc - Create a new File<->Desc association /*{{{*/
840// ---------------------------------------------------------------------
841/* */
842bool pkgCacheGenerator::NewFileDesc(pkgCache::DescIterator &Desc,
843 ListParser &List)
844{
845 if (CurrentFile == 0)
846 return true;
847
848 // Get a structure
4ad8619b 849 map_pointer_t const DescFile = AllocateInMap(sizeof(pkgCache::DescFile));
a52f938b 850 if (DescFile == 0)
c5f44afc 851 return false;
770c32ec 852
a52f938b
OS
853 pkgCache::DescFileIterator DF(Cache,Cache.DescFileP + DescFile);
854 DF->File = CurrentFile - Cache.PkgFileP;
770c32ec 855
a52f938b 856 // Link it to the end of the list
4ad8619b 857 map_pointer_t *Last = &Desc->FileList;
f7f0d6c7 858 for (pkgCache::DescFileIterator D = Desc.FileList(); D.end() == false; ++D)
a52f938b 859 Last = &D->NextFile;
770c32ec 860
a52f938b
OS
861 DF->NextFile = *Last;
862 *Last = DF.Index();
863
864 DF->Offset = List.Offset();
865 DF->Size = List.Size();
866 if (Cache.HeaderP->MaxDescFileSize < DF->Size)
867 Cache.HeaderP->MaxDescFileSize = DF->Size;
868 Cache.HeaderP->DescFileCount++;
869
870 return true;
871}
872 /*}}}*/
873// CacheGenerator::NewDescription - Create a new Description /*{{{*/
874// ---------------------------------------------------------------------
875/* This puts a description structure in the linked list */
4ad8619b 876map_pointer_t pkgCacheGenerator::NewDescription(pkgCache::DescIterator &Desc,
a65e22c6
DK
877 const string &Lang,
878 const MD5SumValue &md5sum,
4ad8619b 879 map_stringitem_t const idxmd5str)
a52f938b
OS
880{
881 // Get a structure
4ad8619b 882 map_pointer_t const Description = AllocateInMap(sizeof(pkgCache::Description));
a52f938b
OS
883 if (Description == 0)
884 return 0;
885
886 // Fill it in
887 Desc = pkgCache::DescIterator(Cache,Cache.DescP + Description);
a52f938b 888 Desc->ID = Cache.HeaderP->DescriptionCount++;
78a5476f 889 map_stringitem_t const idxlanguage_code = StoreString(MIXED, Lang);
a65e22c6 890 if (unlikely(idxlanguage_code == 0))
c5f44afc 891 return 0;
a9fe5928 892 Desc->language_code = idxlanguage_code;
a65e22c6
DK
893
894 if (idxmd5str != 0)
895 Desc->md5sum = idxmd5str;
896 else
897 {
4ad8619b 898 map_stringitem_t const idxmd5sum = WriteStringInMap(md5sum.Value());
a65e22c6
DK
899 if (unlikely(idxmd5sum == 0))
900 return 0;
901 Desc->md5sum = idxmd5sum;
902 }
a52f938b
OS
903
904 return Description;
905}
906 /*}}}*/
25396fb0 907// CacheGenerator::NewDepends - Create a dependency element /*{{{*/
dcb79bae
AL
908// ---------------------------------------------------------------------
909/* This creates a dependency element in the tree. It is linked to the
910 version and to the package that it is pointing to. */
25396fb0
DK
911bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
912 pkgCache::VerIterator &Ver,
913 string const &Version,
914 unsigned int const &Op,
915 unsigned int const &Type,
4ad8619b 916 map_stringitem_t* &OldDepLast)
9c44383f 917{
4ad8619b 918 map_stringitem_t index = 0;
9c44383f
DK
919 if (Version.empty() == false)
920 {
b8a884c0
DK
921 int const CmpOp = Op & 0x0F;
922 // =-deps are used (79:1) for lockstep on same-source packages (e.g. data-packages)
923 if (CmpOp == pkgCache::Dep::Equals && strcmp(Version.c_str(), Ver.VerStr()) == 0)
924 index = Ver->VerStr;
925
926 if (index == 0)
927 {
928 void const * const oldMap = Map.Data();
30b45652 929 index = StoreString(VERSIONNUMBER, Version);
b8a884c0
DK
930 if (unlikely(index == 0))
931 return false;
885594fc 932 if (OldDepLast != 0 && oldMap != Map.Data())
4ad8619b 933 OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
b8a884c0 934 }
9c44383f
DK
935 }
936 return NewDepends(Pkg, Ver, index, Op, Type, OldDepLast);
937}
938bool pkgCacheGenerator::NewDepends(pkgCache::PkgIterator &Pkg,
939 pkgCache::VerIterator &Ver,
4ad8619b 940 map_pointer_t const Version,
9c44383f
DK
941 unsigned int const &Op,
942 unsigned int const &Type,
4ad8619b 943 map_pointer_t* &OldDepLast)
dcb79bae 944{
a9fe5928 945 void const * const oldMap = Map.Data();
dcb79bae 946 // Get a structure
4ad8619b 947 map_pointer_t const Dependency = AllocateInMap(sizeof(pkgCache::Dependency));
5bf15716 948 if (unlikely(Dependency == 0))
dcb79bae 949 return false;
9c44383f 950
dcb79bae
AL
951 // Fill it in
952 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
a9fe5928 953 Dynamic<pkgCache::DepIterator> DynDep(Dep);
dcb79bae
AL
954 Dep->ParentVer = Ver.Index();
955 Dep->Type = Type;
956 Dep->CompareOp = Op;
9c44383f 957 Dep->Version = Version;
dcb79bae 958 Dep->ID = Cache.HeaderP->DependsCount++;
5bf15716 959
dcb79bae
AL
960 // Link it to the package
961 Dep->Package = Pkg.Index();
962 Dep->NextRevDepends = Pkg->RevDepends;
963 Pkg->RevDepends = Dep.Index();
25396fb0
DK
964
965 // Do we know where to link the Dependency to?
966 if (OldDepLast == NULL)
c1a22377 967 {
f9eec0e7 968 OldDepLast = &Ver->DependsList;
f7f0d6c7 969 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; ++D)
f9eec0e7 970 OldDepLast = &D->NextDepends;
a9fe5928 971 } else if (oldMap != Map.Data())
4ad8619b 972 OldDepLast += (map_pointer_t const * const) Map.Data() - (map_pointer_t const * const) oldMap;
45415543 973
f9eec0e7
AL
974 Dep->NextDepends = *OldDepLast;
975 *OldDepLast = Dep.Index();
976 OldDepLast = &Dep->NextDepends;
c1a22377 977
dcb79bae
AL
978 return true;
979}
980 /*}}}*/
25396fb0
DK
981// ListParser::NewDepends - Create the environment for a new dependency /*{{{*/
982// ---------------------------------------------------------------------
983/* This creates a Group and the Package to link this dependency to if
984 needed and handles also the caching of the old endpoint */
32b9a14c 985bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator &Ver,
25396fb0
DK
986 const string &PackageName,
987 const string &Arch,
988 const string &Version,
989 unsigned int Op,
990 unsigned int Type)
991{
992 pkgCache::GrpIterator Grp;
a9fe5928 993 Dynamic<pkgCache::GrpIterator> DynGrp(Grp);
25396fb0
DK
994 if (unlikely(Owner->NewGroup(Grp, PackageName) == false))
995 return false;
996
997 // Locate the target package
998 pkgCache::PkgIterator Pkg = Grp.FindPkg(Arch);
c919ad6e 999 // we don't create 'none' packages and their dependencies if we can avoid it …
7605509f 1000 if (Pkg.end() == true && Arch == "none" && strcmp(Ver.ParentPkg().Arch(), "none") != 0)
c919ad6e 1001 return true;
a9fe5928 1002 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
25396fb0
DK
1003 if (Pkg.end() == true) {
1004 if (unlikely(Owner->NewPackage(Pkg, PackageName, Arch) == false))
1005 return false;
1006 }
1007
1008 // Is it a file dependency?
1009 if (unlikely(PackageName[0] == '/'))
1010 FoundFileDeps = true;
1011
1012 /* Caching the old end point speeds up generation substantially */
1013 if (OldDepVer != Ver) {
1014 OldDepLast = NULL;
1015 OldDepVer = Ver;
1016 }
1017
1018 return Owner->NewDepends(Pkg, Ver, Version, Op, Type, OldDepLast);
1019}
1020 /*}}}*/
dcb79bae
AL
1021// ListParser::NewProvides - Create a Provides element /*{{{*/
1022// ---------------------------------------------------------------------
1023/* */
32b9a14c 1024bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator &Ver,
67e0766f
DK
1025 const string &PkgName,
1026 const string &PkgArch,
171c75f1 1027 const string &Version)
dcb79bae
AL
1028{
1029 pkgCache &Cache = Owner->Cache;
8efa2a3b
AL
1030
1031 // We do not add self referencing provides
566046f4 1032 if (Ver.ParentPkg().Name() == PkgName && (PkgArch == Ver.ParentPkg().Arch() ||
959470da 1033 (PkgArch == "all" && strcmp((Cache.StrP + Cache.HeaderP->Architecture), Ver.ParentPkg().Arch()) == 0)))
8efa2a3b 1034 return true;
dcb79bae
AL
1035
1036 // Get a structure
4ad8619b 1037 map_pointer_t const Provides = Owner->AllocateInMap(sizeof(pkgCache::Provides));
5bf15716 1038 if (unlikely(Provides == 0))
dcb79bae 1039 return false;
a7e66b17 1040 Cache.HeaderP->ProvidesCount++;
dcb79bae
AL
1041
1042 // Fill it in
1043 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
a9fe5928 1044 Dynamic<pkgCache::PrvIterator> DynPrv(Prv);
dcb79bae
AL
1045 Prv->Version = Ver.Index();
1046 Prv->NextPkgProv = Ver->ProvidesList;
1047 Ver->ProvidesList = Prv.Index();
27cae771 1048 if (Version.empty() == false) {
4ad8619b 1049 map_stringitem_t const idxProvideVersion = WriteString(Version);
27cae771
MV
1050 Prv->ProvideVersion = idxProvideVersion;
1051 if (unlikely(idxProvideVersion == 0))
1052 return false;
1053 }
dcb79bae
AL
1054
1055 // Locate the target package
8efa2a3b 1056 pkgCache::PkgIterator Pkg;
a9fe5928 1057 Dynamic<pkgCache::PkgIterator> DynPkg(Pkg);
67e0766f 1058 if (unlikely(Owner->NewPackage(Pkg,PkgName, PkgArch) == false))
8efa2a3b 1059 return false;
dcb79bae
AL
1060
1061 // Link it to the package
1062 Prv->ParentPkg = Pkg.Index();
1063 Prv->NextProvides = Pkg->ProvidesList;
1064 Pkg->ProvidesList = Prv.Index();
1065
1066 return true;
1067}
1068 /*}}}*/
68134bda
DK
1069bool pkgCacheGenerator::ListParser::SameVersion(unsigned short const Hash,/*{{{*/
1070 pkgCache::VerIterator const &Ver)
1071{
1072 return Hash == Ver->Hash;
1073}
1074 /*}}}*/
578bfd0a
AL
1075// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
1076// ---------------------------------------------------------------------
1077/* This is used to select which file is to be associated with all newly
b2e465d6 1078 added versions. The caller is responsible for setting the IMS fields. */
171c75f1 1079bool pkgCacheGenerator::SelectFile(const string &File,const string &Site,
b2e465d6
AL
1080 const pkgIndexFile &Index,
1081 unsigned long Flags)
578bfd0a 1082{
578bfd0a 1083 // Get some space for the structure
4ad8619b 1084 map_pointer_t const idxFile = AllocateInMap(sizeof(*CurrentFile));
a9fe5928 1085 if (unlikely(idxFile == 0))
578bfd0a 1086 return false;
a9fe5928
DK
1087 CurrentFile = Cache.PkgFileP + idxFile;
1088
578bfd0a 1089 // Fill it in
4ad8619b 1090 map_stringitem_t const idxFileName = WriteStringInMap(File);
78a5476f 1091 map_stringitem_t const idxSite = StoreString(MIXED, Site);
a9fe5928
DK
1092 if (unlikely(idxFileName == 0 || idxSite == 0))
1093 return false;
1094 CurrentFile->FileName = idxFileName;
1095 CurrentFile->Site = idxSite;
578bfd0a
AL
1096 CurrentFile->NextFile = Cache.HeaderP->FileList;
1097 CurrentFile->Flags = Flags;
e1b74f61 1098 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
78a5476f 1099 map_stringitem_t const idxIndexType = StoreString(MIXED, Index.GetType()->Label);
a9fe5928
DK
1100 if (unlikely(idxIndexType == 0))
1101 return false;
1102 CurrentFile->IndexType = idxIndexType;
578bfd0a 1103 PkgFileName = File;
ad00ae81 1104 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
b35d2f5f 1105 Cache.HeaderP->PackageFileCount++;
b2e465d6 1106
ddc1d8d0 1107 if (Progress != 0)
b2e465d6 1108 Progress->SubProgress(Index.Size());
8efa2a3b 1109 return true;
578bfd0a
AL
1110}
1111 /*}}}*/
f55a958f
AL
1112// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
1113// ---------------------------------------------------------------------
1114/* This is used to create handles to strings. Given the same text it
1115 always returns the same number */
78a5476f 1116map_stringitem_t pkgCacheGenerator::StoreString(enum StringType const type, const char *S,
f55a958f
AL
1117 unsigned int Size)
1118{
78a5476f
DK
1119 std::string const key(S, Size);
1120
1121 std::map<std::string,map_stringitem_t> * strings;
1122 switch(type) {
1123 case MIXED: strings = &strMixed; break;
1124 case PKGNAME: strings = &strPkgNames; break;
30b45652 1125 case VERSIONNUMBER: strings = &strVersions; break;
78a5476f
DK
1126 case SECTION: strings = &strSections; break;
1127 default: _error->Fatal("Unknown enum type used for string storage of '%s'", key.c_str()); return 0;
f55a958f 1128 }
a9fe5928 1129
78a5476f
DK
1130 std::map<std::string,map_stringitem_t>::const_iterator const item = strings->find(key);
1131 if (item != strings->end())
1132 return item->second;
a9fe5928 1133
78a5476f
DK
1134 map_stringitem_t const idxString = WriteStringInMap(S,Size);
1135 strings->insert(std::make_pair(key, idxString));
1136 return idxString;
f55a958f
AL
1137}
1138 /*}}}*/
b2e465d6 1139// CheckValidity - Check that a cache is up-to-date /*{{{*/
b35d2f5f 1140// ---------------------------------------------------------------------
b2e465d6
AL
1141/* This just verifies that each file in the list of index files exists,
1142 has matching attributes with the cache and the cache does not have
1143 any extra files. */
2ec858bc
MV
1144static bool CheckValidity(const string &CacheFile,
1145 pkgSourceList &List,
1146 FileIterator Start,
1147 FileIterator End,
1148 MMap **OutMap = 0)
b35d2f5f 1149{
c8e572e3 1150 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
b2e465d6
AL
1151 // No file, certainly invalid
1152 if (CacheFile.empty() == true || FileExists(CacheFile) == false)
c8e572e3
MV
1153 {
1154 if (Debug == true)
1155 std::clog << "CacheFile doesn't exist" << std::endl;
b35d2f5f 1156 return false;
c8e572e3
MV
1157 }
1158
96d14a91 1159 if (List.GetLastModifiedTime() > GetModificationTime(CacheFile))
2ec858bc
MV
1160 {
1161 if (Debug == true)
1162 std::clog << "sources.list is newer than the cache" << std::endl;
1163 return false;
1164 }
1165
b2e465d6 1166 // Map it
b35d2f5f 1167 FileFd CacheF(CacheFile,FileFd::ReadOnly);
eb162ff7 1168 SPtr<MMap> Map = new MMap(CacheF,0);
b35d2f5f 1169 pkgCache Cache(Map);
b2e465d6 1170 if (_error->PendingError() == true || Map->Size() == 0)
b35d2f5f 1171 {
c8e572e3
MV
1172 if (Debug == true)
1173 std::clog << "Errors are pending or Map is empty()" << std::endl;
b35d2f5f
AL
1174 _error->Discard();
1175 return false;
1176 }
b35d2f5f 1177
b2e465d6
AL
1178 /* Now we check every index file, see if it is in the cache,
1179 verify the IMS data and check that it is on the disk too.. */
1180 SPtrArray<bool> Visited = new bool[Cache.HeaderP->PackageFileCount];
1181 memset(Visited,0,sizeof(*Visited)*Cache.HeaderP->PackageFileCount);
f7f0d6c7 1182 for (; Start != End; ++Start)
c8e572e3
MV
1183 {
1184 if (Debug == true)
1185 std::clog << "Checking PkgFile " << (*Start)->Describe() << ": ";
b2e465d6 1186 if ((*Start)->HasPackages() == false)
c8e572e3
MV
1187 {
1188 if (Debug == true)
1189 std::clog << "Has NO packages" << std::endl;
b2e465d6 1190 continue;
c8e572e3 1191 }
a77ad7c3 1192
b2e465d6 1193 if ((*Start)->Exists() == false)
b35d2f5f 1194 {
a791a450 1195#if 0 // mvo: we no longer give a message here (Default Sources spec)
b2e465d6
AL
1196 _error->WarningE("stat",_("Couldn't stat source package list %s"),
1197 (*Start)->Describe().c_str());
a791a450 1198#endif
c8e572e3
MV
1199 if (Debug == true)
1200 std::clog << "file doesn't exist" << std::endl;
b2e465d6 1201 continue;
b35d2f5f 1202 }
b2e465d6
AL
1203
1204 // FindInCache is also expected to do an IMS check.
1205 pkgCache::PkgFileIterator File = (*Start)->FindInCache(Cache);
1206 if (File.end() == true)
c8e572e3
MV
1207 {
1208 if (Debug == true)
1209 std::clog << "FindInCache returned end-Pointer" << std::endl;
b35d2f5f 1210 return false;
c8e572e3 1211 }
a52f938b 1212
b2e465d6 1213 Visited[File->ID] = true;
c8e572e3
MV
1214 if (Debug == true)
1215 std::clog << "with ID " << File->ID << " is valid" << std::endl;
b35d2f5f
AL
1216 }
1217
b2e465d6
AL
1218 for (unsigned I = 0; I != Cache.HeaderP->PackageFileCount; I++)
1219 if (Visited[I] == false)
c8e572e3
MV
1220 {
1221 if (Debug == true)
1222 std::clog << "File with ID" << I << " wasn't visited" << std::endl;
b2e465d6 1223 return false;
c8e572e3 1224 }
b35d2f5f 1225
b35d2f5f
AL
1226 if (_error->PendingError() == true)
1227 {
c8e572e3
MV
1228 if (Debug == true)
1229 {
1230 std::clog << "Validity failed because of pending errors:" << std::endl;
1231 _error->DumpErrors();
1232 }
b35d2f5f
AL
1233 _error->Discard();
1234 return false;
1235 }
b35d2f5f 1236
b2e465d6
AL
1237 if (OutMap != 0)
1238 *OutMap = Map.UnGuard();
b35d2f5f
AL
1239 return true;
1240}
1241 /*}}}*/
b2e465d6 1242// ComputeSize - Compute the total size of a bunch of files /*{{{*/
b35d2f5f 1243// ---------------------------------------------------------------------
b2e465d6
AL
1244/* Size is kind of an abstract notion that is only used for the progress
1245 meter */
4ad8619b 1246static map_filesize_t ComputeSize(FileIterator Start,FileIterator End)
b35d2f5f 1247{
4ad8619b 1248 map_filesize_t TotalSize = 0;
ef74268b 1249 for (; Start < End; ++Start)
b35d2f5f 1250 {
b2e465d6 1251 if ((*Start)->HasPackages() == false)
ef74268b 1252 continue;
b2e465d6 1253 TotalSize += (*Start)->Size();
b35d2f5f 1254 }
b2e465d6 1255 return TotalSize;
2d11135a
AL
1256}
1257 /*}}}*/
b2e465d6 1258// BuildCache - Merge the list of index files into the cache /*{{{*/
2d11135a 1259// ---------------------------------------------------------------------
b2e465d6
AL
1260/* */
1261static bool BuildCache(pkgCacheGenerator &Gen,
2e5f4e45 1262 OpProgress *Progress,
4ad8619b 1263 map_filesize_t &CurrentSize,map_filesize_t TotalSize,
e7b470ee 1264 FileIterator Start, FileIterator End)
2d11135a 1265{
45415543 1266 FileIterator I;
f7f0d6c7 1267 for (I = Start; I != End; ++I)
2d11135a 1268 {
45415543 1269 if ((*I)->HasPackages() == false)
2d11135a
AL
1270 continue;
1271
45415543 1272 if ((*I)->Exists() == false)
2d11135a 1273 continue;
b2e465d6 1274
45415543 1275 if ((*I)->FindInCache(Gen.GetCache()).end() == false)
a77ad7c3
AL
1276 {
1277 _error->Warning("Duplicate sources.list entry %s",
45415543 1278 (*I)->Describe().c_str());
a77ad7c3
AL
1279 continue;
1280 }
1281
4ad8619b 1282 map_filesize_t Size = (*I)->Size();
2e5f4e45
DK
1283 if (Progress != NULL)
1284 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Reading package lists"));
b2e465d6 1285 CurrentSize += Size;
2d11135a 1286
45415543 1287 if ((*I)->Merge(Gen,Progress) == false)
b2e465d6
AL
1288 return false;
1289 }
45415543
AL
1290
1291 if (Gen.HasFileDeps() == true)
1292 {
2e5f4e45
DK
1293 if (Progress != NULL)
1294 Progress->Done();
45415543
AL
1295 TotalSize = ComputeSize(Start, End);
1296 CurrentSize = 0;
f7f0d6c7 1297 for (I = Start; I != End; ++I)
45415543 1298 {
4ad8619b 1299 map_filesize_t Size = (*I)->Size();
2e5f4e45
DK
1300 if (Progress != NULL)
1301 Progress->OverallProgress(CurrentSize,TotalSize,Size,_("Collecting File Provides"));
45415543
AL
1302 CurrentSize += Size;
1303 if ((*I)->MergeFileProvides(Gen,Progress) == false)
1304 return false;
1305 }
1306 }
2d11135a 1307
b35d2f5f
AL
1308 return true;
1309}
1310 /*}}}*/
dd13742e 1311// CacheGenerator::CreateDynamicMMap - load an mmap with configuration options /*{{{*/
dcdf1ef1 1312DynamicMMap* pkgCacheGenerator::CreateDynamicMMap(FileFd *CacheF, unsigned long Flags) {
4ad8619b
DK
1313 map_filesize_t const MapStart = _config->FindI("APT::Cache-Start", 24*1024*1024);
1314 map_filesize_t const MapGrow = _config->FindI("APT::Cache-Grow", 1*1024*1024);
1315 map_filesize_t const MapLimit = _config->FindI("APT::Cache-Limit", 0);
dcdf1ef1
DK
1316 Flags |= MMap::Moveable;
1317 if (_config->FindB("APT::Cache-Fallback", false) == true)
1318 Flags |= MMap::Fallback;
1319 if (CacheF != NULL)
1320 return new DynamicMMap(*CacheF, Flags, MapStart, MapGrow, MapLimit);
1321 else
1322 return new DynamicMMap(Flags, MapStart, MapGrow, MapLimit);
1323}
dd13742e 1324 /*}}}*/
2e5f4e45 1325// CacheGenerator::MakeStatusCache - Construct the status cache /*{{{*/
b35d2f5f 1326// ---------------------------------------------------------------------
b2e465d6
AL
1327/* This makes sure that the status cache (the cache that has all
1328 index files from the sources list and all local ones) is ready
1329 to be mmaped. If OutMap is not zero then a MMap object representing
1330 the cache will be stored there. This is pretty much mandetory if you
1331 are using AllowMem. AllowMem lets the function be run as non-root
1332 where it builds the cache 'fast' into a memory buffer. */
453b82a3 1333APT_DEPRECATED bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress,
2e5f4e45
DK
1334 MMap **OutMap, bool AllowMem)
1335 { return pkgCacheGenerator::MakeStatusCache(List, &Progress, OutMap, AllowMem); }
1336bool pkgCacheGenerator::MakeStatusCache(pkgSourceList &List,OpProgress *Progress,
b2e465d6 1337 MMap **OutMap,bool AllowMem)
b35d2f5f 1338{
c8e572e3 1339 bool const Debug = _config->FindB("Debug::pkgCacheGen", false);
73688d27
DK
1340
1341 std::vector<pkgIndexFile *> Files;
1342 for (std::vector<metaIndex *>::const_iterator i = List.begin();
7db98ffc 1343 i != List.end();
f7f0d6c7 1344 ++i)
7db98ffc 1345 {
73688d27
DK
1346 std::vector <pkgIndexFile *> *Indexes = (*i)->GetIndexFiles();
1347 for (std::vector<pkgIndexFile *>::const_iterator j = Indexes->begin();
7db98ffc 1348 j != Indexes->end();
f7f0d6c7 1349 ++j)
7db98ffc
MZ
1350 Files.push_back (*j);
1351 }
1352
4ad8619b 1353 map_filesize_t const EndOfSource = Files.size();
b2e465d6
AL
1354 if (_system->AddStatusFiles(Files) == false)
1355 return false;
c5f44afc 1356
b2e465d6 1357 // Decide if we can write to the files..
c8e572e3
MV
1358 string const CacheFile = _config->FindFile("Dir::Cache::pkgcache");
1359 string const SrcCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
1cd1c398
DK
1360
1361 // ensure the cache directory exists
1362 if (CacheFile.empty() == false || SrcCacheFile.empty() == false)
1363 {
1364 string dir = _config->FindDir("Dir::Cache");
1365 size_t const len = dir.size();
1366 if (len > 5 && dir.find("/apt/", len - 6, 5) == len - 5)
1367 dir = dir.substr(0, len - 5);
1368 if (CacheFile.empty() == false)
1369 CreateDirectory(dir, flNotFile(CacheFile));
1370 if (SrcCacheFile.empty() == false)
1371 CreateDirectory(dir, flNotFile(SrcCacheFile));
1372 }
1373
b2e465d6
AL
1374 // Decide if we can write to the cache
1375 bool Writeable = false;
1376 if (CacheFile.empty() == false)
1377 Writeable = access(flNotFile(CacheFile).c_str(),W_OK) == 0;
1378 else
1379 if (SrcCacheFile.empty() == false)
1380 Writeable = access(flNotFile(SrcCacheFile).c_str(),W_OK) == 0;
c8e572e3
MV
1381 if (Debug == true)
1382 std::clog << "Do we have write-access to the cache files? " << (Writeable ? "YES" : "NO") << std::endl;
1383
b2e465d6
AL
1384 if (Writeable == false && AllowMem == false && CacheFile.empty() == false)
1385 return _error->Error(_("Unable to write to %s"),flNotFile(CacheFile).c_str());
2e5f4e45
DK
1386
1387 if (Progress != NULL)
1388 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1389
b2e465d6 1390 // Cache is OK, Fin.
2ec858bc 1391 if (CheckValidity(CacheFile, List, Files.begin(),Files.end(),OutMap) == true)
b2e465d6 1392 {
2e5f4e45
DK
1393 if (Progress != NULL)
1394 Progress->OverallProgress(1,1,1,_("Reading package lists"));
c8e572e3
MV
1395 if (Debug == true)
1396 std::clog << "pkgcache.bin is valid - no need to build anything" << std::endl;
b2e465d6
AL
1397 return true;
1398 }
c8e572e3
MV
1399 else if (Debug == true)
1400 std::clog << "pkgcache.bin is NOT valid" << std::endl;
b2e465d6
AL
1401
1402 /* At this point we know we need to reconstruct the package cache,
1403 begin. */
1404 SPtr<FileFd> CacheF;
1405 SPtr<DynamicMMap> Map;
1406 if (Writeable == true && CacheFile.empty() == false)
1407 {
41b4dee4 1408 _error->PushToStack();
b2e465d6 1409 unlink(CacheFile.c_str());
22041bd2 1410 CacheF = new FileFd(CacheFile,FileFd::WriteAtomic);
7a3c2ab0 1411 fchmod(CacheF->Fd(),0644);
dcdf1ef1 1412 Map = CreateDynamicMMap(CacheF, MMap::Public);
b35d2f5f 1413 if (_error->PendingError() == true)
41b4dee4
DK
1414 {
1415 delete CacheF.UnGuard();
1416 delete Map.UnGuard();
1417 if (Debug == true)
1418 std::clog << "Open filebased MMap FAILED" << std::endl;
1419 Writeable = false;
1420 if (AllowMem == false)
1421 {
1422 _error->MergeWithStack();
1423 return false;
1424 }
1425 _error->RevertToStack();
1426 }
0952aee6 1427 else
41b4dee4
DK
1428 {
1429 _error->MergeWithStack();
0952aee6
DH
1430 if (Debug == true)
1431 std::clog << "Open filebased MMap" << std::endl;
41b4dee4 1432 }
b35d2f5f 1433 }
41b4dee4 1434 if (Writeable == false || CacheFile.empty() == true)
8ce4327b 1435 {
b2e465d6 1436 // Just build it in memory..
dcdf1ef1 1437 Map = CreateDynamicMMap(NULL);
c8e572e3
MV
1438 if (Debug == true)
1439 std::clog << "Open memory Map (not filebased)" << std::endl;
8ce4327b 1440 }
b35d2f5f 1441
b2e465d6 1442 // Lets try the source cache.
4ad8619b
DK
1443 map_filesize_t CurrentSize = 0;
1444 map_filesize_t TotalSize = 0;
2ec858bc 1445 if (CheckValidity(SrcCacheFile, List, Files.begin(),
b2e465d6 1446 Files.begin()+EndOfSource) == true)
2d11135a 1447 {
c8e572e3
MV
1448 if (Debug == true)
1449 std::clog << "srcpkgcache.bin is valid - populate MMap with it." << std::endl;
b2e465d6
AL
1450 // Preload the map with the source cache
1451 FileFd SCacheF(SrcCacheFile,FileFd::ReadOnly);
4ad8619b 1452 map_pointer_t const alloc = Map->RawAllocate(SCacheF.Size());
eb162ff7
DK
1453 if ((alloc == 0 && _error->PendingError())
1454 || SCacheF.Read((unsigned char *)Map->Data() + alloc,
1455 SCacheF.Size()) == false)
b2e465d6
AL
1456 return false;
1457
1458 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
c8e572e3 1459
b2e465d6 1460 // Build the status cache
2e5f4e45 1461 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1462 if (_error->PendingError() == true)
b2e465d6
AL
1463 return false;
1464 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1465 Files.begin()+EndOfSource,Files.end()) == false)
1466 return false;
1467 }
1468 else
2d11135a 1469 {
c8e572e3
MV
1470 if (Debug == true)
1471 std::clog << "srcpkgcache.bin is NOT valid - rebuild" << std::endl;
b2e465d6 1472 TotalSize = ComputeSize(Files.begin(),Files.end());
2d11135a 1473
b2e465d6 1474 // Build the source cache
2e5f4e45 1475 pkgCacheGenerator Gen(Map.Get(),Progress);
b2e465d6
AL
1476 if (_error->PendingError() == true)
1477 return false;
1478 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1479 Files.begin(),Files.begin()+EndOfSource) == false)
1480 return false;
2d11135a 1481
b2e465d6
AL
1482 // Write it back
1483 if (Writeable == true && SrcCacheFile.empty() == false)
2d11135a 1484 {
22041bd2 1485 FileFd SCacheF(SrcCacheFile,FileFd::WriteAtomic);
b2e465d6
AL
1486 if (_error->PendingError() == true)
1487 return false;
7a3c2ab0
AL
1488
1489 fchmod(SCacheF.Fd(),0644);
1490
b2e465d6
AL
1491 // Write out the main data
1492 if (SCacheF.Write(Map->Data(),Map->Size()) == false)
1493 return _error->Error(_("IO Error saving source cache"));
1494 SCacheF.Sync();
1495
1496 // Write out the proper header
1497 Gen.GetCache().HeaderP->Dirty = false;
1498 if (SCacheF.Seek(0) == false ||
1499 SCacheF.Write(Map->Data(),sizeof(*Gen.GetCache().HeaderP)) == false)
1500 return _error->Error(_("IO Error saving source cache"));
b2e465d6 1501 Gen.GetCache().HeaderP->Dirty = true;
7a3c2ab0 1502 SCacheF.Sync();
2d11135a
AL
1503 }
1504
b2e465d6
AL
1505 // Build the status cache
1506 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1507 Files.begin()+EndOfSource,Files.end()) == false)
1508 return false;
2d11135a 1509 }
c8e572e3
MV
1510 if (Debug == true)
1511 std::clog << "Caches are ready for shipping" << std::endl;
2d11135a 1512
b2e465d6
AL
1513 if (_error->PendingError() == true)
1514 return false;
1515 if (OutMap != 0)
2d11135a 1516 {
b2e465d6 1517 if (CacheF != 0)
2d11135a 1518 {
b2e465d6 1519 delete Map.UnGuard();
eb162ff7 1520 *OutMap = new MMap(*CacheF,0);
2d11135a 1521 }
b2e465d6
AL
1522 else
1523 {
1524 *OutMap = Map.UnGuard();
1525 }
2d11135a
AL
1526 }
1527
b2e465d6
AL
1528 return true;
1529}
1530 /*}}}*/
2e5f4e45 1531// CacheGenerator::MakeOnlyStatusCache - Build only a status files cache/*{{{*/
b2e465d6
AL
1532// ---------------------------------------------------------------------
1533/* */
453b82a3 1534APT_DEPRECATED bool pkgMakeOnlyStatusCache(OpProgress &Progress,DynamicMMap **OutMap)
2e5f4e45
DK
1535 { return pkgCacheGenerator::MakeOnlyStatusCache(&Progress, OutMap); }
1536bool pkgCacheGenerator::MakeOnlyStatusCache(OpProgress *Progress,DynamicMMap **OutMap)
b2e465d6 1537{
73688d27 1538 std::vector<pkgIndexFile *> Files;
4ad8619b 1539 map_filesize_t EndOfSource = Files.size();
b2e465d6
AL
1540 if (_system->AddStatusFiles(Files) == false)
1541 return false;
dcdf1ef1
DK
1542
1543 SPtr<DynamicMMap> Map = CreateDynamicMMap(NULL);
4ad8619b
DK
1544 map_filesize_t CurrentSize = 0;
1545 map_filesize_t TotalSize = 0;
b2e465d6
AL
1546
1547 TotalSize = ComputeSize(Files.begin()+EndOfSource,Files.end());
1548
1549 // Build the status cache
2e5f4e45
DK
1550 if (Progress != NULL)
1551 Progress->OverallProgress(0,1,1,_("Reading package lists"));
1552 pkgCacheGenerator Gen(Map.Get(),Progress);
2d11135a 1553 if (_error->PendingError() == true)
b2e465d6
AL
1554 return false;
1555 if (BuildCache(Gen,Progress,CurrentSize,TotalSize,
1556 Files.begin()+EndOfSource,Files.end()) == false)
1557 return false;
25396fb0 1558
b2e465d6
AL
1559 if (_error->PendingError() == true)
1560 return false;
1561 *OutMap = Map.UnGuard();
2d11135a 1562
b2e465d6 1563 return true;
2d11135a
AL
1564}
1565 /*}}}*/
5f4db009 1566// IsDuplicateDescription /*{{{*/
60683765 1567static bool IsDuplicateDescription(pkgCache::DescIterator Desc,
5f4db009
DK
1568 MD5SumValue const &CurMd5, std::string const &CurLang)
1569{
22f07fc5 1570 // Descriptions in the same link-list have all the same md5
7f5aab82 1571 if (Desc.end() == true || MD5SumValue(Desc.md5()) != CurMd5)
22f07fc5
DK
1572 return false;
1573 for (; Desc.end() == false; ++Desc)
1574 if (Desc.LanguageCode() == CurLang)
5f4db009
DK
1575 return true;
1576 return false;
1577}
1578 /*}}}*/
5a8e963b 1579// CacheGenerator::FinishCache /*{{{*/
65512241 1580bool pkgCacheGenerator::FinishCache(OpProgress * /*Progress*/)
5a8e963b
DK
1581{
1582 return true;
1583}
1584 /*}}}*/