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