#include "private.h"
+#include <assert.h>
/* all lock info, to detect double-opens (fcntl file don't nest!) */
static struct tdb_file *files = NULL;
for (i = files; i; i = i->next) {
if (i->device == device && i->inode == ino) {
+ i->refcnt++;
break;
}
}
tdb->hash_priv);
newdb.hdr.recovery = 0;
newdb.hdr.features_used = newdb.hdr.features_offered = TDB_FEATURE_MASK;
+ newdb.hdr.seqnum = 0;
memset(newdb.hdr.reserved, 0, sizeof(newdb.hdr.reserved));
/* Initial hashes are empty. */
memset(newdb.hdr.hashtable, 0, sizeof(newdb.hdr.hashtable));
tdb->file->num_lockrecs = 0;
tdb->file->lockrecs = NULL;
tdb->file->allrecord_lock.count = 0;
+ tdb->file->refcnt = 1;
return TDB_SUCCESS;
}
tdb->transaction = NULL;
tdb->stats = NULL;
tdb->access = NULL;
+ tdb->last_error = TDB_SUCCESS;
tdb->file = NULL;
tdb_hash_init(tdb);
tdb_io_init(tdb);
}
if (tdb_flags & ~(TDB_INTERNAL | TDB_NOLOCK | TDB_NOMMAP | TDB_CONVERT
- | TDB_NOSYNC)) {
+ | TDB_NOSYNC | TDB_SEQNUM)) {
ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
"tdb_open: unknown flags %u", tdb_flags);
goto fail;
if (ecode != TDB_SUCCESS) {
goto fail;
}
+ if (name) {
+ tdb->name = strdup(name);
+ if (!tdb->name) {
+ ecode = tdb_logerr(tdb, TDB_ERR_OOM,
+ TDB_LOG_ERROR,
+ "tdb_open: failed to"
+ " allocate name");
+ goto fail;
+ }
+ }
tdb_convert(tdb, &hdr.hash_seed, sizeof(hdr.hash_seed));
tdb->hash_seed = hdr.hash_seed;
tdb_ftable_init(tdb);
tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
"tdb_open: could not open file %s: %s",
name, strerror(errno));
- goto fail;
+ goto fail_errno;
}
/* on exec, don't inherit the fd */
tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
"tdb_open: could not stat open %s: %s",
name, strerror(errno));
- goto fail;
+ goto fail_errno;
}
ecode = tdb_new_file(tdb);
tdb->file->inode = st.st_ino;
tdb->file->map_ptr = NULL;
tdb->file->map_size = sizeof(struct tdb_header);
- } else {
- /* FIXME */
- ecode = tdb_logerr(tdb, TDB_ERR_EINVAL, TDB_LOG_USE_ERROR,
- "tdb_open: %s (%d,%d) is already open in"
- " this process",
- name, (int)st.st_dev, (int)st.st_ino);
- goto fail;
}
/* ensure there is only one process initialising at once */
}
/* If they used O_TRUNC, read will return 0. */
- rlen = read(tdb->file->fd, &hdr, sizeof(hdr));
+ rlen = pread(tdb->file->fd, &hdr, sizeof(hdr), 0);
if (rlen == 0 && (open_flags & O_CREAT)) {
ecode = tdb_new_database(tdb, seed, &hdr);
if (ecode != TDB_SUCCESS) {
goto fail;
}
- /* Add to linked list. */
- files = tdb->file;
+ /* Add to linked list if we're new. */
+ if (tdb->file->refcnt == 1)
+ files = tdb->file;
return tdb;
fail:
/* Map ecode to some logical errno. */
- if (!saved_errno) {
- switch (ecode) {
- case TDB_ERR_CORRUPT:
- case TDB_ERR_IO:
- saved_errno = EIO;
- break;
- case TDB_ERR_LOCK:
- saved_errno = EWOULDBLOCK;
- break;
- case TDB_ERR_OOM:
- saved_errno = ENOMEM;
- break;
- case TDB_ERR_EINVAL:
- saved_errno = EINVAL;
- break;
- default:
- saved_errno = EINVAL;
- break;
- }
+ switch (ecode) {
+ case TDB_ERR_CORRUPT:
+ case TDB_ERR_IO:
+ saved_errno = EIO;
+ break;
+ case TDB_ERR_LOCK:
+ saved_errno = EWOULDBLOCK;
+ break;
+ case TDB_ERR_OOM:
+ saved_errno = ENOMEM;
+ break;
+ case TDB_ERR_EINVAL:
+ saved_errno = EINVAL;
+ break;
+ default:
+ saved_errno = EINVAL;
+ break;
}
+fail_errno:
#ifdef TDB_TRACE
close(tdb->tracefd);
#endif
- free((char *)tdb->name);
+ free(cast_const(char *, tdb->name));
if (tdb->file) {
- tdb_unlock_all(tdb);
- if (tdb->file->map_ptr) {
- if (tdb->flags & TDB_INTERNAL) {
- free(tdb->file->map_ptr);
- } else
- tdb_munmap(tdb->file);
+ tdb_lock_cleanup(tdb);
+ if (--tdb->file->refcnt == 0) {
+ assert(tdb->file->num_lockrecs == 0);
+ if (tdb->file->map_ptr) {
+ if (tdb->flags & TDB_INTERNAL) {
+ free(tdb->file->map_ptr);
+ } else
+ tdb_munmap(tdb->file);
+ }
+ if (close(tdb->file->fd) != 0)
+ tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
+ "tdb_open: failed to close tdb fd"
+ " on error: %s", strerror(errno));
+ free(tdb->file->lockrecs);
+ free(tdb->file);
}
- if (close(tdb->file->fd) != 0)
- tdb_logerr(tdb, TDB_ERR_IO, TDB_LOG_ERROR,
- "tdb_open: failed to close tdb fd"
- " on error: %s", strerror(errno));
- free(tdb->file->lockrecs);
- free(tdb->file);
}
free(tdb);
else
tdb_munmap(tdb->file);
}
- free((char *)tdb->name);
+ free(cast_const(char *, tdb->name));
if (tdb->file) {
struct tdb_file **i;
- ret = close(tdb->file->fd);
- /* Remove from files list */
- for (i = &files; *i; i = &(*i)->next) {
- if (*i == tdb->file) {
- *i = tdb->file->next;
- break;
+ tdb_lock_cleanup(tdb);
+ if (--tdb->file->refcnt == 0) {
+ ret = close(tdb->file->fd);
+
+ /* Remove from files list */
+ for (i = &files; *i; i = &(*i)->next) {
+ if (*i == tdb->file) {
+ *i = tdb->file->next;
+ break;
+ }
}
+ free(tdb->file->lockrecs);
+ free(tdb->file);
}
- free(tdb->file->lockrecs);
- free(tdb->file);
}
#ifdef TDB_TRACE