More MD5
[ntk/apt.git] / apt-pkg / pkgcachegen.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
67db871e 3// $Id: pkgcachegen.cc,v 1.42 1999/10/29 04:49:37 jgg 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 /*{{{*/
6c139d6e 13#ifdef __GNUG__
094a497d 14#pragma implementation "apt-pkg/pkgcachegen.h"
6c139d6e
AL
15#endif
16
094a497d
AL
17#include <apt-pkg/pkgcachegen.h>
18#include <apt-pkg/error.h>
19#include <apt-pkg/version.h>
b35d2f5f
AL
20#include <apt-pkg/progress.h>
21#include <apt-pkg/sourcelist.h>
22#include <apt-pkg/configuration.h>
23#include <apt-pkg/deblistparser.h>
cdcc6d34 24#include <apt-pkg/strutl.h>
f9eec0e7 25#include <system.h>
578bfd0a
AL
26
27#include <sys/stat.h>
28#include <unistd.h>
803fafcb 29#include <errno.h>
578bfd0a
AL
30 /*}}}*/
31
32// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
33// ---------------------------------------------------------------------
34/* We set the diry flag and make sure that is written to the disk */
404ec98e 35pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map,OpProgress &Prog) :
ddc1d8d0 36 Map(Map), Cache(Map), Progress(&Prog)
578bfd0a 37{
ddc1d8d0
AL
38 CurrentFile = 0;
39
578bfd0a
AL
40 if (_error->PendingError() == true)
41 return;
42
43 if (Map.Size() == 0)
44 {
45 Map.RawAllocate(sizeof(pkgCache::Header));
46 *Cache.HeaderP = pkgCache::Header();
47 }
48 Cache.HeaderP->Dirty = true;
49 Map.Sync(0,sizeof(pkgCache::Header));
50 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
f9eec0e7 51 memset(UniqHash,0,sizeof(UniqHash));
578bfd0a
AL
52}
53 /*}}}*/
54// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
55// ---------------------------------------------------------------------
56/* We sync the data then unset the dirty flag in two steps so as to
57 advoid a problem during a crash */
58pkgCacheGenerator::~pkgCacheGenerator()
59{
60 if (_error->PendingError() == true)
61 return;
62 if (Map.Sync() == false)
63 return;
64
65 Cache.HeaderP->Dirty = false;
66 Map.Sync(0,sizeof(pkgCache::Header));
67}
68 /*}}}*/
69// CacheGenerator::MergeList - Merge the package list /*{{{*/
70// ---------------------------------------------------------------------
71/* This provides the generation of the entries in the cache. Each loop
72 goes through a single package record from the underlying parse engine. */
ddc1d8d0
AL
73bool pkgCacheGenerator::MergeList(ListParser &List,
74 pkgCache::VerIterator *OutVer)
578bfd0a
AL
75{
76 List.Owner = this;
0149949b 77
f9eec0e7 78 unsigned int Counter = 0;
0149949b 79 while (List.Step() == true)
578bfd0a
AL
80 {
81 // Get a pointer to the package structure
9ddf7030 82 string PackageName = List.Package();
65a1e968
AL
83 if (PackageName.empty() == true)
84 return false;
85
9ddf7030 86 pkgCache::PkgIterator Pkg;
8efa2a3b 87 if (NewPackage(Pkg,PackageName) == false)
b35d2f5f 88 return _error->Error("Error occured while processing %s (NewPackage)",PackageName.c_str());
a246f2dc 89 Counter++;
ddc1d8d0
AL
90 if (Counter % 100 == 0 && Progress != 0)
91 Progress->Progress(List.Offset());
8ce4327b 92
578bfd0a
AL
93 /* Get a pointer to the version structure. We know the list is sorted
94 so we use that fact in the search. Insertion of new versions is
95 done with correct sorting */
96 string Version = List.Version();
f55a958f
AL
97 if (Version.empty() == true)
98 {
99 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
b35d2f5f 100 return _error->Error("Error occured while processing %s (UsePackage1)",PackageName.c_str());
f55a958f
AL
101 continue;
102 }
103
578bfd0a 104 pkgCache::VerIterator Ver = Pkg.VersionList();
349cd3b8 105 map_ptrloc *Last = &Pkg->VersionList;
2246928b 106 int Res = 1;
f55a958f 107 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
578bfd0a
AL
108 {
109 Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
110 Ver.VerStr() + strlen(Ver.VerStr()));
111 if (Res >= 0)
112 break;
113 }
114
115 /* We already have a version for this item, record that we
116 saw it */
204fbdcc
AL
117 unsigned long Hash = List.VersionHash();
118 if (Res == 0 && Ver->Hash == Hash)
578bfd0a 119 {
f55a958f 120 if (List.UsePackage(Pkg,Ver) == false)
b35d2f5f 121 return _error->Error("Error occured while processing %s (UsePackage2)",PackageName.c_str());
f78439bf 122
578bfd0a 123 if (NewFileVer(Ver,List) == false)
b35d2f5f 124 return _error->Error("Error occured while processing %s (NewFileVer1)",PackageName.c_str());
578bfd0a 125
ddc1d8d0
AL
126 // Read only a single record and return
127 if (OutVer != 0)
128 {
129 *OutVer = Ver;
130 return true;
131 }
132
578bfd0a
AL
133 continue;
134 }
135
204fbdcc
AL
136 // Skip to the end of the same version set.
137 if (Res == 0)
138 {
139 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
140 {
141 Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
142 Ver.VerStr() + strlen(Ver.VerStr()));
143 if (Res != 0)
144 break;
145 }
146 }
147
578bfd0a 148 // Add a new version
f55a958f
AL
149 *Last = NewVersion(Ver,Version,*Last);
150 Ver->ParentPkg = Pkg.Index();
204fbdcc 151 Ver->Hash = Hash;
578bfd0a 152 if (List.NewVersion(Ver) == false)
b35d2f5f 153 return _error->Error("Error occured while processing %s (NewVersion1)",PackageName.c_str());
0149949b 154
f55a958f 155 if (List.UsePackage(Pkg,Ver) == false)
b35d2f5f 156 return _error->Error("Error occured while processing %s (UsePackage3)",PackageName.c_str());
f55a958f 157
578bfd0a 158 if (NewFileVer(Ver,List) == false)
b35d2f5f 159 return _error->Error("Error occured while processing %s (NewVersion2)",PackageName.c_str());
ddc1d8d0
AL
160
161 // Read only a single record and return
162 if (OutVer != 0)
163 {
164 *OutVer = Ver;
165 return true;
166 }
578bfd0a 167 }
0149949b 168
578bfd0a
AL
169 return true;
170}
171 /*}}}*/
172// CacheGenerator::NewPackage - Add a new package /*{{{*/
173// ---------------------------------------------------------------------
174/* This creates a new package structure and adds it to the hash table */
f55a958f 175bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
578bfd0a 176{
8efa2a3b
AL
177 Pkg = Cache.FindPkg(Name);
178 if (Pkg.end() == false)
179 return true;
180
578bfd0a
AL
181 // Get a structure
182 unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
183 if (Package == 0)
184 return false;
185
f55a958f 186 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
578bfd0a
AL
187
188 // Insert it into the hash table
f55a958f 189 unsigned long Hash = Cache.Hash(Name);
578bfd0a
AL
190 Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
191 Cache.HeaderP->HashTable[Hash] = Package;
192
193 // Set the name and the ID
194 Pkg->Name = Map.WriteString(Name);
195 if (Pkg->Name == 0)
196 return false;
197 Pkg->ID = Cache.HeaderP->PackageCount++;
198
199 return true;
200}
201 /*}}}*/
202// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
203// ---------------------------------------------------------------------
204/* */
f55a958f 205bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
578bfd0a
AL
206 ListParser &List)
207{
ddc1d8d0
AL
208 if (CurrentFile == 0)
209 return true;
210
dcb79bae
AL
211 // Get a structure
212 unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
213 if (VerFile == 0)
214 return 0;
215
216 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
217 VF->File = CurrentFile - Cache.PkgFileP;
03e39e59
AL
218
219 // Link it to the end of the list
349cd3b8 220 map_ptrloc *Last = &Ver->FileList;
03e39e59
AL
221 for (pkgCache::VerFileIterator V = Ver.FileList(); V.end() == false; V++)
222 Last = &V->NextFile;
223 VF->NextFile = *Last;
224 *Last = VF.Index();
225
dcb79bae
AL
226 VF->Offset = List.Offset();
227 VF->Size = List.Size();
ad00ae81
AL
228 if (Cache.HeaderP->MaxVerFileSize < VF->Size)
229 Cache.HeaderP->MaxVerFileSize = VF->Size;
a7e66b17
AL
230 Cache.HeaderP->VerFileCount++;
231
f55a958f 232 return true;
578bfd0a
AL
233}
234 /*}}}*/
235// CacheGenerator::NewVersion - Create a new Version /*{{{*/
236// ---------------------------------------------------------------------
f55a958f 237/* This puts a version structure in the linked list */
578bfd0a 238unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
f55a958f 239 string VerStr,
578bfd0a
AL
240 unsigned long Next)
241{
f55a958f
AL
242 // Get a structure
243 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
244 if (Version == 0)
0149949b 245 return 0;
f55a958f
AL
246
247 // Fill it in
248 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
f55a958f
AL
249 Ver->NextVer = Next;
250 Ver->ID = Cache.HeaderP->VersionCount++;
251 Ver->VerStr = Map.WriteString(VerStr);
252 if (Ver->VerStr == 0)
0149949b 253 return 0;
f55a958f 254
0149949b 255 return Version;
578bfd0a
AL
256}
257 /*}}}*/
dcb79bae
AL
258// ListParser::NewDepends - Create a dependency element /*{{{*/
259// ---------------------------------------------------------------------
260/* This creates a dependency element in the tree. It is linked to the
261 version and to the package that it is pointing to. */
262bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
9ddf7030
AL
263 string PackageName,
264 string Version,
dcb79bae
AL
265 unsigned int Op,
266 unsigned int Type)
267{
268 pkgCache &Cache = Owner->Cache;
269
270 // Get a structure
271 unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
272 if (Dependency == 0)
273 return false;
274
275 // Fill it in
276 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
277 Dep->ParentVer = Ver.Index();
278 Dep->Type = Type;
279 Dep->CompareOp = Op;
280 Dep->ID = Cache.HeaderP->DependsCount++;
281
282 // Locate the target package
8efa2a3b
AL
283 pkgCache::PkgIterator Pkg;
284 if (Owner->NewPackage(Pkg,PackageName) == false)
285 return false;
dcb79bae
AL
286
287 // Probe the reverse dependency list for a version string that matches
288 if (Version.empty() == false)
289 {
f9eec0e7 290/* for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++, Hit++)
dcb79bae 291 if (I->Version != 0 && I.TargetVer() == Version)
f9eec0e7 292 Dep->Version = I->Version;*/
dcb79bae
AL
293 if (Dep->Version == 0)
294 if ((Dep->Version = WriteString(Version)) == 0)
295 return false;
296 }
c1a22377 297
dcb79bae
AL
298 // Link it to the package
299 Dep->Package = Pkg.Index();
300 Dep->NextRevDepends = Pkg->RevDepends;
301 Pkg->RevDepends = Dep.Index();
302
c1a22377
AL
303 /* Link it to the version (at the end of the list)
304 Caching the old end point speeds up generation substantially */
f9eec0e7 305 if (OldDepVer != Ver)
c1a22377 306 {
f9eec0e7 307 OldDepLast = &Ver->DependsList;
c1a22377 308 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
f9eec0e7
AL
309 OldDepLast = &D->NextDepends;
310 OldDepVer = Ver;
c1a22377 311 }
dcb79bae 312
f9eec0e7
AL
313 Dep->NextDepends = *OldDepLast;
314 *OldDepLast = Dep.Index();
315 OldDepLast = &Dep->NextDepends;
c1a22377 316
dcb79bae
AL
317 return true;
318}
319 /*}}}*/
320// ListParser::NewProvides - Create a Provides element /*{{{*/
321// ---------------------------------------------------------------------
322/* */
323bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
8efa2a3b 324 string PackageName,
9ddf7030 325 string Version)
dcb79bae
AL
326{
327 pkgCache &Cache = Owner->Cache;
8efa2a3b
AL
328
329 // We do not add self referencing provides
330 if (Ver.ParentPkg().Name() == PackageName)
331 return true;
dcb79bae
AL
332
333 // Get a structure
334 unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
335 if (Provides == 0)
336 return false;
a7e66b17 337 Cache.HeaderP->ProvidesCount++;
dcb79bae
AL
338
339 // Fill it in
340 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
341 Prv->Version = Ver.Index();
342 Prv->NextPkgProv = Ver->ProvidesList;
343 Ver->ProvidesList = Prv.Index();
344 if (Version.empty() == false && (Prv->Version = WriteString(Version)) == 0)
345 return false;
346
347 // Locate the target package
8efa2a3b
AL
348 pkgCache::PkgIterator Pkg;
349 if (Owner->NewPackage(Pkg,PackageName) == false)
350 return false;
dcb79bae
AL
351
352 // Link it to the package
353 Prv->ParentPkg = Pkg.Index();
354 Prv->NextProvides = Pkg->ProvidesList;
355 Pkg->ProvidesList = Prv.Index();
356
357 return true;
358}
359 /*}}}*/
578bfd0a
AL
360// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
361// ---------------------------------------------------------------------
362/* This is used to select which file is to be associated with all newly
363 added versions. */
364bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
365{
366 struct stat Buf;
367 if (stat(File.c_str(),&Buf) == -1)
368 return _error->Errno("stat","Couldn't stat ",File.c_str());
369
370 // Get some space for the structure
371 CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
372 if (CurrentFile == Cache.PkgFileP)
373 return false;
374
375 // Fill it in
376 CurrentFile->FileName = Map.WriteString(File);
377 CurrentFile->Size = Buf.st_size;
378 CurrentFile->mtime = Buf.st_mtime;
379 CurrentFile->NextFile = Cache.HeaderP->FileList;
380 CurrentFile->Flags = Flags;
e1b74f61 381 CurrentFile->ID = Cache.HeaderP->PackageFileCount;
578bfd0a 382 PkgFileName = File;
ad00ae81 383 Cache.HeaderP->FileList = CurrentFile - Cache.PkgFileP;
b35d2f5f
AL
384 Cache.HeaderP->PackageFileCount++;
385
578bfd0a
AL
386 if (CurrentFile->FileName == 0)
387 return false;
404ec98e 388
ddc1d8d0
AL
389 if (Progress != 0)
390 Progress->SubProgress(Buf.st_size);
8efa2a3b 391 return true;
578bfd0a
AL
392}
393 /*}}}*/
f55a958f
AL
394// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
395// ---------------------------------------------------------------------
396/* This is used to create handles to strings. Given the same text it
397 always returns the same number */
398unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
399 unsigned int Size)
400{
f9eec0e7
AL
401 /* We use a very small transient hash table here, this speeds up generation
402 by a fair amount on slower machines */
403 pkgCache::StringItem *&Bucket = UniqHash[(S[0]*5 + S[1]) % _count(UniqHash)];
404 if (Bucket != 0 &&
405 stringcmp(S,S+Size,Cache.StrP + Bucket->String) == 0)
406 return Bucket->String;
407
f55a958f
AL
408 // Search for an insertion point
409 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
410 int Res = 1;
349cd3b8 411 map_ptrloc *Last = &Cache.HeaderP->StringList;
f55a958f
AL
412 for (; I != Cache.StringItemP; Last = &I->NextItem,
413 I = Cache.StringItemP + I->NextItem)
414 {
9c14e3d6 415 Res = stringcmp(S,S+Size,Cache.StrP + I->String);
f55a958f
AL
416 if (Res >= 0)
417 break;
418 }
419
420 // Match
421 if (Res == 0)
f9eec0e7
AL
422 {
423 Bucket = I;
0149949b 424 return I->String;
f9eec0e7 425 }
f55a958f
AL
426
427 // Get a structure
428 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
429 if (Item == 0)
0149949b
AL
430 return 0;
431
f55a958f
AL
432 // Fill in the structure
433 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
434 ItemP->NextItem = I - Cache.StringItemP;
435 *Last = Item;
436 ItemP->String = Map.WriteString(S,Size);
437 if (ItemP->String == 0)
0149949b 438 return 0;
f55a958f 439
f9eec0e7 440 Bucket = ItemP;
0149949b 441 return ItemP->String;
f55a958f
AL
442}
443 /*}}}*/
b35d2f5f
AL
444
445// SrcCacheCheck - Check if the source package cache is uptodate /*{{{*/
446// ---------------------------------------------------------------------
447/* The source cache is checked against the source list and the files
448 on disk, any difference results in a false. */
449bool pkgSrcCacheCheck(pkgSourceList &List)
450{
451 if (_error->PendingError() == true)
452 return false;
e1b74f61 453
3b5421b4 454 string CacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
0919e3f9 455 string ListDir = _config->FindDir("Dir::State::lists");
e1b74f61
AL
456
457 // Count the number of missing files
458 int Missing = 0;
459 for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
460 {
be8922fd
AL
461 // Only cache deb source types.
462 if (I->Type != pkgSourceList::Item::Deb)
6f86c974
AL
463 {
464 Missing++;
be8922fd 465 continue;
6f86c974 466 }
be8922fd 467
e1b74f61
AL
468 string File = ListDir + URItoFileName(I->PackagesURI());
469 struct stat Buf;
470 if (stat(File.c_str(),&Buf) != 0)
471 {
472 _error->WarningE("stat","Couldn't stat source package list '%s' (%s)",
473 I->PackagesInfo().c_str(),File.c_str());
474 Missing++;
475 }
476 }
eb6a718e 477
e1b74f61 478 // Open the source package cache
b35d2f5f
AL
479 if (FileExists(CacheFile) == false)
480 return false;
481
482 FileFd CacheF(CacheFile,FileFd::ReadOnly);
483 if (_error->PendingError() == true)
484 {
485 _error->Discard();
486 return false;
487 }
488
489 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
0a8e3465 490 if (_error->PendingError() == true || Map.Size() == 0)
b35d2f5f
AL
491 {
492 _error->Discard();
493 return false;
494 }
495
496 pkgCache Cache(Map);
497 if (_error->PendingError() == true)
498 {
499 _error->Discard();
500 return false;
501 }
c5162d56 502
b35d2f5f 503 // They are certianly out of sync
c5162d56 504 if (Cache.Head().PackageFileCount != List.size() - Missing)
b35d2f5f
AL
505 return false;
506
507 for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
a339613f 508 {
b35d2f5f
AL
509 // Search for a match in the source list
510 bool Bad = true;
511 for (pkgSourceList::const_iterator I = List.begin();
512 I != List.end(); I++)
513 {
a339613f
AL
514 // Only cache deb source types.
515 if (I->Type != pkgSourceList::Item::Deb)
516 continue;
517
b35d2f5f
AL
518 string File = ListDir + URItoFileName(I->PackagesURI());
519 if (F.FileName() == File)
520 {
521 Bad = false;
522 break;
523 }
524 }
525
526 // Check if the file matches what was cached
527 Bad |= !F.IsOk();
528 if (Bad == true)
529 return false;
530 }
531
532 return true;
533}
534 /*}}}*/
535// PkgCacheCheck - Check if the package cache is uptodate /*{{{*/
536// ---------------------------------------------------------------------
537/* This does a simple check of all files used to compose the cache */
538bool pkgPkgCacheCheck(string CacheFile)
539{
540 if (_error->PendingError() == true)
541 return false;
542
543 // Open the source package cache
544 if (FileExists(CacheFile) == false)
545 return false;
546
547 FileFd CacheF(CacheFile,FileFd::ReadOnly);
548 if (_error->PendingError() == true)
549 {
550 _error->Discard();
551 return false;
552 }
553
554 MMap Map(CacheF,MMap::Public | MMap::ReadOnly);
0a8e3465 555 if (_error->PendingError() == true || Map.Size() == 0)
b35d2f5f
AL
556 {
557 _error->Discard();
558 return false;
559 }
560
561 pkgCache Cache(Map);
562 if (_error->PendingError() == true)
563 {
564 _error->Discard();
565 return false;
566 }
567
0118833a
AL
568 // Status files that must be in the cache
569 string Status[3];
3b5421b4
AL
570 Status[0] = _config->FindFile("Dir::State::xstatus");
571 Status[1]= _config->FindFile("Dir::State::userstatus");
572 Status[2] = _config->FindFile("Dir::State::status");
0118833a 573
b35d2f5f
AL
574 // Cheack each file
575 for (pkgCache::PkgFileIterator F(Cache); F.end() == false; F++)
0118833a 576 {
b35d2f5f
AL
577 if (F.IsOk() == false)
578 return false;
0118833a
AL
579
580 // See if this is one of the status files
581 for (int I = 0; I != 3; I++)
582 if (F.FileName() == Status[I])
583 Status[I] = string();
584 }
585
586 // Make sure all the status files are loaded.
587 for (int I = 0; I != 3; I++)
588 {
589 if (Status[I].empty() == false && FileExists(Status[I]) == true)
590 return false;
591 }
592
b35d2f5f
AL
593 return true;
594}
595 /*}}}*/
ddc1d8d0 596// AddStatusSize - Add the size of the status files /*{{{*/
b35d2f5f
AL
597// ---------------------------------------------------------------------
598/* This adds the size of all the status files to the size counter */
ddc1d8d0 599bool pkgAddStatusSize(unsigned long &TotalSize)
b35d2f5f
AL
600{
601 // Grab the file names
3b5421b4
AL
602 string xstatus = _config->FindFile("Dir::State::xstatus");
603 string userstatus = _config->FindFile("Dir::State::userstatus");
604 string status = _config->FindFile("Dir::State::status");
b35d2f5f
AL
605
606 // Grab the sizes
607 struct stat Buf;
608 if (stat(xstatus.c_str(),&Buf) == 0)
609 TotalSize += Buf.st_size;
610 if (stat(userstatus.c_str(),&Buf) == 0)
611 TotalSize += Buf.st_size;
612 if (stat(status.c_str(),&Buf) != 0)
613 return _error->Errno("stat","Couldn't stat the status file %s",status.c_str());
614 TotalSize += Buf.st_size;
615
616 return true;
617}
618 /*}}}*/
619// MergeStatus - Add the status files to the cache /*{{{*/
620// ---------------------------------------------------------------------
621/* This adds the status files to the map */
ddc1d8d0
AL
622bool pkgMergeStatus(OpProgress &Progress,pkgCacheGenerator &Gen,
623 unsigned long &CurrentSize,unsigned long TotalSize)
b35d2f5f
AL
624{
625 // Grab the file names
626 string Status[3];
3b5421b4
AL
627 Status[0] = _config->FindFile("Dir::State::xstatus");
628 Status[1]= _config->FindFile("Dir::State::userstatus");
629 Status[2] = _config->FindFile("Dir::State::status");
b35d2f5f
AL
630
631 for (int I = 0; I != 3; I++)
632 {
633 // Check if the file exists and it is not the primary status file.
634 string File = Status[I];
635 if (I != 2 && FileExists(File) == false)
636 continue;
637
638 FileFd Pkg(File,FileFd::ReadOnly);
639 debListParser Parser(Pkg);
8ce4327b 640 Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists");
b35d2f5f
AL
641 if (_error->PendingError() == true)
642 return _error->Error("Problem opening %s",File.c_str());
643 CurrentSize += Pkg.Size();
8ce4327b
AL
644
645 Progress.SubProgress(0,"Local Package State - " + flNotDir(File));
b35d2f5f
AL
646 if (Gen.SelectFile(File,pkgCache::Flag::NotSource) == false)
647 return _error->Error("Problem with SelectFile %s",File.c_str());
648
649 if (Gen.MergeList(Parser) == false)
650 return _error->Error("Problem with MergeList %s",File.c_str());
8ce4327b 651 Progress.Progress(Pkg.Size());
b35d2f5f
AL
652 }
653
2d11135a
AL
654 return true;
655}
656 /*}}}*/
657// GenerateSrcCache - Write the source package lists to the map /*{{{*/
658// ---------------------------------------------------------------------
659/* This puts the source package cache into the given generator. */
660bool pkgGenerateSrcCache(pkgSourceList &List,OpProgress &Progress,
661 pkgCacheGenerator &Gen,
b80d5b89 662 unsigned long &CurrentSize,unsigned long &TotalSize)
2d11135a
AL
663{
664 string ListDir = _config->FindDir("Dir::State::lists");
665
666 // Prepare the progress indicator
667 TotalSize = 0;
668 struct stat Buf;
669 for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
670 {
671 string File = ListDir + URItoFileName(I->PackagesURI());
672 if (stat(File.c_str(),&Buf) != 0)
673 continue;
674 TotalSize += Buf.st_size;
675 }
676
ddc1d8d0 677 if (pkgAddStatusSize(TotalSize) == false)
2d11135a
AL
678 return false;
679
680 // Generate the pkg source cache
681 CurrentSize = 0;
682 for (pkgSourceList::const_iterator I = List.begin(); I != List.end(); I++)
683 {
684 // Only cache deb source types.
685 if (I->Type != pkgSourceList::Item::Deb)
686 continue;
687
688 string File = ListDir + URItoFileName(I->PackagesURI());
689
690 if (FileExists(File) == false)
691 continue;
692
693 FileFd Pkg(File,FileFd::ReadOnly);
694 debListParser Parser(Pkg);
695 Progress.OverallProgress(CurrentSize,TotalSize,Pkg.Size(),"Reading Package Lists");
696 if (_error->PendingError() == true)
697 return _error->Error("Problem opening %s",File.c_str());
698 CurrentSize += Pkg.Size();
699
700 Progress.SubProgress(0,I->PackagesInfo());
701 if (Gen.SelectFile(File) == false)
702 return _error->Error("Problem with SelectFile %s",File.c_str());
703
704 if (Gen.MergeList(Parser) == false)
705 return _error->Error("Problem with MergeList %s",File.c_str());
706
707 // Check the release file
708 string RFile = ListDir + URItoFileName(I->ReleaseURI());
709 if (FileExists(RFile) == true)
710 {
711 FileFd Rel(RFile,FileFd::ReadOnly);
712 if (_error->PendingError() == true)
713 return false;
714 Parser.LoadReleaseInfo(Gen.GetCurFile(),Rel);
715 }
716 }
717
b35d2f5f
AL
718 return true;
719}
720 /*}}}*/
721// MakeStatusCache - Generates a cache that includes the status files /*{{{*/
722// ---------------------------------------------------------------------
723/* This copies the package source cache and then merges the status and
724 xstatus files into it. */
725bool pkgMakeStatusCache(pkgSourceList &List,OpProgress &Progress)
726{
67db871e
AL
727 unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
728
8ce4327b
AL
729 Progress.OverallProgress(0,1,1,"Reading Package Lists");
730
3b5421b4 731 string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
b35d2f5f 732 bool SrcOk = pkgSrcCacheCheck(List);
0a8e3465 733 bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
eb6a718e 734
b35d2f5f
AL
735 // Rebuild the source and package caches
736 if (SrcOk == false)
737 {
3b5421b4 738 string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
b35d2f5f
AL
739 FileFd SCacheF(SCacheFile,FileFd::WriteEmpty);
740 FileFd CacheF(CacheFile,FileFd::WriteEmpty);
67db871e 741 DynamicMMap Map(CacheF,MMap::Public,MapSize);
b35d2f5f
AL
742 if (_error->PendingError() == true)
743 return false;
2d11135a 744
b35d2f5f 745 pkgCacheGenerator Gen(Map,Progress);
2d11135a 746 unsigned long CurrentSize = 0;
b35d2f5f 747 unsigned long TotalSize = 0;
2d11135a 748 if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
b35d2f5f
AL
749 return false;
750
b35d2f5f
AL
751 // Write the src cache
752 Gen.GetCache().HeaderP->Dirty = false;
753 if (SCacheF.Write(Map.Data(),Map.Size()) == false)
754 return _error->Error("IO Error saving source cache");
755 Gen.GetCache().HeaderP->Dirty = true;
756
757 // Merge in the source caches
758 return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
759 }
760
761 if (PkgOk == true)
8ce4327b
AL
762 {
763 Progress.OverallProgress(1,1,1,"Reading Package Lists");
b35d2f5f 764 return true;
8ce4327b 765 }
b35d2f5f
AL
766
767 // We use the source cache to generate the package cache
3b5421b4 768 string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
b35d2f5f
AL
769
770 FileFd SCacheF(SCacheFile,FileFd::ReadOnly);
771 FileFd CacheF(CacheFile,FileFd::WriteEmpty);
67db871e 772 DynamicMMap Map(CacheF,MMap::Public,MapSize);
b35d2f5f
AL
773 if (_error->PendingError() == true)
774 return false;
775
776 // Preload the map with the source cache
777 if (SCacheF.Read((unsigned char *)Map.Data() + Map.RawAllocate(SCacheF.Size()),
778 SCacheF.Size()) == false)
779 return false;
780
781 pkgCacheGenerator Gen(Map,Progress);
782
783 // Compute the progress
784 unsigned long TotalSize = 0;
ddc1d8d0 785 if (pkgAddStatusSize(TotalSize) == false)
b35d2f5f
AL
786 return false;
787
788 unsigned long CurrentSize = 0;
789 return pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize);
790}
791 /*}}}*/
2d11135a
AL
792// MakeStatusCacheMem - Returns a map for the status cache /*{{{*/
793// ---------------------------------------------------------------------
794/* This creates a map object for the status cache. If the process has write
795 access to the caches then it is the same as MakeStatusCache, otherwise it
796 creates a memory block and puts the cache in there. */
797MMap *pkgMakeStatusCacheMem(pkgSourceList &List,OpProgress &Progress)
798{
67db871e
AL
799 unsigned long MapSize = _config->FindI("APT::Cache-Limit",4*1024*1024);
800
2d11135a
AL
801 /* If the cache file is writeable this is just a wrapper for
802 MakeStatusCache */
803 string CacheFile = _config->FindFile("Dir::Cache::pkgcache");
803fafcb
AL
804 bool Writeable = (access(CacheFile.c_str(),W_OK) == 0) ||
805 (errno == ENOENT);
806
2d11135a
AL
807 if (Writeable == true)
808 {
809 if (pkgMakeStatusCache(List,Progress) == false)
810 return 0;
811
812 // Open the cache file
813 FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
814 if (_error->PendingError() == true)
815 return 0;
816
817 MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
818 if (_error->PendingError() == true)
819 {
820 delete Map;
821 return 0;
822 }
823 return Map;
824 }
825
826 // Mostly from MakeStatusCache..
827 Progress.OverallProgress(0,1,1,"Reading Package Lists");
828
829 bool SrcOk = pkgSrcCacheCheck(List);
830 bool PkgOk = SrcOk && pkgPkgCacheCheck(CacheFile);
831
832 // Rebuild the source and package caches
833 if (SrcOk == false)
834 {
67db871e 835 DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize);
2d11135a
AL
836 if (_error->PendingError() == true)
837 {
838 delete Map;
839 return 0;
840 }
841
842 pkgCacheGenerator Gen(*Map,Progress);
843 unsigned long CurrentSize = 0;
844 unsigned long TotalSize = 0;
845 if (pkgGenerateSrcCache(List,Progress,Gen,CurrentSize,TotalSize) == false)
846 {
847 delete Map;
848 return 0;
849 }
850
851 // Merge in the source caches
852 if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
853 {
854 delete Map;
855 return 0;
856 }
857
858 return Map;
859 }
860
861 if (PkgOk == true)
862 {
863 Progress.OverallProgress(1,1,1,"Reading Package Lists");
864
865 // Open the cache file
866 FileFd File(_config->FindFile("Dir::Cache::pkgcache"),FileFd::ReadOnly);
867 if (_error->PendingError() == true)
868 return 0;
869
870 MMap *Map = new MMap(File,MMap::Public | MMap::ReadOnly);
871 if (_error->PendingError() == true)
872 {
873 delete Map;
874 return 0;
875 }
876 return Map;
877 }
878
879 // We use the source cache to generate the package cache
880 string SCacheFile = _config->FindFile("Dir::Cache::srcpkgcache");
881 FileFd SCacheF(SCacheFile,FileFd::ReadOnly);
67db871e 882 DynamicMMap *Map = new DynamicMMap(MMap::Public,MapSize);
2d11135a
AL
883 if (_error->PendingError() == true)
884 {
885 delete Map;
886 return 0;
887 }
888
889 // Preload the map with the source cache
890 if (SCacheF.Read((unsigned char *)Map->Data() + Map->RawAllocate(SCacheF.Size()),
891 SCacheF.Size()) == false)
892 {
893 delete Map;
894 return 0;
895 }
896
897 pkgCacheGenerator Gen(*Map,Progress);
898
899 // Compute the progress
900 unsigned long TotalSize = 0;
ddc1d8d0 901 if (pkgAddStatusSize(TotalSize) == false)
2d11135a
AL
902 {
903 delete Map;
904 return 0;
905 }
906
907 unsigned long CurrentSize = 0;
908 if (pkgMergeStatus(Progress,Gen,CurrentSize,TotalSize) == false)
909 {
910 delete Map;
911 return 0;
912 }
913
914 return Map;
915}
916 /*}}}*/