]> git.saurik.com Git - apt.git/blob - apt-pkg/pkgcachegen.cc
aac3f77d9596299cc074db051daa2e898d28c927
[apt.git] / apt-pkg / pkgcachegen.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: pkgcachegen.cc,v 1.7 1998/07/07 04:17:04 jgg Exp $
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 /*{{{*/
13 #ifdef __GNUG__
14 #pragma implementation "pkglib/pkgcachegen.h"
15 #endif
16
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 */
28 pkgCacheGenerator::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 */
47 pkgCacheGenerator::~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. */
62 bool pkgCacheGenerator::MergeList(ListParser &List)
63 {
64 List.Owner = this;
65
66 while (List.Step() == true)
67 {
68 // Get a pointer to the package structure
69 string PackageName = List.Package();
70 pkgCache::PkgIterator Pkg;
71 Cache.FindPkg(PackageName);
72 if (Pkg.end() == true)
73 {
74 if (NewPackage(Pkg,PackageName) == false)
75 return false;
76 }
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();
82 if (Version.empty() == true)
83 {
84 if (List.UsePackage(Pkg,pkgCache::VerIterator(Cache)) == false)
85 return false;
86 continue;
87 }
88
89 pkgCache::VerIterator Ver = Pkg.VersionList();
90 unsigned long *Last = &Pkg->VersionList;
91 int Res = 1;
92 for (; Ver.end() == false; Last = &Ver->NextVer, Ver++)
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 {
104 if (List.UsePackage(Pkg,Ver) == false)
105 return false;
106
107 if (NewFileVer(Ver,List) == false)
108 return false;
109
110 continue;
111 }
112
113 // Add a new version
114 *Last = NewVersion(Ver,Version,*Last);
115 Ver->ParentPkg = Pkg.Index();
116 if (List.NewVersion(Ver) == false)
117 return false;
118
119 if (List.UsePackage(Pkg,Ver) == false)
120 return false;
121
122 if (NewFileVer(Ver,List) == false)
123 return false;
124 }
125
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 */
132 bool pkgCacheGenerator::NewPackage(pkgCache::PkgIterator &Pkg,string Name)
133 {
134 // Get a structure
135 unsigned long Package = Map.Allocate(sizeof(pkgCache::Package));
136 if (Package == 0)
137 return false;
138
139 Pkg = pkgCache::PkgIterator(Cache,Cache.PkgP + Package);
140
141 // Insert it into the hash table
142 unsigned long Hash = Cache.Hash(Name);
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 /* */
158 bool pkgCacheGenerator::NewFileVer(pkgCache::VerIterator &Ver,
159 ListParser &List)
160 {
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
173 return true;
174 }
175 /*}}}*/
176 // CacheGenerator::NewVersion - Create a new Version /*{{{*/
177 // ---------------------------------------------------------------------
178 /* This puts a version structure in the linked list */
179 unsigned long pkgCacheGenerator::NewVersion(pkgCache::VerIterator &Ver,
180 string VerStr,
181 unsigned long Next)
182 {
183 // Get a structure
184 unsigned long Version = Map.Allocate(sizeof(pkgCache::Version));
185 if (Version == 0)
186 return 0;
187
188 // Fill it in
189 Ver = pkgCache::VerIterator(Cache,Cache.VerP + Version);
190 Ver->NextVer = Next;
191 Ver->ID = Cache.HeaderP->VersionCount++;
192 Ver->VerStr = Map.WriteString(VerStr);
193 if (Ver->VerStr == 0)
194 return 0;
195
196 return Version;
197 }
198 /*}}}*/
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. */
203 bool pkgCacheGenerator::ListParser::NewDepends(pkgCache::VerIterator Ver,
204 string PackageName,
205 string Version,
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
224 pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
225 if (Pkg.end() == true)
226 if (Owner->NewPackage(Pkg,PackageName) == false)
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 /* */
258 bool pkgCacheGenerator::ListParser::NewProvides(pkgCache::VerIterator Ver,
259 string PackageName,
260 string Version)
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
278 pkgCache::PkgIterator Pkg = Cache.FindPkg(PackageName);
279 if (Pkg.end() == true)
280 if (Owner->NewPackage(Pkg,PackageName) == false)
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 /*}}}*/
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. */
295 bool 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 /*}}}*/
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 */
322 unsigned 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)
341 return I->String;
342
343 // Get a structure
344 unsigned long Item = Map.Allocate(sizeof(pkgCache::StringItem));
345 if (Item == 0)
346 return 0;
347
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)
354 return 0;
355
356 return ItemP->String;
357 }
358 /*}}}*/