Sync
[ntk/apt.git] / apt-pkg / pkgcachegen.cc
CommitLineData
578bfd0a
AL
1// -*- mode: cpp; mode: fold -*-
2// Description /*{{{*/
6c139d6e 3// $Id: pkgcachegen.cc,v 1.7 1998/07/07 04:17:04 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
AL
13#ifdef __GNUG__
14#pragma implementation "pkglib/pkgcachegen.h"
15#endif
16
578bfd0a
AL
17#include <pkglib/pkgcachegen.h>
18#include <pkglib/error.h>
19#include <pkglib/version.h>
20
21#include <sys/stat.h>
22#include <unistd.h>
23 /*}}}*/
24
25// CacheGenerator::pkgCacheGenerator - Constructor /*{{{*/
26// ---------------------------------------------------------------------
27/* We set the diry flag and make sure that is written to the disk */
28pkgCacheGenerator::pkgCacheGenerator(DynamicMMap &Map) : Map(Map), Cache(Map)
29{
30 if (_error->PendingError() == true)
31 return;
32
33 if (Map.Size() == 0)
34 {
35 Map.RawAllocate(sizeof(pkgCache::Header));
36 *Cache.HeaderP = pkgCache::Header();
37 }
38 Cache.HeaderP->Dirty = true;
39 Map.Sync(0,sizeof(pkgCache::Header));
40 Map.UsePools(*Cache.HeaderP->Pools,sizeof(Cache.HeaderP->Pools)/sizeof(Cache.HeaderP->Pools[0]));
41}
42 /*}}}*/
43// CacheGenerator::~pkgCacheGenerator - Destructor /*{{{*/
44// ---------------------------------------------------------------------
45/* We sync the data then unset the dirty flag in two steps so as to
46 advoid a problem during a crash */
47pkgCacheGenerator::~pkgCacheGenerator()
48{
49 if (_error->PendingError() == true)
50 return;
51 if (Map.Sync() == false)
52 return;
53
54 Cache.HeaderP->Dirty = false;
55 Map.Sync(0,sizeof(pkgCache::Header));
56}
57 /*}}}*/
58// CacheGenerator::MergeList - Merge the package list /*{{{*/
59// ---------------------------------------------------------------------
60/* This provides the generation of the entries in the cache. Each loop
61 goes through a single package record from the underlying parse engine. */
62bool pkgCacheGenerator::MergeList(ListParser &List)
63{
64 List.Owner = this;
0149949b
AL
65
66 while (List.Step() == true)
578bfd0a
AL
67 {
68 // Get a pointer to the package structure
9ddf7030
AL
69 string PackageName = List.Package();
70 pkgCache::PkgIterator Pkg;
71 Cache.FindPkg(PackageName);
f55a958f 72 if (Pkg.end() == true)
578bfd0a 73 {
9ddf7030 74 if (NewPackage(Pkg,PackageName) == false)
578bfd0a 75 return false;
578bfd0a 76 }
578bfd0a
AL
77
78 /* Get a pointer to the version structure. We know the list is sorted
79 so we use that fact in the search. Insertion of new versions is
80 done with correct sorting */
81 string Version = List.Version();
f55a958f
AL
82 if (Version.empty() == true)
83 {
84 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
85 return false;
86 continue;
87 }
88
578bfd0a
AL
89 pkgCache::VerIterator Ver = Pkg.VersionList();
90 unsigned long *Last = &Pkg->VersionList;
2246928b 91 int Res = 1;
f55a958f 92 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
578bfd0a
AL
93 {
94 Res = pkgVersionCompare(Version.begin(),Version.end(),Ver.VerStr(),
95 Ver.VerStr() + strlen(Ver.VerStr()));
96 if (Res >= 0)
97 break;
98 }
99
100 /* We already have a version for this item, record that we
101 saw it */
102 if (Res == 0)
103 {
f55a958f
AL
104 if (List.UsePackage(Pkg,Ver) == false)
105 return false;
106
578bfd0a
AL
107 if (NewFileVer(Ver,List) == false)
108 return false;
109
110 continue;
111 }
112
113 // Add a new version
f55a958f
AL
114 *Last = NewVersion(Ver,Version,*Last);
115 Ver->ParentPkg = Pkg.Index();
578bfd0a
AL
116 if (List.NewVersion(Ver) == false)
117 return false;
0149949b 118
f55a958f
AL
119 if (List.UsePackage(Pkg,Ver) == false)
120 return false;
121
578bfd0a
AL
122 if (NewFileVer(Ver,List) == false)
123 return false;
124 }
0149949b 125
578bfd0a
AL
126 return true;
127}
128 /*}}}*/
129// CacheGenerator::NewPackage - Add a new package /*{{{*/
130// ---------------------------------------------------------------------
131/* This creates a new package structure and adds it to the hash table */
f55a958f 132bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
578bfd0a
AL
133{
134 // Get a structure
135 unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
136 if (Package == 0)
137 return false;
138
f55a958f 139 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
578bfd0a
AL
140
141 // Insert it into the hash table
f55a958f 142 unsigned long Hash = Cache.Hash(Name);
578bfd0a
AL
143 Pkg->NextPackage = Cache.HeaderP->HashTable[Hash];
144 Cache.HeaderP->HashTable[Hash] = Package;
145
146 // Set the name and the ID
147 Pkg->Name = Map.WriteString(Name);
148 if (Pkg->Name == 0)
149 return false;
150 Pkg->ID = Cache.HeaderP->PackageCount++;
151
152 return true;
153}
154 /*}}}*/
155// CacheGenerator::NewFileVer - Create a new File<->Version association /*{{{*/
156// ---------------------------------------------------------------------
157/* */
f55a958f 158bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
578bfd0a
AL
159 ListParser &List)
160{
dcb79bae
AL
161 // Get a structure
162 unsigned long VerFile = Map.Allocate(sizeof(pkgCache::VerFile));
163 if (VerFile == 0)
164 return 0;
165
166 pkgCache::VerFileIterator VF(Cache,Cache.VerFileP + VerFile);
167 VF->File = CurrentFile - Cache.PkgFileP;
168 VF->NextFile = Ver->FileList;
169 Ver->FileList = VF.Index();
170 VF->Offset = List.Offset();
171 VF->Size = List.Size();
172
f55a958f 173 return true;
578bfd0a
AL
174}
175 /*}}}*/
176// CacheGenerator::NewVersion - Create a new Version /*{{{*/
177// ---------------------------------------------------------------------
f55a958f 178/* This puts a version structure in the linked list */
578bfd0a 179unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
f55a958f 180 string VerStr,
578bfd0a
AL
181 unsigned long Next)
182{
f55a958f
AL
183 // Get a structure
184 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
185 if (Version == 0)
0149949b 186 return 0;
f55a958f
AL
187
188 // Fill it in
189 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
f55a958f
AL
190 Ver->NextVer = Next;
191 Ver->ID = Cache.HeaderP->VersionCount++;
192 Ver->VerStr = Map.WriteString(VerStr);
193 if (Ver->VerStr == 0)
0149949b 194 return 0;
f55a958f 195
0149949b 196 return Version;
578bfd0a
AL
197}
198 /*}}}*/
dcb79bae
AL
199// ListParser::NewDepends - Create a dependency element /*{{{*/
200// ---------------------------------------------------------------------
201/* This creates a dependency element in the tree. It is linked to the
202 version and to the package that it is pointing to. */
203bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
9ddf7030
AL
204 string PackageName,
205 string Version,
dcb79bae
AL
206 unsigned int Op,
207 unsigned int Type)
208{
209 pkgCache &Cache = Owner->Cache;
210
211 // Get a structure
212 unsigned long Dependency = Owner->Map.Allocate(sizeof(pkgCache::Dependency));
213 if (Dependency == 0)
214 return false;
215
216 // Fill it in
217 pkgCache::DepIterator Dep(Cache,Cache.DepP + Dependency);
218 Dep->ParentVer = Ver.Index();
219 Dep->Type = Type;
220 Dep->CompareOp = Op;
221 Dep->ID = Cache.HeaderP->DependsCount++;
222
223 // Locate the target package
9ddf7030 224 pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
dcb79bae 225 if (Pkg.end() == true)
9ddf7030 226 if (Owner->NewPackage(Pkg,PackageName) == false)
dcb79bae
AL
227 return false;
228
229 // Probe the reverse dependency list for a version string that matches
230 if (Version.empty() == false)
231 {
232 for (pkgCache::DepIterator I = Pkg.RevDependsList(); I.end() == false; I++)
233 if (I->Version != 0 && I.TargetVer() == Version)
234 Dep->Version = I->Version;
235 if (Dep->Version == 0)
236 if ((Dep->Version = WriteString(Version)) == 0)
237 return false;
238 }
239
240 // Link it to the package
241 Dep->Package = Pkg.Index();
242 Dep->NextRevDepends = Pkg->RevDepends;
243 Pkg->RevDepends = Dep.Index();
244
245 // Link it to the version (at the end of the list)
246 unsigned long *Last = &Ver->DependsList;
247 for (pkgCache::DepIterator D = Ver.DependsList(); D.end() == false; D++)
248 Last = &D->NextDepends;
249 Dep->NextDepends = *Last;
250 *Last = Dep.Index();
251
252 return true;
253}
254 /*}}}*/
255// ListParser::NewProvides - Create a Provides element /*{{{*/
256// ---------------------------------------------------------------------
257/* */
258bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
9ddf7030
AL
259 string PackageName,
260 string Version)
dcb79bae
AL
261{
262 pkgCache &Cache = Owner->Cache;
263
264 // Get a structure
265 unsigned long Provides = Owner->Map.Allocate(sizeof(pkgCache::Provides));
266 if (Provides == 0)
267 return false;
268
269 // Fill it in
270 pkgCache::PrvIterator Prv(Cache,Cache.ProvideP + Provides,Cache.PkgP);
271 Prv->Version = Ver.Index();
272 Prv->NextPkgProv = Ver->ProvidesList;
273 Ver->ProvidesList = Prv.Index();
274 if (Version.empty() == false && (Prv->Version = WriteString(Version)) == 0)
275 return false;
276
277 // Locate the target package
9ddf7030 278 pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
dcb79bae 279 if (Pkg.end() == true)
9ddf7030 280 if (Owner->NewPackage(Pkg,PackageName) == false)
dcb79bae
AL
281 return false;
282
283 // Link it to the package
284 Prv->ParentPkg = Pkg.Index();
285 Prv->NextProvides = Pkg->ProvidesList;
286 Pkg->ProvidesList = Prv.Index();
287
288 return true;
289}
290 /*}}}*/
578bfd0a
AL
291// CacheGenerator::SelectFile - Select the current file being parsed /*{{{*/
292// ---------------------------------------------------------------------
293/* This is used to select which file is to be associated with all newly
294 added versions. */
295bool pkgCacheGenerator::SelectFile(string File,unsigned long Flags)
296{
297 struct stat Buf;
298 if (stat(File.c_str(),&Buf) == -1)
299 return _error->Errno("stat","Couldn't stat ",File.c_str());
300
301 // Get some space for the structure
302 CurrentFile = Cache.PkgFileP + Map.Allocate(sizeof(*CurrentFile));
303 if (CurrentFile == Cache.PkgFileP)
304 return false;
305
306 // Fill it in
307 CurrentFile->FileName = Map.WriteString(File);
308 CurrentFile->Size = Buf.st_size;
309 CurrentFile->mtime = Buf.st_mtime;
310 CurrentFile->NextFile = Cache.HeaderP->FileList;
311 CurrentFile->Flags = Flags;
312 PkgFileName = File;
313
314 if (CurrentFile->FileName == 0)
315 return false;
316}
317 /*}}}*/
f55a958f
AL
318// CacheGenerator::WriteUniqueString - Insert a unique string /*{{{*/
319// ---------------------------------------------------------------------
320/* This is used to create handles to strings. Given the same text it
321 always returns the same number */
322unsigned long pkgCacheGenerator::WriteUniqString(const char *S,
323 unsigned int Size)
324{
325 // Search for an insertion point
326 pkgCache::StringItem *I = Cache.StringItemP + Cache.HeaderP->StringList;
327 int Res = 1;
328 unsigned long *Last = &Cache.HeaderP->StringList;
329 for (; I != Cache.StringItemP; Last = &I->NextItem,
330 I = Cache.StringItemP + I->NextItem)
331 {
332 Res = strncmp(Cache.StrP + I->String,S,Size);
333 if (Res == 0 && *(Cache.StrP + I->String + Size) != 0)
334 Res = 1;
335 if (Res >= 0)
336 break;
337 }
338
339 // Match
340 if (Res == 0)
0149949b 341 return I->String;
f55a958f
AL
342
343 // Get a structure
344 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
345 if (Item == 0)
0149949b
AL
346 return 0;
347
f55a958f
AL
348 // Fill in the structure
349 pkgCache::StringItem *ItemP = Cache.StringItemP + Item;
350 ItemP->NextItem = I - Cache.StringItemP;
351 *Last = Item;
352 ItemP->String = Map.WriteString(S,Size);
353 if (ItemP->String == 0)
0149949b 354 return 0;
f55a958f 355
0149949b 356 return ItemP->String;
f55a958f
AL
357}
358 /*}}}*/