heim_error_t heim_error_createv(int error_code, const char *fmt, va_list ap) { heim_error_t e; char *str; int len; str = malloc(1024); if (str == NULL) return NULL; len = vsnprintf(str, 1024, fmt, ap); if (len < 0) { free(str); return NULL; } e = _heim_alloc_object(&_heim_error_object, sizeof(struct heim_error)); if (e) { e->msg = heim_string_create(str); e->error_code = error_code; } free(str); return e; }
heim_error_t heim_error_createv(int error_code, const char *fmt, va_list ap) { heim_error_t e; char *str; int len; int save_errno = errno; str = malloc(1024); errno = save_errno; if (str == NULL) return heim_error_create_enomem(); len = vsnprintf(str, 1024, fmt, ap); errno = save_errno; if (len < 0) { free(str); return NULL; /* XXX We should have a special heim_error_t for this */ } e = _heim_alloc_object(&_heim_error_object, sizeof(struct heim_error)); if (e) { e->msg = heim_string_create(str); e->error_code = error_code; } free(str); errno = save_errno; return e; }
heim_string_t heim_string_create(const char *string) { size_t len = strlen(string); heim_string_t s; s = _heim_alloc_object(&_heim_string_object, len + 1); if (s) memcpy(s, string, len + 1); return s; }
heim_string_t heim_string_create_with_bytes(const void *data, size_t len) { heim_string_t s; s = _heim_alloc_object(&_heim_string_object, len + 1); if (s) { memcpy(s, data, len); ((char *)s)[len] = '\0'; } return s; }
heim_number_t heim_number_create(int number) { heim_number_t n; if (number < 0xffffff && number >= 0) return heim_base_make_tagged_object(number, HEIM_TID_NUMBER); n = _heim_alloc_object(&_heim_number_object, sizeof(int)); if (n) *((int *)n) = number; return n; }
heim_data_t heim_data_create(const void *data, size_t length) { heim_octet_string *os; os = _heim_alloc_object(&_heim_data_object, sizeof(*os) + length); if (os) { os->data = (uint8_t *)os + sizeof(*os); os->length = length; memcpy(os->data, data, length); } return (heim_data_t)os; }
heim_array_t heim_array_create(void) { heim_array_t array; array = _heim_alloc_object(&array_object, sizeof(*array)); if (array == NULL) return NULL; array->val = NULL; array->len = 0; return array; }
heim_data_t heim_data_ref_create(const void *data, size_t length, heim_data_free_f_t dealloc) { heim_octet_string *os; heim_data_free_f_t *deallocp; os = _heim_alloc_object(&_heim_data_object, sizeof(*os) + length); if (os) { os->data = (void *)data; os->length = length; deallocp = _heim_get_isaextra(os, 0); *deallocp = dealloc; } return (heim_data_t)os; }
heim_string_t heim_string_ref_create(const char *string, heim_string_free_f_t dealloc) { heim_string_t s; heim_string_free_f_t *deallocp; s = _heim_alloc_object(&_heim_string_object, 1); if (s) { const char **strp; ((char *)s)[0] = '\0'; deallocp = _heim_get_isaextra(s, 0); *deallocp = dealloc; strp = _heim_get_isaextra(s, 1); *strp = string; } return s; }
heim_dict_t heim_dict_create(size_t size) { heim_dict_t dict; dict = _heim_alloc_object(&dict_object, sizeof(*dict)); dict->size = findprime(size); if (dict->size == 0) { heim_release(dict); return NULL; } dict->tab = calloc(dict->size, sizeof(dict->tab[0])); if (dict->tab == NULL) { dict->size = 0; heim_release(dict); return NULL; } return dict; }
/** * Clone (duplicate) an open DB handle. * * This is useful for multi-threaded applications. Applications must * synchronize access to any given DB handle. * * Returns EBUSY if there is an open transaction for the input db. * * @param db Open DB handle * @param error Output error object * * @return a DB handle * * @addtogroup heimbase */ heim_db_t heim_db_clone(heim_db_t db, heim_error_t *error) { heim_db_t result; int ret; if (heim_get_tid(db) != HEIM_TID_DB) heim_abort("Expected a database"); if (db->in_transaction) heim_abort("DB handle is busy"); if (db->plug->clonef == NULL) { return heim_db_create(heim_string_get_utf8(db->dbtype), heim_string_get_utf8(db->dbname), db->options, error); } result = _heim_alloc_object(&db_object, sizeof(*result)); if (result == NULL) { if (error) *error = heim_error_create_enomem(); return NULL; } result->set_keys = NULL; result->del_keys = NULL; ret = db->plug->clonef(db->db_data, &result->db_data, error); if (ret) { heim_release(result); if (error && !*error) *error = heim_error_create(ENOENT, N_("Could not re-open DB while cloning", "")); return NULL; } db->db_data = NULL; return result; }
/** * Open a database of the given dbtype. * * Database type names can be composed of one or more pseudo-DB types * and one concrete DB type joined with a '+' between each. For * example: "transaction+bdb" might be a Berkeley DB with a layer above * that provides transactions. * * Options may be provided via a dict (an associative array). Existing * options include: * * - "create", with any value (create if DB doesn't exist) * - "exclusive", with any value (exclusive create) * - "truncate", with any value (truncate the DB) * - "read-only", with any value (disallow writes) * - "sync", with any value (make transactions durable) * - "journal-name", with a string value naming a journal file name * * @param dbtype Name of DB type * @param dbname Name of DB (likely a file path) * @param options Options dict * @param db Output open DB handle * @param error Output error object * * @return a DB handle * * @addtogroup heimbase */ heim_db_t heim_db_create(const char *dbtype, const char *dbname, heim_dict_t options, heim_error_t *error) { heim_string_t s; char *p; db_plugin plug; heim_db_t db; int ret = 0; if (options == NULL) { options = heim_dict_create(11); if (options == NULL) { if (error) *error = heim_error_create_enomem(); return NULL; } } else { (void) heim_retain(options); } if (db_plugins == NULL) { heim_release(options); return NULL; } if (dbtype == NULL || *dbtype == '\0') { struct dbtype_iter iter_ctx = { NULL, dbname, options, error}; /* Try all dbtypes */ heim_dict_iterate_f(db_plugins, &iter_ctx, dbtype_iter2create_f); heim_release(options); return iter_ctx.db; } else if (strstr(dbtype, "json")) { (void) heim_db_register(dbtype, NULL, &json_dbt); } /* * Allow for dbtypes that are composed from pseudo-dbtypes chained * to a real DB type with '+'. For example a pseudo-dbtype might * add locking, transactions, transcoding of values, ... */ p = strchr(dbtype, '+'); if (p != NULL) s = heim_string_create_with_bytes(dbtype, p - dbtype); else s = heim_string_create(dbtype); if (s == NULL) { heim_release(options); return NULL; } HEIMDAL_MUTEX_lock(&db_type_mutex); plug = heim_dict_get_value(db_plugins, s); HEIMDAL_MUTEX_unlock(&db_type_mutex); heim_release(s); if (plug == NULL) { if (error) *error = heim_error_create(ENOENT, N_("Heimdal DB plugin not found: %s", ""), dbtype); heim_release(options); return NULL; } db = _heim_alloc_object(&db_object, sizeof(*db)); if (db == NULL) { heim_release(options); return NULL; } db->in_transaction = 0; db->ro_tx = 0; db->set_keys = NULL; db->del_keys = NULL; db->plug = plug; db->options = options; ret = plug->openf(plug->data, dbtype, dbname, options, &db->db_data, error); if (ret) { heim_release(db); if (error && *error == NULL) *error = heim_error_create(ENOENT, N_("Heimdal DB could not be opened: %s", ""), dbname); return NULL; } ret = db_replay_log(db, error); if (ret) { heim_release(db); return NULL; } if (plug->clonef == NULL) { db->dbtype = heim_string_create(dbtype); db->dbname = heim_string_create(dbname); if (!db->dbtype || ! db->dbname) { heim_release(db); if (error) *error = heim_error_create_enomem(); return NULL; } } return db; }