/* initialise a new database with a specified hash size */ static int tdb_new_database(struct tdb_context *tdb, struct tdb_header *header, int hash_size) { struct tdb_header *newdb; size_t size; int ret = -1; /* We make it up in memory, then write it out if not internal */ size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t); if (!(newdb = (struct tdb_header *)calloc(size, 1))) { tdb->ecode = TDB_ERR_OOM; return -1; } /* Fill in the header */ newdb->version = TDB_VERSION; newdb->hash_size = hash_size; tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash); /* Make sure older tdbs (which don't check the magic hash fields) * will refuse to open this TDB. */ if (tdb->flags & TDB_INCOMPATIBLE_HASH) newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC; if (tdb->flags & TDB_INTERNAL) { tdb->map_size = size; tdb->map_ptr = (char *)newdb; memcpy(header, newdb, sizeof(*header)); /* Convert the `ondisk' version if asked. */ CONVERT(*newdb); return 0; } if (lseek(tdb->fd, 0, SEEK_SET) == -1) goto fail; if (ftruncate(tdb->fd, 0) == -1) goto fail; /* This creates an endian-converted header, as if read from disk */ CONVERT(*newdb); memcpy(header, newdb, sizeof(*header)); /* Don't endian-convert the magic food! */ memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); if (!tdb_write_all(tdb->fd, newdb, size)) goto fail; ret = 0; fail: SAFE_FREE(newdb); return ret; }
/* initialise a new database with a specified hash size */ static int tdb_new_database(struct tdb_context *tdb, struct tdb_header *header, int hash_size) { struct tdb_header *newdb; size_t size; int ret = -1; /* We make it up in memory, then write it out if not internal */ size = sizeof(struct tdb_header) + (hash_size+1)*sizeof(tdb_off_t); if (!(newdb = (struct tdb_header *)calloc(size, 1))) { tdb->ecode = TDB_ERR_OOM; return -1; } /* Fill in the header */ newdb->version = TDB_VERSION; newdb->hash_size = hash_size; tdb_header_hash(tdb, &newdb->magic1_hash, &newdb->magic2_hash); /* Make sure older tdbs (which don't check the magic hash fields) * will refuse to open this TDB. */ if (tdb->flags & TDB_INCOMPATIBLE_HASH) newdb->rwlocks = TDB_HASH_RWLOCK_MAGIC; /* * We create a tdb with TDB_FEATURE_FLAG_MUTEX support, * the flag combination and runtime feature checks * are done by the caller already. */ if (tdb->flags & TDB_MUTEX_LOCKING) { newdb->feature_flags |= TDB_FEATURE_FLAG_MUTEX; } /* * If we have any features we add the FEATURE_FLAG_MAGIC, overwriting the * TDB_HASH_RWLOCK_MAGIC above. */ if (newdb->feature_flags != 0) { newdb->rwlocks = TDB_FEATURE_FLAG_MAGIC; } /* * It's required for some following code pathes * to have the fields on 'tdb' up-to-date. * * E.g. tdb_mutex_size() requires it */ tdb->feature_flags = newdb->feature_flags; tdb->hash_size = newdb->hash_size; if (tdb->flags & TDB_INTERNAL) { tdb->map_size = size; tdb->map_ptr = (char *)newdb; memcpy(header, newdb, sizeof(*header)); /* Convert the `ondisk' version if asked. */ CONVERT(*newdb); return 0; } if (lseek(tdb->fd, 0, SEEK_SET) == -1) goto fail; if (ftruncate(tdb->fd, 0) == -1) goto fail; if (newdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) { newdb->mutex_size = tdb_mutex_size(tdb); tdb->hdr_ofs = newdb->mutex_size; } /* This creates an endian-converted header, as if read from disk */ CONVERT(*newdb); memcpy(header, newdb, sizeof(*header)); /* Don't endian-convert the magic food! */ memcpy(newdb->magic_food, TDB_MAGIC_FOOD, strlen(TDB_MAGIC_FOOD)+1); if (!tdb_write_all(tdb->fd, newdb, size)) goto fail; if (newdb->feature_flags & TDB_FEATURE_FLAG_MUTEX) { /* * Now we init the mutex area * followed by a second header. */ ret = ftruncate( tdb->fd, newdb->mutex_size + sizeof(struct tdb_header)); if (ret == -1) { goto fail; } ret = tdb_mutex_init(tdb); if (ret == -1) { goto fail; } /* * Write a second header behind the mutexes. That's the area * that will be mmapp'ed. */ ret = lseek(tdb->fd, newdb->mutex_size, SEEK_SET); if (ret == -1) { goto fail; } if (!tdb_write_all(tdb->fd, newdb, size)) { goto fail; } } ret = 0; fail: SAFE_FREE(newdb); return ret; }