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