/* * Buxton * * Copyright (C) 2015 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include "buxton2.h" #include "common.h" #include "log.h" #include "direct.h" #include "config.h" #include "backends.h" #include "serialize.h" #include "cache.h" static int get_path(uid_t uid, enum buxton_layer_type type, const struct layer *ly, char *path, int sz) { const char *prefix; char suffix[16]; if (!ly || !path || sz <= 0) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } if (type == BUXTON_LAYER_NORMAL) prefix = (ly->storage == STORAGE_VOLATILE) ? TMPFS_DIR : DB_DIR; else prefix = BASE_DB_DIR; if (type == BUXTON_LAYER_NORMAL && ly->type == LAYER_USER) snprintf(suffix, sizeof(suffix), "-%u", uid); else suffix[0] = '\0'; snprintf(path, sz, "%s/%s%s.db", prefix, ly->name, suffix); return BUXTON_ERROR_NONE; } static int get_raw(const struct layer *ly, uid_t uid, enum buxton_layer_type type, const char *key, uint8_t **data, int *len) { int r; const struct backend *backend; char path[FILENAME_MAX]; if (!ly || !key || !data || !len) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = backend_get(ly->backend, &backend); if (r != BUXTON_ERROR_NONE) return r; if (!backend->get_value) { bxt_err("Get: backend '%s' has no get func", backend->name); return BUXTON_ERROR_INVALID_OPERATION; } if (cache_get(type, key, (void **)data, len) == BUXTON_ERROR_NONE) return BUXTON_ERROR_NONE; r = get_path(uid, type, ly, path, sizeof(path)); if (r != BUXTON_ERROR_NONE) return r; r = backend->get_value(path, key, (void **)data, len, (type == BUXTON_LAYER_BASE) ? true : false); if (r != BUXTON_ERROR_NONE) return r; cache_insert(type, key, *data, *len); return BUXTON_ERROR_NONE; } static int get_val(const struct layer *ly, uid_t uid, enum buxton_layer_type type, const char *key, char **rpriv, char **wpriv, struct buxton_value *val) { int r; uint8_t *data; int len; if (!ly || !key) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = get_raw(ly, uid, type, key, &data, &len); if (r != BUXTON_ERROR_NONE) return r; r = deserialz_data(data, len, rpriv, wpriv, val); free(data); return r; } int direct_get(const struct buxton_layer *layer, const char *key, struct buxton_value *val) { int r; const struct layer *ly; struct buxton_value base_val; struct buxton_value db_val; if (!layer || !key || !*key || !val) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; /* First, refer to base db */ r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, NULL, NULL, &base_val); if (r != BUXTON_ERROR_NONE) return r; if (layer->type == BUXTON_LAYER_BASE) { *val = base_val; return BUXTON_ERROR_NONE; } r = get_val(ly, layer->uid, BUXTON_LAYER_NORMAL, key, NULL, NULL, &db_val); if (r != BUXTON_ERROR_NONE) { if (r == BUXTON_ERROR_NOT_EXIST) { *val = base_val; return BUXTON_ERROR_NONE; } value_free(&base_val); return r; } value_free(&base_val); *val = db_val; return BUXTON_ERROR_NONE; } int direct_check(const struct buxton_layer *layer, const char *key) { int r; const struct layer *ly; struct buxton_value val; if (!layer || !key || !*key) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, NULL, NULL, &val); if (r != BUXTON_ERROR_NONE) return r; value_free(&val); return BUXTON_ERROR_NONE; } static bool is_updated_data(enum buxton_layer_type type, const char *key, uint8_t *data, int len) { uint8_t *cur_data; int cur_data_len; int ret; ret = cache_get(type, key, (void **)&cur_data, &cur_data_len); if (ret != BUXTON_ERROR_NONE) return false; if (cur_data_len != len) { free(cur_data); return false; } if (memcmp(cur_data, data, len)) { free(cur_data); return false; } free(cur_data); return true; } static int set_raw(const struct layer *ly, uid_t uid, enum buxton_layer_type type, const char *key, uint8_t *data, int len) { int r; const struct backend *backend; char path[FILENAME_MAX]; if (!ly || !key || !data || len <= 0) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = backend_get(ly->backend, &backend); if (r != BUXTON_ERROR_NONE) return r; if (!backend->set_value) { bxt_err("Set: backend '%s' has no set func", backend->name); return BUXTON_ERROR_INVALID_OPERATION; } if (is_updated_data(type, key, data, len)) { bxt_dbg("skip setting (same data) - (%s)", key); return BUXTON_ERROR_NONE; } r = get_path(uid, type, ly, path, sizeof(path)); if (r != BUXTON_ERROR_NONE) return r; r = backend->set_value(path, key, data, len); if (r != BUXTON_ERROR_NONE) return r; cache_update_data(type, key, data, len); return BUXTON_ERROR_NONE; } static int set_val(const struct layer *ly, uid_t uid, enum buxton_layer_type type, const char *key, const char *rpriv, const char *wpriv, const struct buxton_value *val) { int r; uint8_t *data; int len; if (!val) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = serialz_data(rpriv ? rpriv : "", wpriv ? wpriv : "", val, &data, &len); if (r != BUXTON_ERROR_NONE) return r; r = set_raw(ly, uid, type, key, data, len); free(data); return r; } int direct_set(const struct buxton_layer *layer, const char *key, const struct buxton_value *val) { int r; const struct layer *ly; char *rp; char *wp; if (!layer || !key || !*key || !val) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, &rp, &wp, NULL); if (r != BUXTON_ERROR_NONE) return r; r = set_val(ly, layer->uid, layer->type, key, rp, wp, val); free(rp); free(wp); return r; } static int direct_close(const struct buxton_layer *layer, const struct layer *ly) { int r; char path[FILENAME_MAX]; const struct backend *backend; if (!layer || !ly) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = backend_get(ly->backend, &backend); if (r != BUXTON_ERROR_NONE) return r; if (!backend->close_db) { bxt_err("DirectCreate: backend '%s' has no close_db func", backend->name); return BUXTON_ERROR_INVALID_OPERATION; } r = get_path(layer->uid, BUXTON_LAYER_BASE, ly, path, sizeof(path)); if (r != BUXTON_ERROR_NONE) return r; r = backend->close_db(path); if (r != BUXTON_ERROR_NONE) { bxt_err("DirectCreate: close_db: %s %d", buxton_err_get_str(r), r); return r; } return BUXTON_ERROR_NONE; } int direct_create(const struct buxton_layer *layer, const char *key, const char *rpriv, const char *wpriv, const struct buxton_value *val) { int r; const struct layer *ly; struct buxton_layer unset_layer; if (!layer || !key || !*key || !val) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = check_key_name(key); if (r != BUXTON_ERROR_NONE) return r; r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, NULL, NULL, NULL); if (r == BUXTON_ERROR_NONE) return BUXTON_ERROR_EXIST; r = direct_close(layer, ly); if (r != BUXTON_ERROR_NONE) { bxt_err("failed to close db(%s) %d", ly->name, r); return r; } r = set_val(ly, layer->uid, BUXTON_LAYER_BASE, key, rpriv, wpriv, val); if (r != BUXTON_ERROR_NONE) { bxt_err("failed to create (%s: %s) %d", ly->name, key, r); return r; } if (ly->storage == STORAGE_PERSISTENT) { r = set_val(ly, layer->uid, BUXTON_LAYER_NORMAL, key, rpriv, wpriv, val); if (r != BUXTON_ERROR_NONE) { bxt_err("failed to create (%s: %s) %d", ly->name, key, r); unset_layer = *layer; unset_layer.type = BUXTON_LAYER_BASE; direct_unset(&unset_layer, key); } } return r; } int direct_unset(const struct buxton_layer *layer, const char *key) { int r; const struct layer *ly; const struct backend *backend; char path[FILENAME_MAX]; if (!layer || !key || !*key) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = backend_get(ly->backend, &backend); if (r != BUXTON_ERROR_NONE) return r; if (!backend->unset_value) { bxt_err("Unset: backend '%s' has no unset func", backend->name); return BUXTON_ERROR_INVALID_OPERATION; } r = get_path(layer->uid, layer->type, ly, path, sizeof(path)); if (r != BUXTON_ERROR_NONE) return r; r = backend->unset_value(path, key); if (r != BUXTON_ERROR_NONE) { bxt_err("Unset: unset_value: %s %d", buxton_err_get_str(r), r); return r; } cache_remove(layer->type, key); return BUXTON_ERROR_NONE; } static int comp_str(const void *pa, const void *pb) { const char *sa = pa ? *(char * const *)pa : ""; const char *sb = pb ? *(char * const *)pb : ""; return strcmp(sa, sb); } int direct_list(const struct buxton_layer *layer, char ***names, unsigned int *len, bool is_base) { int r; const struct layer *ly; const struct backend *backend; char path[FILENAME_MAX]; unsigned int _len; if (!layer || !names) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = backend_get(ly->backend, &backend); if (r != BUXTON_ERROR_NONE) return r; if (!backend->list_keys) { bxt_err("List: backend '%s' has no list func", backend->name); return BUXTON_ERROR_INVALID_OPERATION; } r = get_path(layer->uid, is_base ? BUXTON_LAYER_BASE : BUXTON_LAYER_NORMAL, ly, path, sizeof(path)); if (r != BUXTON_ERROR_NONE) return r; r = backend->list_keys(path, names, &_len, is_base); if (r != BUXTON_ERROR_NONE) { bxt_err("List: list_keys: %s %d", buxton_err_get_str(r), r); return r; } if (_len > 1) qsort(*names, _len, sizeof(char *), comp_str); if (len) *len = _len; return BUXTON_ERROR_NONE; } int direct_dump(const struct buxton_layer *layer, char ***key_list, struct buxton_value **value_list, int *len) { int ret; const struct layer *ly; const struct backend *backend; char path[FILENAME_MAX]; unsigned int base_len, nomal_len; int i, j; struct buxton_value *_value_list = NULL; char **base_keys = NULL, **normal_keys = NULL; void **base_values = NULL, **normal_values = NULL; int *base_value_len = NULL, *normal_value_len = NULL; void *tmp; int len_tmp; if (!layer || !key_list || !value_list || !len) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } ret = conf_get_layer(layer->name, &ly); if (ret != BUXTON_ERROR_NONE) return ret; ret = backend_get(ly->backend, &backend); if (ret != BUXTON_ERROR_NONE) return ret; if (!backend->get_dump) { bxt_err("dump: backend '%s' has no list func", backend->name); return BUXTON_ERROR_INVALID_OPERATION; } ret = get_path(layer->uid, BUXTON_LAYER_BASE, ly, path, sizeof(path)); if (ret != BUXTON_ERROR_NONE) return ret; /*base_keys is sorted data */ ret = backend->get_dump(path, &base_keys, &base_values, &base_value_len, &base_len); if (ret != BUXTON_ERROR_NONE) { bxt_err("dump: get_dump failed"); return ret; } ret = get_path(layer->uid, BUXTON_LAYER_NORMAL, ly, path, sizeof(path)); if (ret != BUXTON_ERROR_NONE) { bxt_err("dump: get_path failed"); goto out; } /* normal_keys is sorted data */ ret = backend->get_dump(path, &normal_keys, &normal_values, &normal_value_len, &nomal_len); if (ret != BUXTON_ERROR_NONE) { bxt_err("dump: get_dump failed"); goto out; } _value_list = calloc(base_len, sizeof(struct buxton_value)); if (_value_list == NULL) { bxt_err("dump: calloc failed"); ret = BUXTON_ERROR_OUT_OF_MEMORY; goto out; } for (i = 0, j = 0; i < base_len; i++) { if (j < nomal_len) { if (strcmp(base_keys[i], normal_keys[j]) == 0) { tmp = normal_values[j]; len_tmp = normal_value_len[j]; j++; } else { tmp = base_values[i]; len_tmp = base_value_len[i]; } } else { tmp = base_values[i]; len_tmp = base_value_len[i]; } ret = deserialz_data((uint8_t *)tmp, len_tmp, NULL, NULL, &_value_list[i]); if (ret != BUXTON_ERROR_NONE) { bxt_err("dump: deserialz_data failed %s ", base_keys[i]); goto out; } } *key_list = base_keys; *value_list = _value_list; *len = base_len; out: buxton_free_keys((char **)base_values); buxton_free_keys(normal_keys); buxton_free_keys((char **)normal_values); free(base_value_len); free(normal_value_len); if (ret != BUXTON_ERROR_NONE) { buxton_free_keys(base_keys); if (_value_list) free(_value_list); } return ret; } int direct_get_priv(const struct buxton_layer *layer, const char *key, enum buxton_priv_type type, char **priv) { int r; const struct layer *ly; char **rp; char **wp; if (!layer || !key || !*key || !priv) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } switch (type) { case BUXTON_PRIV_READ: rp = priv; wp = NULL; break; case BUXTON_PRIV_WRITE: rp = NULL; wp = priv; break; default: bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, rp, wp, NULL); return r; } int direct_set_priv(const struct buxton_layer *layer, const char *key, enum buxton_priv_type type, const char *priv) { int r; const struct layer *ly; char *rp; char *wp; const char *t_rp; const char *t_wp; struct buxton_value val; if (!layer || !key || !*key || !priv) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } switch (type) { case BUXTON_PRIV_READ: case BUXTON_PRIV_WRITE: break; default: bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = get_val(ly, layer->uid, BUXTON_LAYER_BASE, key, &rp, &wp, &val); if (r != BUXTON_ERROR_NONE) return r; switch (type) { case BUXTON_PRIV_READ: t_rp = priv; t_wp = wp; break; case BUXTON_PRIV_WRITE: t_rp = rp; t_wp = priv; break; default: /* Never reach */ t_rp = rp; t_wp = wp; break; } r = set_val(ly, layer->uid, BUXTON_LAYER_BASE, key, t_rp, t_wp, &val); value_free(&val); free(rp); free(wp); return r; } int direct_remove_db(const struct buxton_layer *layer) { int r; const struct layer *ly; const struct backend *backend; char path[FILENAME_MAX]; if (!layer) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = conf_get_layer(layer->name, &ly); if (r != BUXTON_ERROR_NONE) return r; r = backend_get(ly->backend, &backend); if (r != BUXTON_ERROR_NONE) return r; if (!backend->remove_db) { bxt_err("Remove db : backend '%s' has no remove_db func", backend->name); return BUXTON_ERROR_INVALID_OPERATION; } r = get_path(layer->uid, layer->type, ly, path, sizeof(path)); if (r != BUXTON_ERROR_NONE) return r; r = backend->remove_db(path); if (r != BUXTON_ERROR_NONE) bxt_err("remote user memory db failed"); return r; } void direct_exit(void) { conf_exit(); backend_exit(); } int direct_init(const char *moddir, const char *confpath, bool *log_on, int *max_line) { int r; GList *backends; if (!moddir || !*moddir || !confpath || !*confpath) { bxt_err("Invalid parameter"); return BUXTON_ERROR_INVALID_PARAMETER; } r = backend_init(moddir); if (r != BUXTON_ERROR_NONE) return r; backends = backend_list(); if (!backends) return BUXTON_ERROR_NOT_EXIST; r = conf_init(confpath, backends, log_on, max_line); g_list_free(backends); return r; }