~ubuntu-branches/ubuntu/oneiric/dpkg/oneiric-proposed

« back to all changes in this revision

Viewing changes to lib/dpkg/database.c

  • Committer: Steve Langasek
  • Date: 2011-03-15 00:11:56 UTC
  • Revision ID: steve.langasek@linaro.org-20110315001156-uyrlgh501d69seku
Merge newer snapshot from Raphael, to keep us in tune with mainline

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * libdpkg - Debian packaging suite library routines
3
 
 * dpkg-db.h - Low level package database routines (hash tables, etc.)
4
 
 *
5
 
 * Copyright © 1995 Ian Jackson <ian@chiark.greenend.org.uk>
6
 
 * Copyright © 2011 Linaro Limited
7
 
 * Copyright © 2011 Raphaël Hertzog <hertzog@debian.org>
8
 
 *
9
 
 * This is free software; you can redistribute it and/or modify
10
 
 * it under the terms of the GNU General Public License as published by
11
 
 * the Free Software Foundation; either version 2 of the License, or
12
 
 * (at your option) any later version.
13
 
 *
14
 
 * This is distributed in the hope that it will be useful,
15
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 
 * GNU General Public License for more details.
18
 
 *
19
 
 * You should have received a copy of the GNU General Public License
20
 
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21
 
 */
22
 
 
23
 
#include <config.h>
24
 
#include <compat.h>
25
 
 
26
 
#include <assert.h>
27
 
#include <ctype.h>
28
 
#include <string.h>
29
 
#include <stdlib.h>
30
 
 
31
 
#include <dpkg/i18n.h>
32
 
#include <dpkg/dpkg.h>
33
 
#include <dpkg/dpkg-db.h>
34
 
#include <dpkg/arch.h>
35
 
 
36
 
/* This must always be a prime for optimal performance.
37
 
 * With 4093 buckets, we glean a 20% speedup, for 8191 buckets
38
 
 * we get 23%. The nominal increase in memory usage is a mere
39
 
 * sizeof(void *) * 8063 (i.e. less than 32 KiB on 32bit systems). */
40
 
#define BINS 8191
41
 
 
42
 
static struct pkgset *bins[BINS];
43
 
static int npkg, nset;
44
 
 
45
 
#define FNV_offset_basis 2166136261ul
46
 
#define FNV_mixing_prime 16777619ul
47
 
 
48
 
/**
49
 
 * Fowler/Noll/Vo -- simple string hash.
50
 
 *
51
 
 * For more info, see <http://www.isthe.com/chongo/tech/comp/fnv/index.html>.
52
 
 */
53
 
static unsigned int hash(const char *name) {
54
 
  register unsigned int h = FNV_offset_basis;
55
 
  register unsigned int p = FNV_mixing_prime;
56
 
  while( *name ) {
57
 
    h *= p;
58
 
    h ^= *name++;
59
 
  }
60
 
  return h;
61
 
}
62
 
 
63
 
void blankversion(struct versionrevision *version) {
64
 
  version->epoch= 0;
65
 
  version->version= version->revision= NULL;
66
 
}
67
 
 
68
 
void
69
 
pkgset_blank(struct pkgset *set)
70
 
{
71
 
  set->name = NULL;
72
 
  set->depended.available = NULL;
73
 
  set->depended.installed = NULL;
74
 
  pkg_blank(&set->pkg);
75
 
  set->pkg.set = set;
76
 
}
77
 
 
78
 
void
79
 
pkg_blank(struct pkginfo *pigp)
80
 
{
81
 
  pigp->set = NULL;
82
 
  pigp->arch_next = NULL;
83
 
  pigp->status= stat_notinstalled;
84
 
  pigp->eflag = eflag_ok;
85
 
  pigp->want= want_unknown;
86
 
  pigp->priority= pri_unknown;
87
 
  pigp->otherpriority = NULL;
88
 
  pigp->section= NULL;
89
 
  blankversion(&pigp->configversion);
90
 
  pigp->files= NULL;
91
 
  pigp->clientdata= NULL;
92
 
  pigp->trigaw.head = pigp->trigaw.tail = NULL;
93
 
  pigp->othertrigaw_head = NULL;
94
 
  pigp->trigpend_head = NULL;
95
 
  pkgbin_blank(&pigp->installed, false);
96
 
  pkgbin_blank(&pigp->available, false);
97
 
}
98
 
 
99
 
void
100
 
pkgbin_blank(struct pkgbin *pifp, bool keep_arch)
101
 
{
102
 
  pifp->essential = false;
103
 
  pifp->multiarch = multiarch_no;
104
 
  pifp->depends= NULL;
105
 
  pifp->description= pifp->maintainer= pifp->source= pifp->installedsize= pifp->bugs= pifp->origin= NULL;
106
 
  if (!keep_arch)
107
 
    pifp->arch = dpkg_arch_find(NULL);
108
 
  blankversion(&pifp->version);
109
 
  pifp->conffiles= NULL;
110
 
  pifp->arbs= NULL;
111
 
}
112
 
 
113
 
static int nes(const char *s) { return s && *s; }
114
 
 
115
 
/**
116
 
 * Check if a pkg is informative.
117
 
 *
118
 
 * Used by dselect and dpkg query options as an aid to decide whether to
119
 
 * display things, and by dump to decide whether to write them out.
120
 
 */
121
 
bool
122
 
pkg_is_informative(struct pkginfo *pkg, struct pkgbin *info)
123
 
{
124
 
  if (info == &pkg->installed &&
125
 
      (pkg->want != want_unknown ||
126
 
       pkg->eflag != eflag_ok ||
127
 
       pkg->status != stat_notinstalled ||
128
 
       informativeversion(&pkg->configversion)))
129
 
    /* We ignore Section and Priority, as these tend to hang around. */
130
 
    return true;
131
 
  if (info->depends ||
132
 
      nes(info->description) ||
133
 
      nes(info->maintainer) ||
134
 
      nes(info->origin) ||
135
 
      nes(info->bugs) ||
136
 
      nes(info->installedsize) ||
137
 
      nes(info->source) ||
138
 
      informativeversion(&info->version) ||
139
 
      info->conffiles ||
140
 
      info->arbs)
141
 
    return true;
142
 
  return false;
143
 
}
144
 
 
145
 
/**
146
 
 * Return the package set with the given name.
147
 
 *
148
 
 * If the package already exists in the internal database, then it returns
149
 
 * the existing structure. Otherwise it allocates a new one and will
150
 
 * return it. The actual name associated to the package set is a lowercase
151
 
 * version of the name given in parameter.
152
 
 *
153
 
 * A package set (struct pkgset) can be composed of multiple package
154
 
 * instances (struct pkginfo) where each instance is distinguished
155
 
 * by its architecture (as recorded in pkg.{installed,available}.architecture).
156
 
 *
157
 
 * @param inname Name of the package set.
158
 
 * @return The package set.
159
 
 */
160
 
struct pkgset *
161
 
pkg_db_find_set(const char *inname)
162
 
{
163
 
  struct pkgset **pointerp, *newpkg;
164
 
  char *name = m_strdup(inname), *p;
165
 
 
166
 
  p= name;
167
 
  while(*p) { *p= tolower(*p); p++; }
168
 
 
169
 
  pointerp= bins + (hash(name) % (BINS));
170
 
  while (*pointerp && strcasecmp((*pointerp)->name,name))
171
 
    pointerp= &(*pointerp)->next;
172
 
  if (*pointerp) {
173
 
    free(name);
174
 
    return *pointerp;
175
 
  }
176
 
 
177
 
  newpkg = nfmalloc(sizeof(struct pkgset));
178
 
  pkgset_blank(newpkg);
179
 
  newpkg->name= nfstrsave(name);
180
 
  newpkg->next= NULL;
181
 
  *pointerp= newpkg;
182
 
  nset++;
183
 
  npkg++;
184
 
 
185
 
  free(name);
186
 
  return newpkg;
187
 
}
188
 
 
189
 
/**
190
 
 * Return the package instance with the given name and architecture.
191
 
 *
192
 
 * It first uses pkg_db_find_set() to retrieve the right package set and
193
 
 * then traverse the various instances to find out whether there's one
194
 
 * matching the given architecture. If yes, it returns it. Otherwise it
195
 
 * allocates an new instance and register it in the package set berfore
196
 
 * returning it.
197
 
 *
198
 
 * If the requested architecture is a NULL pointer, it will be dealt like
199
 
 * the native architecture and the special architecture "all": it will
200
 
 * always return the first instance in the list (this one always exists
201
 
 * since it's part of the pksget structure).
202
 
 *
203
 
 * @param name The package name.
204
 
 * @param arch The requested architecture.
205
 
 * @return The package instance.
206
 
 */
207
 
struct pkginfo *
208
 
pkg_db_find_pkg(const char *name, const struct dpkg_arch *arch)
209
 
{
210
 
  struct pkgset *set;
211
 
  struct pkginfo *pkg, **pkgp;
212
 
 
213
 
  set = pkg_db_find_set(name);
214
 
  pkg = &set->pkg;
215
 
  if (!arch || arch->type == arch_native || arch->type == arch_all ||
216
 
      arch->type == arch_none) {
217
 
    /* Must always use the first instance */
218
 
    assert(pkg->installed.arch->type == arch_native ||
219
 
           pkg->installed.arch->type == arch_all ||
220
 
           pkg->installed.arch->type == arch_none);
221
 
    return pkg;
222
 
  }
223
 
 
224
 
  /* Look into alternate instances for the wanted architecture */
225
 
  pkgp = &pkg->arch_next;
226
 
  while (*pkgp) {
227
 
    if (!(*pkgp)->installed.arch) {
228
 
      /* pkginfo is not differentiated, use it */
229
 
      (*pkgp)->installed.arch = arch;
230
 
      (*pkgp)->available.arch = arch;
231
 
      return *pkgp;
232
 
    }
233
 
    if ((*pkgp)->installed.arch == arch)
234
 
      return *pkgp;
235
 
    pkgp = &(*pkgp)->arch_next;
236
 
  }
237
 
 
238
 
  /* Need to create a new instance for the wanted architecture */
239
 
  pkg = nfmalloc(sizeof(struct pkginfo));
240
 
  pkg_blank(pkg);
241
 
  pkg->set = set;
242
 
  pkg->installed.arch = arch;
243
 
  pkg->available.arch = arch;
244
 
  *pkgp = pkg;
245
 
  npkg++;
246
 
 
247
 
  return pkg;
248
 
}
249
 
 
250
 
/**
251
 
 * Return the number of package sets available in the database.
252
 
 *
253
 
 * @return The number of package sets.
254
 
 */
255
 
int
256
 
pkg_db_count_set(void)
257
 
{
258
 
  return nset;
259
 
}
260
 
 
261
 
/**
262
 
 * Return the number of package instances available in the database.
263
 
 *
264
 
 * @return The number of package instances.
265
 
 */
266
 
int
267
 
pkg_db_count_pkg(void)
268
 
{
269
 
  return npkg;
270
 
}
271
 
 
272
 
struct pkgiterator {
273
 
  struct pkginfo *pigp;
274
 
  int nbinn;
275
 
};
276
 
 
277
 
/**
278
 
 * Create a new package iterator.
279
 
 *
280
 
 * It can iterate either over package sets or over package instances.
281
 
 *
282
 
 * @return The iterator.
283
 
 */
284
 
struct pkgiterator *
285
 
pkg_db_iter_new(void)
286
 
{
287
 
  struct pkgiterator *i;
288
 
  i= m_malloc(sizeof(struct pkgiterator));
289
 
  i->pigp= NULL;
290
 
  i->nbinn= 0;
291
 
  return i;
292
 
}
293
 
 
294
 
/**
295
 
 * Return the next package set in the database.
296
 
 *
297
 
 * If no further package set is available, it will return NULL.
298
 
 *
299
 
 * @name it The iterator.
300
 
 * @return A package set.
301
 
 */
302
 
struct pkgset *
303
 
pkg_db_iter_next_set(struct pkgiterator *it)
304
 
{
305
 
  struct pkgset *set;
306
 
 
307
 
  while (!it->pigp) {
308
 
    if (it->nbinn >= BINS)
309
 
      return NULL;
310
 
    if (bins[it->nbinn])
311
 
      it->pigp = &bins[it->nbinn]->pkg;
312
 
    it->nbinn++;
313
 
  }
314
 
 
315
 
  set = it->pigp->set;
316
 
  if (set->next)
317
 
    it->pigp = &set->next->pkg;
318
 
  else
319
 
    it->pigp = NULL;
320
 
 
321
 
  return set;
322
 
}
323
 
 
324
 
/**
325
 
 * Return the next package instance in the database.
326
 
 *
327
 
 * If no further package instance is available, it will return NULL. Note
328
 
 * that it will return all instances of a given package set in sequential
329
 
 * order. The first instance for a given package set will always
330
 
 * correspond to the native architecture even if that package is not
331
 
 * installed or available.
332
 
 *
333
 
 * @name i The iterator.
334
 
 * @return A package instance.
335
 
 */
336
 
struct pkginfo *
337
 
pkg_db_iter_next_pkg(struct pkgiterator *i)
338
 
{
339
 
  struct pkginfo *r;
340
 
 
341
 
  while (!i->pigp) {
342
 
    if (i->nbinn >= BINS) return NULL;
343
 
    if (bins[i->nbinn])
344
 
      i->pigp = &bins[i->nbinn]->pkg;
345
 
    i->nbinn++;
346
 
  }
347
 
 
348
 
  r = i->pigp;
349
 
  if (r->arch_next)
350
 
    i->pigp = r->arch_next;
351
 
  else if (r->set->next)
352
 
    i->pigp = &r->set->next->pkg;
353
 
  else
354
 
    i->pigp = NULL;
355
 
 
356
 
  return r;
357
 
}
358
 
 
359
 
/**
360
 
 * Free up the resources associated to the package iterator.
361
 
 *
362
 
 * @name i The iterator.
363
 
 */
364
 
void
365
 
pkg_db_iter_free(struct pkgiterator *i)
366
 
{
367
 
  free(i);
368
 
}
369
 
 
370
 
void
371
 
pkg_db_reset(void)
372
 
{
373
 
  int i;
374
 
  nffreeall();
375
 
  nset = 0;
376
 
  npkg = 0;
377
 
  for (i=0; i<BINS; i++) bins[i]= NULL;
378
 
  dpkg_arch_reset();
379
 
}
380
 
 
381
 
void hashreport(FILE *file) {
382
 
  int i, c;
383
 
  struct pkgset *pkg;
384
 
  int *freq;
385
 
 
386
 
  freq = m_malloc(sizeof(int) * nset + 1);
387
 
  for (i = 0; i <= nset; i++) freq[i]= 0;
388
 
  for (i=0; i<BINS; i++) {
389
 
    for (c=0, pkg= bins[i]; pkg; c++, pkg= pkg->next);
390
 
    fprintf(file,"bin %5d has %7d\n",i,c);
391
 
    freq[c]++;
392
 
  }
393
 
  for (i = nset; i > 0 && freq[i] == 0; i--);
394
 
  while (i >= 0) {
395
 
    fprintf(file, "size %7d occurs %5d times\n", i, freq[i]);
396
 
    i--;
397
 
  }
398
 
 
399
 
  m_output(file, "<hash report>");
400
 
 
401
 
  free(freq);
402
 
}