- } else if (!check_header_hash(tdb, !hash_fn, &magic1, &magic2)) {
- TDB1_LOG((tdb, TDB1_DEBUG_FATAL, "tdb1_open_ex: "
- "%s was not created with %s hash function we are using\n"
- "magic1_hash[0x%08X %s 0x%08X] "
- "magic2_hash[0x%08X %s 0x%08X]\n",
- name, hash_alg,
- tdb->header.magic1_hash,
- (tdb->header.magic1_hash == magic1) ? "==" : "!=",
- magic1,
- tdb->header.magic2_hash,
- (tdb->header.magic2_hash == magic2) ? "==" : "!=",
- magic2));
- errno = EINVAL;
- goto fail;
- }
-
- /* Is it already in the open list? If so, fail. */
- if (tdb1_already_open(st.st_dev, st.st_ino)) {
- TDB1_LOG((tdb, TDB1_DEBUG_ERROR, "tdb1_open_ex: "
- "%s (%d,%d) is already open in this process\n",
- name, (int)st.st_dev, (int)st.st_ino));
- errno = EBUSY;
- goto fail;
- }
-
- tdb->map_size = st.st_size;
- tdb->device = st.st_dev;
- tdb->inode = st.st_ino;
- tdb1_mmap(tdb);
- if (locked) {
- if (tdb1_nest_unlock(tdb, TDB1_ACTIVE_LOCK, F_WRLCK, false) == -1) {
- TDB1_LOG((tdb, TDB1_DEBUG_ERROR, "tdb1_open_ex: "
- "failed to release ACTIVE_LOCK on %s: %s\n",
- name, strerror(errno)));
- goto fail;
- }
-
- }
-
- /* We always need to do this if the CLEAR_IF_FIRST flag is set, even if
- we didn't get the initial exclusive lock as we need to let all other
- users know we're using it. */
-
- if (tdb1_flags & TDB1_CLEAR_IF_FIRST) {
- /* leave this lock in place to indicate it's in use */
- if (tdb1_nest_lock(tdb, TDB1_ACTIVE_LOCK, F_RDLCK, TDB1_LOCK_WAIT) == -1) {
- goto fail;
- }
- }
-
- /* if needed, run recovery */
- if (tdb1_transaction_recover(tdb) == -1) {
- goto fail;
- }
-
- internal:
- /* Internal (memory-only) databases skip all the code above to
- * do with disk files, and resume here by releasing their
- * open lock and hooking into the active list. */
- if (tdb1_nest_unlock(tdb, TDB1_OPEN_LOCK, F_WRLCK, false) == -1) {
- goto fail;
- }
- tdb->next = tdb1s;
- tdb1s = tdb;
- return tdb;
-
- fail:
- { int save_errno = errno;
-
- if (!tdb)
- return NULL;
-
- if (tdb->map_ptr) {
- if (tdb->flags & TDB1_INTERNAL)
- SAFE_FREE(tdb->map_ptr);
- else
- tdb1_munmap(tdb);
- }
- if (tdb->fd != -1)
- if (close(tdb->fd) != 0)
- TDB1_LOG((tdb, TDB1_DEBUG_ERROR, "tdb1_open_ex: failed to close tdb->fd on error!\n"));
- SAFE_FREE(tdb->lockrecs);
- SAFE_FREE(tdb->name);
- SAFE_FREE(tdb);
- errno = save_errno;
- return NULL;
- }
-}
-
-/*
- * Set the maximum number of dead records per hash chain
- */
-
-_PUBLIC_ void tdb1_set_max_dead(struct tdb1_context *tdb, int max_dead)
-{
- tdb->max_dead_records = max_dead;
-}
-
-/**
- * Close a database.
- *
- * @returns -1 for error; 0 for success.
- **/
-_PUBLIC_ int tdb1_close(struct tdb1_context *tdb)
-{
- struct tdb1_context **i;
- int ret = 0;
-
- if (tdb->transaction) {
- tdb1_transaction_cancel(tdb);
- }
-
- if (tdb->map_ptr) {
- if (tdb->flags & TDB1_INTERNAL)
- SAFE_FREE(tdb->map_ptr);
- else
- tdb1_munmap(tdb);
- }
- SAFE_FREE(tdb->name);
- if (tdb->fd != -1) {
- ret = close(tdb->fd);
- tdb->fd = -1;
- }
- SAFE_FREE(tdb->lockrecs);
-
- /* Remove from contexts list */
- for (i = &tdb1s; *i; i = &(*i)->next) {
- if (*i == tdb) {
- *i = tdb->next;
- break;
- }
- }
-
- memset(tdb, 0, sizeof(*tdb));
- SAFE_FREE(tdb);
-
- return ret;
-}
-
-/* register a loging function */
-_PUBLIC_ void tdb1_set_logging_function(struct tdb1_context *tdb,
- const struct tdb1_logging_context *log_ctx)
-{
- tdb->log = *log_ctx;
-}
-
-_PUBLIC_ void *tdb1_get_logging_private(struct tdb1_context *tdb)
-{
- return tdb->log.log_private;
-}
-
-static int tdb1_reopen_internal(struct tdb1_context *tdb, bool active_lock)
-{
-#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
- !defined(LIBREPLACE_PWRITE_NOT_REPLACED)
- struct stat st;
-#endif
-
- if (tdb->flags & TDB1_INTERNAL) {
- return 0; /* Nothing to do. */
- }
-
- if (tdb1_have_extra_locks(tdb)) {
- TDB1_LOG((tdb, TDB1_DEBUG_ERROR, "tdb1_reopen: reopen not allowed with locks held\n"));
- goto fail;
- }
-
- if (tdb->transaction != 0) {
- TDB1_LOG((tdb, TDB1_DEBUG_ERROR, "tdb1_reopen: reopen not allowed inside a transaction\n"));
- goto fail;
- }
-
-/* If we have real pread & pwrite, we can skip reopen. */
-#if !defined(LIBREPLACE_PREAD_NOT_REPLACED) || \
- !defined(LIBREPLACE_PWRITE_NOT_REPLACED)
- if (tdb1_munmap(tdb) != 0) {
- TDB1_LOG((tdb, TDB1_DEBUG_FATAL, "tdb1_reopen: munmap failed (%s)\n", strerror(errno)));
- goto fail;
- }
- if (close(tdb->fd) != 0)
- TDB1_LOG((tdb, TDB1_DEBUG_FATAL, "tdb1_reopen: WARNING closing tdb->fd failed!\n"));
- tdb->fd = open(tdb->name, tdb->open_flags & ~(O_CREAT|O_TRUNC), 0);
- if (tdb->fd == -1) {
- TDB1_LOG((tdb, TDB1_DEBUG_FATAL, "tdb1_reopen: open failed (%s)\n", strerror(errno)));
- goto fail;
- }
- if (fstat(tdb->fd, &st) != 0) {
- TDB1_LOG((tdb, TDB1_DEBUG_FATAL, "tdb1_reopen: fstat failed (%s)\n", strerror(errno)));
- goto fail;
- }
- if (st.st_ino != tdb->inode || st.st_dev != tdb->device) {
- TDB1_LOG((tdb, TDB1_DEBUG_FATAL, "tdb1_reopen: file dev/inode has changed!\n"));
- goto fail;
- }
- tdb1_mmap(tdb);
-#endif /* fake pread or pwrite */
-
- /* We may still think we hold the active lock. */
- tdb->num_lockrecs = 0;
- SAFE_FREE(tdb->lockrecs);
-
- if (active_lock && tdb1_nest_lock(tdb, TDB1_ACTIVE_LOCK, F_RDLCK, TDB1_LOCK_WAIT) == -1) {
- TDB1_LOG((tdb, TDB1_DEBUG_FATAL, "tdb1_reopen: failed to obtain active lock\n"));
- goto fail;
- }
-
- return 0;
-
-fail:
- tdb1_close(tdb);
- return -1;
-}
-
-/* reopen a tdb - this can be used after a fork to ensure that we have an independent
- seek pointer from our parent and to re-establish locks */
-_PUBLIC_ int tdb1_reopen(struct tdb1_context *tdb)
-{
- return tdb1_reopen_internal(tdb, tdb->flags & TDB1_CLEAR_IF_FIRST);
-}