]> git.saurik.com Git - apt.git/blob - apt-pkg/pkgcache.cc
First draft of make system and name change to apt-pkg
[apt.git] / apt-pkg / pkgcache.cc
1 // -*- mode: cpp; mode: fold -*-
2 // Description /*{{{*/
3 // $Id: pkgcache.cc,v 1.7 1998/07/12 23:58:32 jgg Exp $
4 /* ######################################################################
5
6 Package Cache - Accessor code for the cache
7
8 Please see doc/apt-pkg/cache.sgml for a more detailed description of
9 this format. Also be sure to keep that file up-to-date!!
10
11 This is the general utility functions for cache managment. They provide
12 a complete set of accessor functions for the cache. The cacheiterators
13 header contains the STL-like iterators that can be used to easially
14 navigate the cache as well as seemlessly dereference the mmap'd
15 indexes. Use these always.
16
17 The main class provides for ways to get package indexes and some
18 general lookup functions to start the iterators.
19
20 ##################################################################### */
21 /*}}}*/
22 // Include Files /*{{{*/
23 #ifdef __GNUG__
24 #pragma implementation "apt-pkg/pkgcache.h"
25 #pragma implementation "apt-pkg/cacheiterators.h"
26 #endif
27 #include <apt-pkg/pkgcache.h>
28 #include <apt-pkg/version.h>
29 #include <apt-pkg/error.h>
30 #include <system.h>
31
32 #include <string>
33 #include <sys/stat.h>
34 #include <unistd.h>
35 /*}}}*/
36
37 // Cache::Header::Header - Constructor /*{{{*/
38 // ---------------------------------------------------------------------
39 /* Simply initialize the header */
40 pkgCache::Header::Header()
41 {
42 Signature = 0x98FE76DC;
43
44 /* Whenever the structures change the major version should be bumped,
45 whenever the generator changes the minor version should be bumped. */
46 MajorVersion = 2;
47 MinorVersion = 0;
48 Dirty = true;
49
50 HeaderSz = sizeof(pkgCache::Header);
51 PackageSz = sizeof(pkgCache::Package);
52 PackageFileSz = sizeof(pkgCache::PackageFile);
53 VersionSz = sizeof(pkgCache::Version);
54 DependencySz = sizeof(pkgCache::Dependency);
55 ProvidesSz = sizeof(pkgCache::Provides);
56 VerFileSz = sizeof(pkgCache::VerFile);
57
58 PackageCount = 0;
59 VersionCount = 0;
60 DependsCount = 0;
61 PackageFileCount = 0;
62
63 FileList = 0;
64 StringList = 0;
65 memset(HashTable,0,sizeof(HashTable));
66 memset(Pools,0,sizeof(Pools));
67 }
68 /*}}}*/
69 // Cache::Header::CheckSizes - Check if the two headers have same *sz /*{{{*/
70 // ---------------------------------------------------------------------
71 /* */
72 bool pkgCache::Header::CheckSizes(Header &Against) const
73 {
74 if (HeaderSz == Against.HeaderSz &&
75 PackageSz == Against.PackageSz &&
76 PackageFileSz == Against.PackageFileSz &&
77 VersionSz == Against.VersionSz &&
78 DependencySz == Against.DependencySz &&
79 VerFileSz == Against.VerFileSz &&
80 ProvidesSz == Against.ProvidesSz)
81 return true;
82 return false;
83 }
84 /*}}}*/
85
86 // Cache::pkgCache - Constructor /*{{{*/
87 // ---------------------------------------------------------------------
88 /* */
89 pkgCache::pkgCache(MMap &Map) : Map(Map)
90 {
91 ReMap();
92 }
93 /*}}}*/
94 // Cache::ReMap - Reopen the cache file /*{{{*/
95 // ---------------------------------------------------------------------
96 /* If the file is already closed then this will open it open it. */
97 bool pkgCache::ReMap()
98 {
99 // Apply the typecasts.
100 HeaderP = (Header *)Map.Data();
101 PkgP = (Package *)Map.Data();
102 VerFileP = (VerFile *)Map.Data();
103 PkgFileP = (PackageFile *)Map.Data();
104 VerP = (Version *)Map.Data();
105 ProvideP = (Provides *)Map.Data();
106 DepP = (Dependency *)Map.Data();
107 StringItemP = (StringItem *)Map.Data();
108 StrP = (char *)Map.Data();
109
110 if (Map.Size() == 0)
111 return false;
112
113 // Check the header
114 Header DefHeader;
115 if (HeaderP->Signature != DefHeader.Signature ||
116 HeaderP->Dirty == true)
117 return _error->Error("The package cache file is corrupted");
118
119 if (HeaderP->MajorVersion != DefHeader.MajorVersion ||
120 HeaderP->MinorVersion != DefHeader.MinorVersion ||
121 HeaderP->CheckSizes(DefHeader) == false)
122 return _error->Error("The package cache file is an incompatible version");
123
124 return true;
125 }
126 /*}}}*/
127 // Cache::Hash - Hash a string /*{{{*/
128 // ---------------------------------------------------------------------
129 /* This is used to generate the hash entries for the HashTable. With my
130 package list from bo this function gets 94% table usage on a 512 item
131 table (480 used items) */
132 unsigned long pkgCache::sHash(string Str)
133 {
134 unsigned long Hash = 0;
135 for (const char *I = Str.begin(); I != Str.end(); I++)
136 Hash += *I * ((Str.end() - I + 1));
137 Header H;
138 return Hash % _count(H.HashTable);
139 }
140
141 unsigned long pkgCache::sHash(const char *Str)
142 {
143 unsigned long Hash = 0;
144 const char *End = Str + strlen(Str);
145 for (const char *I = Str; I != End; I++)
146 Hash += *I * ((End - I + 1));
147 Header H;
148 return Hash % _count(H.HashTable);
149 }
150
151 /*}}}*/
152 // Cache::FindPkg - Locate a package by name /*{{{*/
153 // ---------------------------------------------------------------------
154 /* Returns 0 on error, pointer to the package otherwise */
155 pkgCache::PkgIterator pkgCache::FindPkg(string Name)
156 {
157 // Look at the hash bucket
158 Package *Pkg = PkgP + HeaderP->HashTable[Hash(Name)];
159 for (; Pkg != PkgP; Pkg = PkgP + Pkg->NextPackage)
160 {
161 if (Pkg->Name != 0 && StrP + Pkg->Name == Name)
162 return PkgIterator(*this,Pkg);
163 }
164 return PkgIterator(*this,0);
165 }
166 /*}}}*/
167 // Cache::Priority - Convert a priority value to a string /*{{{*/
168 // ---------------------------------------------------------------------
169 /* */
170 const char *pkgCache::Priority(unsigned char Prio)
171 {
172 const char *Mapping[] = {0,"important","required","standard","optional","extra"};
173 if (Prio < _count(Mapping))
174 return Mapping[Prio];
175 return 0;
176 }
177 /*}}}*/
178
179 // Bases for iterator classes /*{{{*/
180 void pkgCache::VerIterator::_dummy() {}
181 void pkgCache::DepIterator::_dummy() {}
182 void pkgCache::PrvIterator::_dummy() {}
183 /*}}}*/
184 // PkgIterator::operator ++ - Postfix incr /*{{{*/
185 // ---------------------------------------------------------------------
186 /* This will advance to the next logical package in the hash table. */
187 void pkgCache::PkgIterator::operator ++(int)
188 {
189 // Follow the current links
190 if (Pkg != Owner->PkgP)
191 Pkg = Owner->PkgP + Pkg->NextPackage;
192
193 // Follow the hash table
194 while (Pkg == Owner->PkgP && HashIndex < (signed)_count(Owner->HeaderP->HashTable))
195 {
196 HashIndex++;
197 Pkg = Owner->PkgP + Owner->HeaderP->HashTable[HashIndex];
198 }
199 };
200 /*}}}*/
201 // PkgIterator::State - Check the State of the package /*{{{*/
202 // ---------------------------------------------------------------------
203 /* By this we mean if it is either cleanly installed or cleanly removed. */
204 pkgCache::PkgIterator::OkState pkgCache::PkgIterator::State() const
205 {
206 if (Pkg->CurrentState == State::UnPacked ||
207 Pkg->CurrentState == State::HalfConfigured)
208 return NeedsConfigure;
209
210 if (Pkg->CurrentState == State::UnInstalled ||
211 Pkg->CurrentState == State::HalfInstalled ||
212 Pkg->InstState != State::Ok)
213 return NeedsUnpack;
214
215 return NeedsNothing;
216 }
217 /*}}}*/
218 // DepIterator::IsCritical - Returns true if the dep is important /*{{{*/
219 // ---------------------------------------------------------------------
220 /* Currently critical deps are defined as depends, predepends and
221 conflicts. */
222 bool pkgCache::DepIterator::IsCritical()
223 {
224 if (Dep->Type == Dep::Conflicts || Dep->Type == Dep::Depends ||
225 Dep->Type == Dep::PreDepends)
226 return true;
227 return false;
228 }
229 /*}}}*/
230 // DepIterator::SmartTargetPkg - Resolve dep target pointers w/provides /*{{{*/
231 // ---------------------------------------------------------------------
232 /* This intellegently looks at dep target packages and tries to figure
233 out which package should be used. This is needed to nicely handle
234 provide mapping. If the target package has no other providing packages
235 then it returned. Otherwise the providing list is looked at to
236 see if there is one one unique providing package if so it is returned.
237 Otherwise true is returned and the target package is set. The return
238 result indicates whether the node should be expandable */
239 bool pkgCache::DepIterator::SmartTargetPkg(PkgIterator &Result)
240 {
241 Result = TargetPkg();
242
243 // No provides at all
244 if (Result->ProvidesList == 0)
245 return false;
246
247 // There is the Base package and the providing ones which is at least 2
248 if (Result->VersionList != 0)
249 return true;
250
251 /* We have to skip over indirect provisions of the package that
252 owns the dependency. For instance, if libc5-dev depends on the
253 virtual package libc-dev which is provided by libc5-dev and libc6-dev
254 we must ignore libc5-dev when considering the provides list. */
255 PrvIterator PStart = Result.ProvidesList();
256 for (; PStart.end() != true && PStart.OwnerPkg() == ParentPkg(); PStart++);
257
258 // Nothing but indirect self provides
259 if (PStart.end() == true)
260 return false;
261
262 // Check for single packages in the provides list
263 PrvIterator P = PStart;
264 for (; P.end() != true; P++)
265 {
266 // Skip over self provides
267 if (P.OwnerPkg() == ParentPkg())
268 continue;
269 if (PStart.OwnerPkg() != P.OwnerPkg())
270 break;
271 }
272
273 // Check for non dups
274 if (P.end() != true)
275 return true;
276 Result = PStart.OwnerPkg();
277 return false;
278 }
279 /*}}}*/
280 // DepIterator::AllTargets - Returns the set of all possible targets /*{{{*/
281 // ---------------------------------------------------------------------
282 /* This is a more usefull version of TargetPkg() that follows versioned
283 provides. It includes every possible package-version that could satisfy
284 the dependency. The last item in the list has a 0. */
285 pkgCache::Version **pkgCache::DepIterator::AllTargets()
286 {
287 Version **Res = 0;
288 unsigned long Size =0;
289 while (1)
290 {
291 Version **End = Res;
292 PkgIterator DPkg = TargetPkg();
293
294 // Walk along the actual package providing versions
295 for (VerIterator I = DPkg.VersionList(); I.end() == false; I++)
296 {
297 if (pkgCheckDep(TargetVer(),I.VerStr(),Dep->CompareOp) == false)
298 continue;
299
300 if (Dep->Type == Dep::Conflicts && ParentPkg() == I.ParentPkg())
301 continue;
302
303 Size++;
304 if (Res != 0)
305 *End++ = I;
306 }
307
308 // Follow all provides
309 for (PrvIterator I = DPkg.ProvidesList(); I.end() == false; I++)
310 {
311 if (pkgCheckDep(TargetVer(),I.ProvideVersion(),Dep->CompareOp) == false)
312 continue;
313
314 if (Dep->Type == Dep::Conflicts && ParentPkg() == I.OwnerPkg())
315 continue;
316
317 Size++;
318 if (Res != 0)
319 *End++ = I.OwnerVer();
320 }
321
322 // Do it again and write it into the array
323 if (Res == 0)
324 {
325 Res = new Version *[Size+1];
326 Size = 0;
327 }
328 else
329 {
330 *End = 0;
331 break;
332 }
333 }
334
335 return Res;
336 }
337 /*}}}*/
338 // VerIterator::CompareVer - Fast version compare for same pkgs /*{{{*/
339 // ---------------------------------------------------------------------
340 /* This just looks over the version list to see if B is listed before A. In
341 most cases this will return in under 4 checks, ver lists are short. */
342 int pkgCache::VerIterator::CompareVer(const VerIterator &B) const
343 {
344 // Check if they are equal
345 if (*this == B)
346 return 0;
347 if (end() == true)
348 return -1;
349 if (B.end() == true)
350 return 1;
351
352 /* Start at A and look for B. If B is found then A > B otherwise
353 B was before A so A < B */
354 VerIterator I = *this;
355 for (;I.end() == false; I++)
356 if (I == B)
357 return 1;
358 return -1;
359 }
360 /*}}}*/
361 // VerIterator::Downloadable - Checks if the version is downloadable /*{{{*/
362 // ---------------------------------------------------------------------
363 /* */
364 bool pkgCache::VerIterator::Downloadable() const
365 {
366 VerFileIterator Files = FileList();
367 for (; Files.end() == false; Files++)
368 if ((Files.File()->Flags & Flag::NotSource) != Flag::NotSource)
369 return true;
370 return false;
371 }
372 /*}}}*/
373 // PkgFileIterator::IsOk - Checks if the cache is in sync with the file /*{{{*/
374 // ---------------------------------------------------------------------
375 /* This stats the file and compares its stats with the ones that were
376 stored during generation. Date checks should probably also be
377 included here. */
378 bool pkgCache::PkgFileIterator::IsOk()
379 {
380 struct stat Buf;
381 if (stat(FileName(),&Buf) != 0)
382 return false;
383
384 if (Buf.st_size != (signed)File->Size || Buf.st_mtime != File->mtime)
385 return false;
386
387 return true;
388 }
389 /*}}}*/