Bug Summary

File:lib/backend/db3.c
Warning:line 1047, column 29
Null pointer passed as an argument to a 'nonnull' parameter

Annotated Source Code

1/** \ingroup rpmdb
2 * \file lib/db3.c
3 */
4
5static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
6
7#include "system.h"
8
9#include <errno(*__errno_location ()).h>
10#include <sys/wait.h>
11#include <popt.h>
12#include <db.h>
13#include <signal.h>
14
15#include <rpm/rpmtypes.h>
16#include <rpm/rpmmacro.h>
17#include <rpm/rpmfileutil.h>
18#include <rpm/rpmlog.h>
19
20#include "lib/rpmdb_internal.h"
21
22#include "debug.h"
23
24static const char * _errpfx = "rpmdb";
25
26struct dbiCursor_s {
27 dbiIndex dbi;
28 const void *key;
29 unsigned int keylen;
30 int flags;
31 DBC *cursor;
32};
33
34static struct dbiConfig_s staticdbicfg;
35static struct dbConfig_s staticcfg;
36
37/** \ingroup dbi
38 */
39static const struct poptOption rdbOptions[] = {
40 /* Environment options */
41
42 { "cdb", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_INIT_CDB0x00000080,
43 NULL((void*)0), NULL((void*)0) },
44 { "lock", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_INIT_LOCK0x00000100,
45 NULL((void*)0), NULL((void*)0) },
46 { "log", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_INIT_LOG0x00000200,
47 NULL((void*)0), NULL((void*)0) },
48 { "txn", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_INIT_TXN0x00002000,
49 NULL((void*)0), NULL((void*)0) },
50 { "recover", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_RECOVER0x00000002,
51 NULL((void*)0), NULL((void*)0) },
52 { "recover_fatal", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_RECOVER_FATAL0x00020000,
53 NULL((void*)0), NULL((void*)0) },
54 { "lockdown", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_LOCKDOWN0x00004000,
55 NULL((void*)0), NULL((void*)0) },
56 { "private", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_eflags, DB_PRIVATE0x00010000,
57 NULL((void*)0), NULL((void*)0) },
58
59 { "deadlock", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_verbose, DB_VERB_DEADLOCK0x00000002,
60 NULL((void*)0), NULL((void*)0) },
61 { "recovery", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_verbose, DB_VERB_RECOVERY0x00000010,
62 NULL((void*)0), NULL((void*)0) },
63 { "waitsfor", 0,POPT_BIT_SET(7U|0x08000000U), &staticcfg.db_verbose, DB_VERB_WAITSFOR0x00010000,
64 NULL((void*)0), NULL((void*)0) },
65 { "verbose", 0,POPT_ARG_VAL7U, &staticcfg.db_verbose, -1,
66 NULL((void*)0), NULL((void*)0) },
67
68 { "cachesize", 0,POPT_ARG_INT2U, &staticcfg.db_cachesize, 0,
69 NULL((void*)0), NULL((void*)0) },
70 { "mmapsize", 0,POPT_ARG_INT2U, &staticcfg.db_mmapsize, 0,
71 NULL((void*)0), NULL((void*)0) },
72 { "mp_mmapsize", 0,POPT_ARG_INT2U, &staticcfg.db_mmapsize, 0,
73 NULL((void*)0), NULL((void*)0) },
74 { "mp_size", 0,POPT_ARG_INT2U, &staticcfg.db_cachesize, 0,
75 NULL((void*)0), NULL((void*)0) },
76
77 { "nofsync", 0,POPT_ARG_NONE0U, &staticcfg.db_no_fsync, 0,
78 NULL((void*)0), NULL((void*)0) },
79
80 /* Per-dbi options */
81 { "nommap", 0,POPT_BIT_SET(7U|0x08000000U), &staticdbicfg.dbi_oflags, DB_NOMMAP0x00000010,
82 NULL((void*)0), NULL((void*)0) },
83
84 { "nodbsync", 0,POPT_ARG_NONE0U, &staticdbicfg.dbi_no_dbsync, 0,
85 NULL((void*)0), NULL((void*)0) },
86 { "lockdbfd", 0,POPT_ARG_NONE0U, &staticdbicfg.dbi_lockdbfd, 0,
87 NULL((void*)0), NULL((void*)0) },
88
89 POPT_TABLEEND{ ((void*)0), '\0', 0, ((void*)0), 0, ((void*)0), ((void*)0) }
90};
91
92
93static int dbapi_err(rpmdb rdb, const char * msg, int error, int printit)
94{
95 if (printit && error) {
96 if (msg)
97 rpmlog(RPMLOG_ERR, _("%s error(%d) from %s: %s\n")dcgettext ("rpm", "%s error(%d) from %s: %s\n", 5),
98 rdb->db_descr, error, msg, db_strerror(error));
99 else
100 rpmlog(RPMLOG_ERR, _("%s error(%d): %s\n")dcgettext ("rpm", "%s error(%d): %s\n", 5),
101 rdb->db_descr, error, db_strerror(error));
102 }
103 return error;
104}
105
106static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
107{
108 return dbapi_err(dbi->dbi_rpmdb, msg, error, printit);
109}
110
111static void errlog(const DB_ENV * env, const char *errpfx, const char *msg)
112{
113 rpmlog(RPMLOG_ERR, "%s: %s\n", errpfx, msg);
114}
115
116static void warnlog(const DB_ENV *env, const char *msg)
117{
118 rpmlog(RPMLOG_WARNING, "%s: %s\n", _errpfx, msg);
119}
120
121static uint32_t db_envflags(DB * db)
122{
123 DB_ENV * env = db->get_env(db);
124 uint32_t eflags = 0;
125 (void) env->get_open_flags(env, &eflags);
126 return eflags;
127}
128
129/*
130 * Try to acquire db environment open/close serialization lock.
131 * Return the open, locked fd on success, -1 on failure.
132 */
133static int serialize_env(const char *dbhome)
134{
135 char *lock_path = rstrscat(NULL((void*)0), dbhome, "/.dbenv.lock", NULL((void*)0));
136 mode_t oldmask = umask(022);
137 int fd = open(lock_path, (O_RDWR02|O_CREAT0100), 0644);
138 umask(oldmask);
139
140 if (fd >= 0) {
141 int rc;
142 struct flock info;
143 memset(&info, 0, sizeof(info));
144 info.l_type = F_WRLCK1;
145 info.l_whence = SEEK_SET0;
146 do {
147 rc = fcntl(fd, F_SETLKW7, &info);
148 } while (rc == -1 && errno(*__errno_location ()) == EINTR4);
149
150 if (rc == -1) {
151 close(fd);
152 fd = -1;
153 }
154 }
155
156 free(lock_path);
157 return fd;
158}
159
160static int db_fini(rpmdb rdb, const char * dbhome)
161{
162 DB_ENV * dbenv = rdb->db_dbenv;
163 int rc;
164 int lockfd = -1;
165 uint32_t eflags = 0;
166
167 if (dbenv == NULL((void*)0))
168 return 0;
169
170 if (rdb->db_opens > 1) {
171 rdb->db_opens--;
172 return 0;
173 }
174
175 (void) dbenv->get_open_flags(dbenv, &eflags);
176 if (!(eflags & DB_PRIVATE0x00010000))
177 lockfd = serialize_env(dbhome);
178
179 rc = dbenv->close(dbenv, 0);
180 rc = dbapi_err(rdb, "dbenv->close", rc, _debug);
181
182 rpmlog(RPMLOG_DEBUG, "closed db environment %s\n", dbhome);
183
184 if (!(eflags & DB_PRIVATE0x00010000) && rdb->db_remove_env) {
185 int xx;
186
187 xx = db_env_create(&dbenv, 0);
188 xx = dbapi_err(rdb, "db_env_create", xx, _debug);
189 xx = dbenv->remove(dbenv, dbhome, 0);
190 /* filter out EBUSY as it just means somebody else gets to clean it */
191 xx = dbapi_err(rdb, "dbenv->remove", xx, (xx == EBUSY16 ? 0 : _debug));
192
193 rpmlog(RPMLOG_DEBUG, "removed db environment %s\n", dbhome);
194
195 }
196
197 if (lockfd >= 0)
198 close(lockfd);
199
200 return rc;
201}
202
203static int fsync_disable(int fd)
204{
205 return 0;
206}
207
208/*
209 * dbenv->failchk() callback method for determining is the given pid/tid
210 * is alive. We only care about pid's though.
211 */
212static int isalive(DB_ENV *dbenv, pid_t pid, db_threadid_t tid, uint32_t flags)
213{
214 int alive = 0;
215
216 if (pid == getpid()) {
217 alive = 1;
218 } else if (kill(pid, 0) == 0) {
219 alive = 1;
220 /* only existing processes can fail with EPERM */
221 } else if (errno(*__errno_location ()) == EPERM1) {
222 alive = 1;
223 }
224
225 return alive;
226}
227
228
229static void dbConfigure(rpmDbiTagVal rpmtag, struct dbConfig_s *cfg, struct dbiConfig_s *dbicfg)
230{
231 char *dbOpts;
232
233 dbOpts = rpmExpand("%{_dbi_config_", rpmTagGetName(rpmtag), "}", NULL((void*)0));
234
235 if (!(dbOpts && *dbOpts && *dbOpts != '%')) {
236 dbOpts = _free(dbOpts)rfree((dbOpts));
237 dbOpts = rpmExpand("%{_dbi_config}", NULL((void*)0));
238 if (!(dbOpts && *dbOpts && *dbOpts != '%')) {
239 dbOpts = _free(dbOpts)rfree((dbOpts));
240 }
241 }
242
243 /* Parse the options for the database element(s). */
244 if (dbOpts && *dbOpts && *dbOpts != '%') {
245 char *o, *oe;
246 char *p, *pe;
247
248 memset(&staticdbicfg, 0, sizeof(staticdbicfg));
249/*=========*/
250 for (o = dbOpts; o && *o; o = oe) {
251 const struct poptOption *opt;
252 const char * tok;
253 unsigned int argInfo;
254
255 /* Skip leading white space. */
256 while (*o && risspace(*o))
257 o++;
258
259 /* Find and terminate next key=value pair. Save next start point. */
260 for (oe = o; oe && *oe; oe++) {
261 if (risspace(*oe))
262 break;
263 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
264 break;
265 }
266 if (oe && *oe)
267 *oe++ = '\0';
268 if (*o == '\0')
269 continue;
270
271 /* Separate key from value, save value start (if any). */
272 for (pe = o; pe && *pe && *pe != '='; pe++)
273 {};
274 p = (pe ? *pe++ = '\0', pe : NULL((void*)0));
275
276 /* Skip over negation at start of token. */
277 for (tok = o; *tok == '!'; tok++)
278 {};
279
280 /* Find key in option table. */
281 for (opt = rdbOptions; opt->longName != NULL((void*)0); opt++) {
282 if (!rstreq(tok, opt->longName))
283 continue;
284 break;
285 }
286 if (opt->longName == NULL((void*)0)) {
287 rpmlog(RPMLOG_ERR,
288 _("unrecognized db option: \"%s\" ignored.\n")dcgettext ("rpm", "unrecognized db option: \"%s\" ignored.\n"
, 5)
, o);
289 continue;
290 }
291
292 /* Toggle the flags for negated tokens, if necessary. */
293 argInfo = opt->argInfo;
294 if (argInfo == POPT_BIT_SET(7U|0x08000000U) && *o == '!' && ((tok - o) % 2))
295 argInfo = POPT_BIT_CLR(7U|0x05000000U);
296
297 /* Save value in template as appropriate. */
298 switch (argInfo & POPT_ARG_MASK0x000000FFU) {
299
300 case POPT_ARG_NONE0U:
301 (void) poptSaveInt((int *)opt->arg, argInfo, 1L);
302 break;
303 case POPT_ARG_VAL7U:
304 (void) poptSaveInt((int *)opt->arg, argInfo, (long)opt->val);
305 break;
306 case POPT_ARG_STRING1U:
307 { char ** t = opt->arg;
308 if (t) {
309/* FIX: opt->arg annotation in popt.h */
310 *t = _free(*t)rfree((*t));
311 *t = xstrdup( (p ? p : "") )rstrdup(((p ? p : "")));
312 }
313 } break;
314
315 case POPT_ARG_INT2U:
316 case POPT_ARG_LONG3U:
317 { long aLong = strtol(p, &pe, 0);
318 if (pe) {
319 if (!rstrncasecmp(pe, "Mb", 2))
320 aLong *= 1024 * 1024;
321 else if (!rstrncasecmp(pe, "Kb", 2))
322 aLong *= 1024;
323 else if (*pe != '\0') {
324 rpmlog(RPMLOG_ERR,
325 _("%s has invalid numeric value, skipped\n")dcgettext ("rpm", "%s has invalid numeric value, skipped\n", 5
)
,
326 opt->longName);
327 continue;
328 }
329 }
330
331 if ((argInfo & POPT_ARG_MASK0x000000FFU) == POPT_ARG_LONG3U) {
332 if (aLong == LONG_MIN(-9223372036854775807L -1L) || aLong == LONG_MAX9223372036854775807L) {
333 rpmlog(RPMLOG_ERR,
334 _("%s has too large or too small long value, skipped\n")dcgettext ("rpm", "%s has too large or too small long value, skipped\n"
, 5)
,
335 opt->longName);
336 continue;
337 }
338 (void) poptSaveLong((long *)opt->arg, argInfo, aLong);
339 break;
340 } else {
341 if (aLong > INT_MAX2147483647 || aLong < INT_MIN(-2147483647 -1)) {
342 rpmlog(RPMLOG_ERR,
343 _("%s has too large or too small integer value, skipped\n")dcgettext ("rpm", "%s has too large or too small integer value, skipped\n"
, 5)
,
344 opt->longName);
345 continue;
346 }
347 (void) poptSaveInt((int *)opt->arg, argInfo, aLong);
348 }
349 } break;
350 default:
351 break;
352 }
353 }
354/*=========*/
355 }
356
357 dbOpts = _free(dbOpts)rfree((dbOpts));
358 if (cfg) {
359 *cfg = staticcfg; /* structure assignment */
360 /* Throw in some defaults if configuration didn't set any */
361 if (!cfg->db_mmapsize)
362 cfg->db_mmapsize = 16 * 1024 * 1024;
363 if (!cfg->db_cachesize)
364 cfg->db_cachesize = 8 * 1024 * 1024;
365 }
366 if (dbicfg) {
367 *dbicfg = staticdbicfg;
368 }
369}
370
371static char * prDbiOpenFlags(int dbflags, int print_dbenv_flags)
372{
373 ARGV_t flags = NULL((void*)0);
374 const struct poptOption *opt;
375 char *buf;
376
377 for (opt = rdbOptions; opt->longName != NULL((void*)0); opt++) {
378 if (opt->argInfo != POPT_BIT_SET(7U|0x08000000U))
379 continue;
380 if (print_dbenv_flags) {
381 if (!(opt->arg == &staticcfg.db_eflags))
382 continue;
383 } else {
384 if (!(opt->arg == &staticdbicfg.dbi_oflags))
385 continue;
386 }
387 if ((dbflags & opt->val) != opt->val)
388 continue;
389 argvAdd(&flags, opt->longName);
390 dbflags &= ~opt->val;
391 }
392 if (dbflags) {
393 char *df = NULL((void*)0);
394 rasprintf(&df, "0x%x", (unsigned)dbflags);
395 argvAdd(&flags, df);
396 free(df);
397 }
398 buf = argvJoin(flags, ":");
399 argvFree(flags);
400
401 return buf ? buf : xstrdup("(none)")rstrdup(("(none)"));
402}
403
404static int db_init(rpmdb rdb, const char * dbhome)
405{
406 DB_ENV *dbenv = NULL((void*)0);
407 int rc, xx;
408 int retry_open = 2;
409 int lockfd = -1;
410 struct dbConfig_s * cfg = &rdb->cfg;
411 /* This is our setup, thou shall not have other setups before us */
412 uint32_t eflags = (DB_CREATE0x00000001|DB_INIT_MPOOL0x00000400|DB_INIT_CDB0x00000080);
413
414 if (rdb->db_dbenv != NULL((void*)0)) {
415 rdb->db_opens++;
416 return 0;
417 } else {
418 /* On first call, set backend description to something... */
419 free(rdb->db_descr);
420 rasprintf(&rdb->db_descr, "db%u", DB_VERSION_MAJOR5);
421 }
422
423 /*
424 * Both verify and rebuild are rather special, if for different reasons:
425 * On rebuild we dont want to be affected by eg paniced environment, and
426 * CDB only slows things down there. Verify is a quirky beast unlike
427 * anything else in BDB, and does not like shared env or CDB.
428 */
429 if (rdb->db_flags & (RPMDB_FLAG_VERIFYONLY|RPMDB_FLAG_REBUILD)) {
430 eflags |= DB_PRIVATE0x00010000;
431 eflags &= ~DB_INIT_CDB0x00000080;
432 }
433
434 rc = db_env_create(&dbenv, 0);
435 rc = dbapi_err(rdb, "db_env_create", rc, _debug);
436 if (dbenv == NULL((void*)0) || rc)
437 goto errxit;
438
439 dbenv->set_alloc(dbenv, rmalloc, rrealloc, NULL((void*)0));
440 dbenv->set_errcall(dbenv, NULL((void*)0));
441 dbenv->set_errpfx(dbenv, _errpfx);
442 dbenv->set_msgcall(dbenv, warnlog);
443
444 /*
445 * These enable automatic stale lock removal.
446 * thread_count 8 is some kind of "magic minimum" value...
447 */
448 dbenv->set_thread_count(dbenv, 8);
449 dbenv->set_isalive(dbenv, isalive);
450
451 dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK0x00000002,
452 (cfg->db_verbose & DB_VERB_DEADLOCK0x00000002));
453 dbenv->set_verbose(dbenv, DB_VERB_RECOVERY0x00000010,
454 (cfg->db_verbose & DB_VERB_RECOVERY0x00000010));
455 dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR0x00010000,
456 (cfg->db_verbose & DB_VERB_WAITSFOR0x00010000));
457
458 if (cfg->db_mmapsize) {
459 xx = dbenv->set_mp_mmapsize(dbenv, cfg->db_mmapsize);
460 xx = dbapi_err(rdb, "dbenv->set_mp_mmapsize", xx, _debug);
461 }
462
463 if (cfg->db_cachesize) {
464 xx = dbenv->set_cachesize(dbenv, 0, cfg->db_cachesize, 0);
465 xx = dbapi_err(rdb, "dbenv->set_cachesize", xx, _debug);
466 }
467
468 /*
469 * Serialize shared environment open (and clock) via fcntl() lock.
470 * Otherwise we can end up calling dbenv->failchk() while another
471 * process is joining the environment, leading to transient
472 * DB_RUNRECOVER errors. Also prevents races wrt removing the
473 * environment (eg chrooted operation). Silently fall back to
474 * private environment on failure to allow non-privileged queries
475 * to "work", broken as it might be.
476 */
477 if (!(eflags & DB_PRIVATE0x00010000)) {
478 lockfd = serialize_env(dbhome);
479 if (lockfd < 0) {
480 eflags |= DB_PRIVATE0x00010000;
481 retry_open--;
482 rpmlog(RPMLOG_DEBUG, "serialize failed, using private dbenv\n");
483 }
484 }
485
486 /*
487 * Actually open the environment. Fall back to private environment
488 * if we dont have permission to join/create shared environment or
489 * system doesn't support it..
490 */
491 while (retry_open) {
492 char *fstr = prDbiOpenFlags(eflags, 1);
493 rpmlog(RPMLOG_DEBUG, "opening db environment %s %s\n", dbhome, fstr);
494 free(fstr);
495
496 rc = (dbenv->open)(dbenv, dbhome, eflags, rdb->db_perms);
497 if ((rc == EACCES13 || rc == EROFS30) || (rc == EINVAL22 && errno(*__errno_location ()) == rc)) {
498 eflags |= DB_PRIVATE0x00010000;
499 retry_open--;
500 } else {
501 retry_open = 0;
502 }
503 }
504 rc = dbapi_err(rdb, "dbenv->open", rc, _debug);
505 if (rc)
506 goto errxit;
507
508 dbenv->set_errcall(dbenv, errlog);
509
510 /* stale lock removal */
511 rc = dbenv->failchk(dbenv, 0);
512 rc = dbapi_err(rdb, "dbenv->failchk", rc, _debug);
513 if (rc)
514 goto errxit;
515
516 rdb->db_dbenv = dbenv;
517 rdb->db_opens = 1;
518
519 if (lockfd >= 0)
520 close(lockfd);
521 return 0;
522
523errxit:
524 if (dbenv) {
525 int xx;
526 xx = dbenv->close(dbenv, 0);
527 xx = dbapi_err(rdb, "dbenv->close", xx, _debug);
528 }
529 if (lockfd >= 0)
530 close(lockfd);
531 return rc;
532}
533
534static void db3_dbSetFSync(rpmdb rdb, int enable)
535{
536#ifdef HAVE_FDATASYNC1
537 db_env_set_func_fsync(enable ? fdatasync : fsync_disable);
538#else
539 db_env_set_func_fsync(enable ? fsync : fsync_disable);
540#endif
541}
542
543static int db3_Ctrl(rpmdb rdb, dbCtrlOp ctrl)
544{
545 return 0;
546}
547
548static int dbiSync(dbiIndex dbi, unsigned int flags)
549{
550 DB * db = dbi->dbi_db;
551 int rc = 0;
552
553 if (db != NULL((void*)0) && !dbi->cfg.dbi_no_dbsync) {
554 rc = db->sync(db, flags);
555 rc = cvtdberr(dbi, "db->sync", rc, _debug);
556 }
557 return rc;
558}
559
560static dbiCursor db3_dbiCursorInit(dbiIndex dbi, unsigned int flags)
561{
562 dbiCursor dbc = NULL((void*)0);
563
564 if (dbi && dbi->dbi_db) {
565 DB * db = dbi->dbi_db;
566 DBC * cursor;
567 int cflags;
568 int rc = 0;
569 uint32_t eflags = db_envflags(db);
570
571 /* DB_WRITECURSOR requires CDB and writable db */
572 if ((flags & DBC_WRITE) &&
573 (eflags & DB_INIT_CDB0x00000080) && !(dbi->dbi_flags & DBI_RDONLY))
574 {
575 cflags = DB_WRITECURSOR0x00000010;
576 } else
577 cflags = 0;
578
579 /*
580 * Check for stale locks which could block writes "forever".
581 * XXX: Should we also do this on reads? Reads are less likely
582 * to get blocked so it seems excessive...
583 * XXX: On DB_RUNRECOVER, we should abort everything. Now
584 * we'll just fail to open a cursor again and again and again.
585 */
586 if (cflags & DB_WRITECURSOR0x00000010) {
587 DB_ENV *dbenv = db->get_env(db);
588 rc = dbenv->failchk(dbenv, 0);
589 rc = cvtdberr(dbi, "dbenv->failchk", rc, _debug);
590 }
591
592 if (rc == 0) {
593 rc = db->cursor(db, NULL((void*)0), &cursor, cflags);
594 rc = cvtdberr(dbi, "db->cursor", rc, _debug);
595 }
596
597 if (rc == 0) {
598 dbc = xcalloc(1, sizeof(*dbc))rcalloc((1), (sizeof(*dbc)));
599 dbc->cursor = cursor;
600 dbc->dbi = dbi;
601 dbc->flags = flags;
602 }
603 }
604
605 return dbc;
606}
607
608static dbiCursor db3_dbiCursorFree(dbiIndex dbi, dbiCursor dbc)
609{
610 if (dbc) {
611 /* Automatically sync on write-cursor close */
612 if (dbc->flags & DBC_WRITE)
613 dbiSync(dbc->dbi, 0);
614 DBC * cursor = dbc->cursor;
615 int rc = cursor->c_close(cursor);
616 cvtdberr(dbc->dbi, "dbcursor->c_close", rc, _debug);
617 free(dbc);
618 }
619 return NULL((void*)0);
620}
621
622static int dbiCursorPut(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
623{
624 int rc = EINVAL22;
625 int sane = (key->data != NULL((void*)0) && key->size > 0 &&
626 data->data != NULL((void*)0) && data->size > 0);
627
628 if (dbc && sane) {
629 DBC * cursor = dbc->cursor;
630 rpmdb rdb = dbc->dbi->dbi_rpmdb;
631 rpmswEnter(&rdb->db_putops, (ssize_t) 0);
632
633 rc = cursor->c_put(cursor, key, data, DB_KEYLAST14);
634 rc = cvtdberr(dbc->dbi, "dbcursor->c_put", rc, _debug);
635
636 rpmswExit(&rdb->db_putops, (ssize_t) data->size);
637 }
638 return rc;
639}
640
641static int dbiCursorGet(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
642{
643 int rc = EINVAL22;
644 int sane = ((flags == DB_NEXT16) || (key->data != NULL((void*)0) && key->size > 0));
645
646 if (dbc && sane) {
647 DBC * cursor = dbc->cursor;
648 rpmdb rdb = dbc->dbi->dbi_rpmdb;
649 int _printit;
650 rpmswEnter(&rdb->db_getops, 0);
651
652 /* XXX db4 does DB_FIRST on uninitialized cursor */
653 rc = cursor->c_get(cursor, key, data, flags);
654 /* XXX DB_NOTFOUND can be returned */
655 _printit = (rc == DB_NOTFOUND(-30988) ? 0 : _debug);
656 rc = cvtdberr(dbc->dbi, "dbcursor->c_get", rc, _printit);
657
658 /* Remember the last key fetched */
659 if (rc == 0) {
660 dbc->key = key->data;
661 dbc->keylen = key->size;
662 } else {
663 dbc->key = NULL((void*)0);
664 dbc->keylen = 0;
665 }
666
667 rpmswExit(&rdb->db_getops, data->size);
668 }
669 return rc;
670}
671
672static int dbiCursorDel(dbiCursor dbc, DBT * key, DBT * data, unsigned int flags)
673{
674 int rc = EINVAL22;
675 int sane = (key->data != NULL((void*)0) && key->size > 0);
676
677 if (dbc && sane) {
678 DBC * cursor = dbc->cursor;
679 int _printit;
680 rpmdb rdb = dbc->dbi->dbi_rpmdb;
681 rpmswEnter(&rdb->db_delops, 0);
682
683 /* XXX TODO: insure that cursor is positioned with duplicates */
684 rc = cursor->c_get(cursor, key, data, DB_SET26);
685 /* XXX DB_NOTFOUND can be returned */
686 _printit = (rc == DB_NOTFOUND(-30988) ? 0 : _debug);
687 rc = cvtdberr(dbc->dbi, "dbcursor->c_get", rc, _printit);
688
689 if (rc == 0) {
690 rc = cursor->c_del(cursor, flags);
691 rc = cvtdberr(dbc->dbi, "dbcursor->c_del", rc, _debug);
692 }
693 rpmswExit(&rdb->db_delops, data->size);
694 }
695 return rc;
696}
697
698static int dbiByteSwapped(dbiIndex dbi)
699{
700 DB * db = dbi->dbi_db;
701 int rc = 0;
702
703 if (dbi->dbi_byteswapped != -1)
704 return dbi->dbi_byteswapped;
705
706 if (db != NULL((void*)0)) {
707 int isswapped = 0;
708 rc = db->get_byteswapped(db, &isswapped);
709 if (rc == 0)
710 dbi->dbi_byteswapped = rc = isswapped;
711 }
712 return rc;
713}
714
715static int db3_dbiVerify(dbiIndex dbi, unsigned int flags)
716{
717 int rc = 0;
718
719 if (dbi && dbi->dbi_db) {
720 DB * db = dbi->dbi_db;
721
722 rc = db->verify(db, dbi->dbi_file, NULL((void*)0), NULL((void*)0), flags);
723 rc = cvtdberr(dbi, "db->verify", rc, _debug);
724
725 rpmlog(RPMLOG_DEBUG, "verified db index %s\n", dbi->dbi_file);
726
727 /* db->verify() destroys the handle, make sure nobody accesses it */
728 dbi->dbi_db = NULL((void*)0);
729 }
730 return rc;
731}
732
733static int db3_dbiClose(dbiIndex dbi, unsigned int flags)
734{
735 rpmdb rdb = dbi->dbi_rpmdb;
736 const char * dbhome = rpmdbHome(rdb);
737 DB * db = dbi->dbi_db;
738 int _printit;
739 int rc = 0;
740
741 if (db) {
742 rc = db->close(db, flags);
743 /* XXX ignore not found error messages. */
744 _printit = (rc == ENOENT2 ? 0 : _debug);
745 rc = cvtdberr(dbi, "db->close", rc, _printit);
746 db = dbi->dbi_db = NULL((void*)0);
747
748 rpmlog(RPMLOG_DEBUG, "closed db index %s/%s\n",
749 dbhome, dbi->dbi_file);
750 }
751
752 db_fini(rdb, dbhome ? dbhome : "");
753
754 dbi->dbi_db = NULL((void*)0);
755
756 dbi = dbiFree(dbi);
757
758 return rc;
759}
760
761/*
762 * Lock a file using fcntl(2). Traditionally this is Packages,
763 * the file used to store metadata of installed header(s),
764 * as Packages is always opened, and should be opened first,
765 * for any rpmdb access.
766 *
767 * If no DBENV is used, then access is protected with a
768 * shared/exclusive locking scheme, as always.
769 *
770 * With a DBENV, the fcntl(2) lock is necessary only to keep
771 * the riff-raff from playing where they don't belong, as
772 * the DBENV should provide it's own locking scheme. So try to
773 * acquire a lock, but permit failures, as some other
774 * DBENV player may already have acquired the lock.
775 *
776 * With NPTL posix mutexes, revert to fcntl lock on non-functioning
777 * glibc/kernel combinations.
778 */
779static int dbiFlock(dbiIndex dbi, int mode)
780{
781 int fdno = -1;
782 int rc = 0;
783 DB * db = dbi->dbi_db;
784
785 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
786 rc = 1;
787 } else {
788 const char *dbhome = rpmdbHome(dbi->dbi_rpmdb);
789 struct flock l;
790 memset(&l, 0, sizeof(l));
791 l.l_whence = 0;
792 l.l_start = 0;
793 l.l_len = 0;
794 l.l_type = (mode & O_ACCMODE0003) == O_RDONLY00
795 ? F_RDLCK0 : F_WRLCK1;
796 l.l_pid = 0;
797
798 rc = fcntl(fdno, F_SETLK6, (void *) &l);
799 if (rc) {
800 uint32_t eflags = db_envflags(db);
801 /* Warning iff using non-private CDB locking. */
802 rc = (((eflags & DB_INIT_CDB0x00000080) && !(eflags & DB_PRIVATE0x00010000)) ? 0 : 1);
803 rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING),
804 _("cannot get %s lock on %s/%s\n")dcgettext ("rpm", "cannot get %s lock on %s/%s\n", 5),
805 ((mode & O_ACCMODE0003) == O_RDONLY00)
806 ? _("shared")dcgettext ("rpm", "shared", 5) : _("exclusive")dcgettext ("rpm", "exclusive", 5),
807 dbhome, dbi->dbi_file);
808 } else {
809 rpmlog(RPMLOG_DEBUG,
810 "locked db index %s/%s\n",
811 dbhome, dbi->dbi_file);
812 }
813 }
814 return rc;
815}
816
817static int db3_dbiOpen(rpmdb rdb, rpmDbiTagVal rpmtag, dbiIndex * dbip, int flags)
818{
819 const char *dbhome = rpmdbHome(rdb);
820 dbiIndex dbi = NULL((void*)0);
821 int rc = 0;
822 int retry_open;
823 int verifyonly = (flags & RPMDB_FLAG_VERIFYONLY);
824
825 DB * db = NULL((void*)0);
826 DBTYPE dbtype = DB_UNKNOWN;
827 uint32_t oflags;
828 static int _lockdbfd = 0;
829
830 if (dbip)
831 *dbip = NULL((void*)0);
832
833 if ((dbi = dbiNew(rdb, rpmtag)) == NULL((void*)0))
834 return 1;
835
836 /*
837 * Parse db configuration parameters.
838 */
839 dbConfigure(rpmtag, rdb->db_dbenv == NULL((void*)0) ? &rdb->cfg : NULL((void*)0), &dbi->cfg);
840
841 /*
842 * Map open mode flags onto configured database/environment flags.
843 */
844 oflags = dbi->cfg.dbi_oflags;
845 if ((rdb->db_mode & O_ACCMODE0003) == O_RDONLY00)
846 oflags |= DB_RDONLY0x00000400;
847
848 rc = db_init(rdb, dbhome);
849
850 retry_open = (rc == 0) ? 2 : 0;
851
852 while (retry_open) {
853 rc = db_create(&db, rdb->db_dbenv, 0);
854 rc = cvtdberr(dbi, "db_create", rc, _debug);
855
856 /* For verify we only want the handle, not an open db */
857 if (verifyonly)
858 break;
859
860 if (rc == 0 && db != NULL((void*)0)) {
861 int _printit;
862 char *dbfs = prDbiOpenFlags(oflags, 0);
863 rpmlog(RPMLOG_DEBUG, "opening db index %s/%s %s mode=0x%x\n",
864 dbhome, dbi->dbi_file, dbfs, rdb->db_mode);
865 free(dbfs);
866
867 rc = (db->open)(db, NULL((void*)0), dbi->dbi_file, NULL((void*)0),
868 dbtype, oflags, rdb->db_perms);
869
870 /* Attempt to create if missing, discarding DB_RDONLY (!) */
871 if (rc == ENOENT2) {
872 oflags |= DB_CREATE0x00000001;
873 oflags &= ~DB_RDONLY0x00000400;
874 dbtype = (rpmtag == RPMDBI_PACKAGES) ? DB_HASH : DB_BTREE;
875 retry_open--;
876 } else {
877 retry_open = 0;
878 }
879
880 /* XXX return rc == errno without printing */
881 _printit = (rc > 0 ? 0 : _debug);
882 rc = cvtdberr(dbi, "db->open", rc, _printit);
883
884 /* Validate the index type is something we can support */
885 if ((rc == 0) && (dbtype == DB_UNKNOWN)) {
886 db->get_type(db, &dbtype);
887 if (dbtype != DB_HASH && dbtype != DB_BTREE) {
888 rpmlog(RPMLOG_ERR, _("invalid index type %x on %s/%s\n")dcgettext ("rpm", "invalid index type %x on %s/%s\n", 5),
889 dbtype, dbhome, dbi->dbi_file);
890 rc = 1;
891 }
892 }
893
894 if (rc != 0) {
895 db->close(db, 0);
896 db = NULL((void*)0);
897 }
898 }
899 }
900
901 dbi->dbi_db = db;
902
903 dbi->dbi_flags = 0;
904 if (oflags & DB_CREATE0x00000001)
905 dbi->dbi_flags |= DBI_CREATED;
906 if (oflags & DB_RDONLY0x00000400)
907 dbi->dbi_flags |= DBI_RDONLY;
908
909 if (!verifyonly && rc == 0 && dbi->cfg.dbi_lockdbfd && _lockdbfd++ == 0) {
910 rc = dbiFlock(dbi, rdb->db_mode);
911 }
912
913 if (rc == 0 && dbi->dbi_db != NULL((void*)0) && dbip != NULL((void*)0)) {
914 *dbip = dbi;
915 } else {
916 (void) dbiClose(dbi, 0);
917 }
918
919 return rc;
920}
921
922union _dbswap {
923 unsigned int ui;
924 unsigned char uc[4];
925};
926
927#define _DBSWAP(_a){ unsigned char _b, *_c = (_a).uc; _b = _c[3]; _c[3] = _c[0];
_c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
\
928\
929 { unsigned char _b, *_c = (_a).uc; \
930 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
931 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
932\
933 }
934
935/**
936 * Convert retrieved data to index set.
937 * @param dbi index database handle
938 * @param data retrieved data
939 * @retval setp (malloc'ed) index set
940 * @return 0 on success
941 */
942static int dbt2set(dbiIndex dbi, DBT * data, dbiIndexSet * setp)
943{
944 int _dbbyteswapped = dbiByteSwapped(dbi);
945 const char * sdbir;
946 dbiIndexSet set;
947 unsigned int i;
948
949 if (dbi == NULL((void*)0) || data == NULL((void*)0) || setp == NULL((void*)0))
950 return -1;
951
952 if ((sdbir = data->data) == NULL((void*)0)) {
953 *setp = NULL((void*)0);
954 return 0;
955 }
956
957 set = dbiIndexSetNew(data->size / (2 * sizeof(int32_t)));
958 set->count = data->size / (2 * sizeof(int32_t));
959
960 for (i = 0; i < set->count; i++) {
961 union _dbswap hdrNum, tagNum;
962
963 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
964 sdbir += sizeof(hdrNum.ui);
965 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
966 sdbir += sizeof(tagNum.ui);
967 if (_dbbyteswapped) {
968 _DBSWAP(hdrNum){ unsigned char _b, *_c = (hdrNum).uc; _b = _c[3]; _c[3] = _c
[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
969 _DBSWAP(tagNum){ unsigned char _b, *_c = (tagNum).uc; _b = _c[3]; _c[3] = _c
[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
970 }
971 set->recs[i].hdrNum = hdrNum.ui;
972 set->recs[i].tagNum = tagNum.ui;
973 }
974 *setp = set;
975 return 0;
976}
977
978/**
979 * Convert index set to database representation.
980 * @param dbi index database handle
981 * @param data retrieved data
982 * @param set index set
983 * @return 0 on success
984 */
985static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
986{
987 int _dbbyteswapped = dbiByteSwapped(dbi);
988 char * tdbir;
989 unsigned int i;
990
991 if (dbi == NULL((void*)0) || data == NULL((void*)0) || set == NULL((void*)0))
992 return -1;
993
994 data->size = set->count * (2 * sizeof(int32_t));
995 if (data->size == 0) {
996 data->data = NULL((void*)0);
997 return 0;
998 }
999 tdbir = data->data = xmalloc(data->size)rmalloc((data->size));
1000
1001 for (i = 0; i < set->count; i++) {
1002 union _dbswap hdrNum, tagNum;
1003
1004 memset(&hdrNum, 0, sizeof(hdrNum));
1005 memset(&tagNum, 0, sizeof(tagNum));
1006 hdrNum.ui = set->recs[i].hdrNum;
1007 tagNum.ui = set->recs[i].tagNum;
1008 if (_dbbyteswapped) {
1009 _DBSWAP(hdrNum){ unsigned char _b, *_c = (hdrNum).uc; _b = _c[3]; _c[3] = _c
[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
1010 _DBSWAP(tagNum){ unsigned char _b, *_c = (tagNum).uc; _b = _c[3]; _c[3] = _c
[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
1011 }
1012 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
1013 tdbir += sizeof(hdrNum.ui);
1014 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
1015 tdbir += sizeof(tagNum.ui);
1016 }
1017 return 0;
1018}
1019
1020static rpmRC db3_idxdbGet(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
1021 dbiIndexSet *set, int searchType)
1022{
1023 rpmRC rc = RPMRC_FAIL; /* assume failure */
1024 if (dbi != NULL((void*)0) && dbc != NULL((void*)0) && set != NULL((void*)0)) {
1
Assuming 'dbi' is not equal to NULL
2
Assuming 'dbc' is not equal to NULL
3
Assuming 'set' is not equal to NULL
4
Taking true branch
1025 int cflags = DB_NEXT16;
1026 int dbrc;
1027 DBT data, key;
1028 memset(&data, 0, sizeof(data));
1029 memset(&key, 0, sizeof(key));
1030
1031 if (keyp) {
5
Assuming 'keyp' is null
6
Taking false branch
1032 if (keylen == 0) { /* XXX "/" fixup */
1033 keyp = "";
1034 keylen = 1;
1035 }
1036 key.data = (void *) keyp; /* discards const */
1037 key.size = keylen;
1038 cflags = searchType == DBC_PREFIX_SEARCH ? DB_SET_RANGE27 : DB_SET26;
1039 }
1040
1041 for (;;) {
7
Loop condition is true. Entering loop body
1042 dbiIndexSet newset = NULL((void*)0);
1043 dbrc = dbiCursorGet(dbc, &key, &data, cflags);
1044 if (dbrc != 0)
8
Taking false branch
1045 break;
1046 if (searchType == DBC_PREFIX_SEARCH &&
9
Assuming 'searchType' is equal to DBC_PREFIX_SEARCH
1047 (key.size < keylen || memcmp(key.data, keyp, keylen) != 0))
10
Null pointer passed as an argument to a 'nonnull' parameter
1048 break;
1049 dbt2set(dbi, &data, &newset);
1050 if (*set == NULL((void*)0)) {
1051 *set = newset;
1052 } else {
1053 dbiIndexSetAppendSet(*set, newset, 0);
1054 dbiIndexSetFree(newset);
1055 }
1056 if (searchType != DBC_PREFIX_SEARCH)
1057 break;
1058 key.data = NULL((void*)0);
1059 key.size = 0;
1060 cflags = DB_NEXT16;
1061 }
1062
1063 /* fixup result status for prefix search */
1064 if (searchType == DBC_PREFIX_SEARCH) {
1065 if (dbrc == DB_NOTFOUND(-30988) && *set != NULL((void*)0) && (*set)->count > 0)
1066 dbrc = 0;
1067 else if (dbrc == 0 && (*set == NULL((void*)0) || (*set)->count == 0))
1068 dbrc = DB_NOTFOUND(-30988);
1069 }
1070
1071 if (dbrc == 0) {
1072 rc = RPMRC_OK;
1073 } else if (dbrc == DB_NOTFOUND(-30988)) {
1074 rc = RPMRC_NOTFOUND;
1075 } else {
1076 rpmlog(RPMLOG_ERR,
1077 _("error(%d) getting \"%s\" records from %s index: %s\n")dcgettext ("rpm", "error(%d) getting \"%s\" records from %s index: %s\n"
, 5)
,
1078 dbrc, keyp ? keyp : "???", dbiName(dbi), db_strerror(dbrc));
1079 }
1080 }
1081 return rc;
1082}
1083
1084/* Update secondary index. NULL set deletes the key */
1085static rpmRC updateIndex(dbiCursor dbc, const char *keyp, unsigned int keylen,
1086 dbiIndexSet set)
1087{
1088 rpmRC rc = RPMRC_FAIL;
1089
1090 if (dbc && keyp) {
1091 dbiIndex dbi = dbc->dbi;
1092 int dbrc;
1093 DBT data, key;
1094 memset(&key, 0, sizeof(data));
1095 memset(&data, 0, sizeof(data));
1096
1097 key.data = (void *) keyp; /* discards const */
1098 key.size = keylen;
1099
1100 if (set)
1101 set2dbt(dbi, &data, set);
1102
1103 if (dbiIndexSetCount(set) > 0) {
1104 dbrc = dbiCursorPut(dbc, &key, &data, DB_KEYLAST14);
1105 if (dbrc) {
1106 rpmlog(RPMLOG_ERR,
1107 _("error(%d) storing record \"%s\" into %s\n")dcgettext ("rpm", "error(%d) storing record \"%s\" into %s\n"
, 5)
,
1108 dbrc, (char*)key.data, dbiName(dbi));
1109 }
1110 free(data.data);
1111 } else {
1112 dbrc = dbiCursorDel(dbc, &key, &data, 0);
1113 if (dbrc) {
1114 rpmlog(RPMLOG_ERR,
1115 _("error(%d) removing record \"%s\" from %s\n")dcgettext ("rpm", "error(%d) removing record \"%s\" from %s\n"
, 5)
,
1116 dbrc, (char*)key.data, dbiName(dbi));
1117 }
1118 }
1119
1120 if (dbrc == 0)
1121 rc = RPMRC_OK;
1122 }
1123
1124 return rc;
1125}
1126
1127static rpmRC db3_idxdbPut(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
1128 dbiIndexItem rec)
1129{
1130 dbiIndexSet set = NULL((void*)0);
1131 rpmRC rc;
1132
1133 if (keyp && keylen == 0) { /* XXX "/" fixup */
1134 keyp = "";
1135 keylen++;
1136 }
1137 rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
1138
1139 /* Not found means a new key and is not an error. */
1140 if (rc && rc != RPMRC_NOTFOUND)
1141 return rc;
1142
1143 if (set == NULL((void*)0))
1144 set = dbiIndexSetNew(1);
1145 dbiIndexSetAppend(set, rec, 1, 0);
1146
1147 rc = updateIndex(dbc, keyp, keylen, set);
1148
1149 dbiIndexSetFree(set);
1150 return rc;
1151}
1152
1153static rpmRC db3_idxdbDel(dbiIndex dbi, dbiCursor dbc, const char *keyp, size_t keylen,
1154 dbiIndexItem rec)
1155{
1156 dbiIndexSet set = NULL((void*)0);
1157 rpmRC rc;
1158
1159 if (keyp && keylen == 0) { /* XXX "/" fixup */
1160 keyp = "";
1161 keylen++;
1162 }
1163 rc = idxdbGet(dbi, dbc, keyp, keylen, &set, DBC_NORMAL_SEARCH);
1164 if (rc)
1165 return rc;
1166
1167 if (dbiIndexSetPrune(set, rec, 1, 1)) {
1168 /* Nothing was pruned. XXX: Can this actually happen? */
1169 rc = RPMRC_OK;
1170 } else {
1171 /* If there's data left, update data. Otherwise delete the key. */
1172 if (dbiIndexSetCount(set) > 0) {
1173 rc = updateIndex(dbc, keyp, keylen, set);
1174 } else {
1175 rc = updateIndex(dbc, keyp, keylen, NULL((void*)0));
1176 }
1177 };
1178 dbiIndexSetFree(set);
1179
1180 return rc;
1181}
1182
1183static const void * db3_idxdbKey(dbiIndex dbi, dbiCursor dbc, unsigned int *keylen)
1184{
1185 const void *key = NULL((void*)0);
1186 if (dbc) {
1187 key = dbc->key;
1188 if (key && keylen)
1189 *keylen = dbc->keylen;
1190 }
1191 return key;
1192}
1193
1194
1195/* Update primary Packages index. NULL hdr means remove */
1196static rpmRC updatePackages(dbiCursor dbc, unsigned int hdrNum, DBT *hdr)
1197{
1198 union _dbswap mi_offset;
1199 int rc = 0;
1200 DBT key;
1201
1202 if (dbc == NULL((void*)0) || hdrNum == 0)
1203 return RPMRC_FAIL;
1204
1205 memset(&key, 0, sizeof(key));
1206
1207 mi_offset.ui = hdrNum;
1208 if (dbiByteSwapped(dbc->dbi) == 1)
1209 _DBSWAP(mi_offset){ unsigned char _b, *_c = (mi_offset).uc; _b = _c[3]; _c[3] =
_c[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
1210 key.data = (void *) &mi_offset;
1211 key.size = sizeof(mi_offset.ui);
1212
1213 if (hdr) {
1214 rc = dbiCursorPut(dbc, &key, hdr, DB_KEYLAST14);
1215 if (rc) {
1216 rpmlog(RPMLOG_ERR,
1217 _("error(%d) adding header #%d record\n")dcgettext ("rpm", "error(%d) adding header #%d record\n", 5), rc, hdrNum);
1218 }
1219 } else {
1220 DBT data;
1221
1222 memset(&data, 0, sizeof(data));
1223 rc = dbiCursorGet(dbc, &key, &data, DB_SET26);
1224 if (rc) {
1225 rpmlog(RPMLOG_ERR,
1226 _("error(%d) removing header #%d record\n")dcgettext ("rpm", "error(%d) removing header #%d record\n", 5
)
, rc, hdrNum);
1227 } else
1228 rc = dbiCursorDel(dbc, &key, &data, 0);
1229 }
1230
1231 return rc == 0 ? RPMRC_OK : RPMRC_FAIL;
1232}
1233
1234/* Get current header instance number or try to allocate a new one */
1235static unsigned int pkgInstance(dbiIndex dbi, int alloc)
1236{
1237 unsigned int hdrNum = 0;
1238
1239 if (dbi != NULL((void*)0) && dbi->dbi_type == DBI_PRIMARY) {
1240 dbiCursor dbc;
1241 DBT key, data;
1242 unsigned int firstkey = 0;
1243 union _dbswap mi_offset;
1244 int ret;
1245
1246 memset(&key, 0, sizeof(key));
1247 memset(&data, 0, sizeof(data));
1248
1249 dbc = dbiCursorInit(dbi, alloc ? DBC_WRITE : 0);
1250
1251 /* Key 0 holds the current largest instance, fetch it */
1252 key.data = &firstkey;
1253 key.size = sizeof(firstkey);
1254 ret = dbiCursorGet(dbc, &key, &data, DB_SET26);
1255
1256 if (ret == 0 && data.data) {
1257 memcpy(&mi_offset, data.data, sizeof(mi_offset.ui));
1258 if (dbiByteSwapped(dbi) == 1)
1259 _DBSWAP(mi_offset){ unsigned char _b, *_c = (mi_offset).uc; _b = _c[3]; _c[3] =
_c[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
1260 hdrNum = mi_offset.ui;
1261 }
1262
1263 if (alloc) {
1264 /* Rather complicated "increment by one", bswapping as needed */
1265 ++hdrNum;
1266 mi_offset.ui = hdrNum;
1267 if (dbiByteSwapped(dbi) == 1)
1268 _DBSWAP(mi_offset){ unsigned char _b, *_c = (mi_offset).uc; _b = _c[3]; _c[3] =
_c[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
1269 if (ret == 0 && data.data) {
1270 memcpy(data.data, &mi_offset, sizeof(mi_offset.ui));
1271 } else {
1272 data.data = &mi_offset;
1273 data.size = sizeof(mi_offset.ui);
1274 }
1275
1276 /* Unless we manage to insert the new instance number, we failed */
1277 ret = dbiCursorPut(dbc, &key, &data, DB_KEYLAST14);
1278 if (ret) {
1279 hdrNum = 0;
1280 rpmlog(RPMLOG_ERR,
1281 _("error(%d) allocating new package instance\n")dcgettext ("rpm", "error(%d) allocating new package instance\n"
, 5)
, ret);
1282 }
1283 }
1284 dbiCursorFree(dbi, dbc);
1285 }
1286
1287 return hdrNum;
1288}
1289
1290static rpmRC db3_pkgdbPut(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
1291 unsigned char *hdrBlob, unsigned int hdrLen)
1292{
1293 DBT hdr;
1294 memset(&hdr, 0, sizeof(hdr));
1295 hdr.data = hdrBlob;
1296 hdr.size = hdrLen;
1297 return updatePackages(dbc, hdrNum, &hdr);
1298}
1299
1300static rpmRC db3_pkgdbDel(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum)
1301{
1302 return updatePackages(dbc, hdrNum, NULL((void*)0));
1303}
1304
1305static rpmRC db3_pkgdbGet(dbiIndex dbi, dbiCursor dbc, unsigned int hdrNum,
1306 unsigned char **hdrBlob, unsigned int *hdrLen)
1307{
1308 DBT key, data;
1309 union _dbswap mi_offset;
1310 int rc;
1311
1312 if (dbc == NULL((void*)0))
1313 return RPMRC_FAIL;
1314
1315 memset(&key, 0, sizeof(key));
1316 memset(&data, 0, sizeof(data));
1317
1318 if (hdrNum) {
1319 mi_offset.ui = hdrNum;
1320 if (dbiByteSwapped(dbc->dbi) == 1)
1321 _DBSWAP(mi_offset){ unsigned char _b, *_c = (mi_offset).uc; _b = _c[3]; _c[3] =
_c[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
1322 key.data = (void *) &mi_offset;
1323 key.size = sizeof(mi_offset.ui);
1324 }
1325
1326#if !defined(_USE_COPY_LOAD)
1327 data.flags |= DB_DBT_MALLOC0x010;
1328#endif
1329 rc = dbiCursorGet(dbc, &key, &data, hdrNum ? DB_SET26 : DB_NEXT16);
1330 if (rc == 0) {
1331 if (hdrBlob)
1332 *hdrBlob = data.data;
1333 if (hdrLen)
1334 *hdrLen = data.size;
1335 return RPMRC_OK;
1336 } else if (rc == DB_NOTFOUND(-30988))
1337 return RPMRC_NOTFOUND;
1338 else
1339 return RPMRC_FAIL;
1340}
1341
1342static unsigned int db3_pkgdbKey(dbiIndex dbi, dbiCursor dbc)
1343{
1344 union _dbswap mi_offset;
1345
1346 if (dbc == NULL((void*)0) || dbc->key == NULL((void*)0))
1347 return 0;
1348 memcpy(&mi_offset, dbc->key, sizeof(mi_offset.ui));
1349 if (dbiByteSwapped(dbc->dbi) == 1)
1350 _DBSWAP(mi_offset){ unsigned char _b, *_c = (mi_offset).uc; _b = _c[3]; _c[3] =
_c[0]; _c[0] = _b; _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; }
;
1351 return mi_offset.ui;
1352}
1353
1354static rpmRC db3_pkgdbNew(dbiIndex dbi, dbiCursor dbc, unsigned int *hdrNum)
1355{
1356 unsigned int num;
1357 if (dbc == NULL((void*)0))
1358 return RPMRC_FAIL;
1359 num = pkgInstance(dbc->dbi, 1);
1360 if (!num)
1361 return RPMRC_FAIL;
1362 *hdrNum = num;
1363 return RPMRC_OK;
1364}
1365
1366struct rpmdbOps_s db3_dbops = {
1367 .open = db3_dbiOpen,
1368 .close = db3_dbiClose,
1369 .verify = db3_dbiVerify,
1370
1371 .setFSync = db3_dbSetFSync,
1372 .ctrl = db3_Ctrl,
1373
1374 .cursorInit = db3_dbiCursorInit,
1375 .cursorFree = db3_dbiCursorFree,
1376
1377 .pkgdbGet = db3_pkgdbGet,
1378 .pkgdbPut = db3_pkgdbPut,
1379 .pkgdbDel = db3_pkgdbDel,
1380 .pkgdbNew = db3_pkgdbNew,
1381 .pkgdbKey = db3_pkgdbKey,
1382
1383 .idxdbGet = db3_idxdbGet,
1384 .idxdbPut = db3_idxdbPut,
1385 .idxdbDel = db3_idxdbDel,
1386 .idxdbKey = db3_idxdbKey
1387};
1388