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