/* * Copyright 2024 Google LLC * * 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 "services/normal/settings/settings_file.h" #include "system/status_codes.h" #include "util/crc8.h" #include #include #include "clar_asserts.h" struct { bool open; void *values[UINT8_MAX]; void *keys[UINT8_MAX]; uint32_t val_lens[UINT8_MAX]; uint32_t key_lens[UINT8_MAX]; bool dirty[UINT8_MAX]; } s_settings_file; void fake_settings_file_reset(void) { for (unsigned i = 0; i < UINT8_MAX; ++i) { free(s_settings_file.values[i]); s_settings_file.values[i] = NULL; free(s_settings_file.keys[i]); s_settings_file.keys[i] = NULL; s_settings_file.val_lens[i] = 0; s_settings_file.key_lens[i] = 0; s_settings_file.dirty[i] = false; } s_settings_file.open = false; } status_t settings_file_get(SettingsFile *file, const void *key, size_t key_len, void *val_out, size_t val_out_len) { if (settings_file_exists(file, key, key_len)) { const uint8_t key_crc8 = crc8_calculate_bytes(key, key_len, false); memcpy(val_out, s_settings_file.values[key_crc8], val_out_len); return S_SUCCESS; } memset(val_out, 0, val_out_len); return E_DOES_NOT_EXIST; } status_t settings_file_set(SettingsFile *file, const void *key, size_t key_len, const void *val, size_t val_len) { void *val_copy = malloc(val_len); void *key_copy = malloc(key_len); cl_assert(val_copy && key_copy); memcpy(val_copy, val, val_len); memcpy(key_copy, key, key_len); const uint8_t key_crc8 = crc8_calculate_bytes(key, key_len, false); if (s_settings_file.values[key_crc8] != NULL) { cl_assert(memcmp(key, s_settings_file.keys[key_crc8], key_len) == 0); } free(s_settings_file.values[key_crc8]); free(s_settings_file.keys[key_crc8]); s_settings_file.values[key_crc8] = val_copy; s_settings_file.keys[key_crc8] = key_copy; s_settings_file.val_lens[key_crc8] = val_len; s_settings_file.key_lens[key_crc8] = key_len; s_settings_file.dirty[key_crc8] = true; return S_SUCCESS; } int settings_file_get_len(SettingsFile *file, const void *key, size_t key_len) { if (settings_file_exists(file, key, key_len)) { const uint8_t key_crc8 = crc8_calculate_bytes(key, key_len, false); return s_settings_file.val_lens[key_crc8]; } return 0; } status_t settings_file_delete(SettingsFile *file, const void *key, size_t key_len) { if (settings_file_exists(file, key, key_len)) { const uint8_t key_crc8 = crc8_calculate_bytes(key, key_len, false); free(s_settings_file.values[key_crc8]); free(s_settings_file.keys[key_crc8]); s_settings_file.values[key_crc8] = NULL; s_settings_file.keys[key_crc8] = NULL; s_settings_file.val_lens[key_crc8] = 0; s_settings_file.key_lens[key_crc8] = 0; s_settings_file.dirty[key_crc8] = false; return S_SUCCESS; } else { return E_DOES_NOT_EXIST; } } status_t settings_file_open(SettingsFile *file, const char *name, int max_used_space) { if (s_settings_file.open) { return E_BUSY; } else { *file = (SettingsFile){}; s_settings_file.open = true; return S_SUCCESS; } } void settings_file_close(SettingsFile *file) { cl_assert(s_settings_file.open); s_settings_file.open = false; } bool settings_file_exists(SettingsFile *file, const void *key, size_t key_len) { const uint8_t key_crc8 = crc8_calculate_bytes(key, key_len, false); return (s_settings_file.values[key_crc8] != NULL && memcmp(s_settings_file.keys[key_crc8], key, key_len) == 0); } status_t settings_file_mark_synced(SettingsFile *file, const void *key, size_t key_len) { if (settings_file_exists(file, key, key_len)) { const uint8_t key_crc8 = crc8_calculate_bytes(key, key_len, false); s_settings_file.dirty[key_crc8] = false; return S_SUCCESS; } return E_DOES_NOT_EXIST; } status_t settings_file_set_byte(SettingsFile *file, const void *key, size_t key_len, size_t offset, uint8_t byte) { if (settings_file_exists(file, key, key_len)) { const uint8_t key_crc8 = crc8_calculate_bytes(key, key_len, false); uint8_t *val_bytes = s_settings_file.values[key_crc8]; val_bytes[offset] &= byte; return S_SUCCESS; } else { return E_DOES_NOT_EXIST; } } uint8_t s_cur_itr; static void prv_get_key(SettingsFile *file, void *key, size_t key_len) { memcpy(key, s_settings_file.keys[s_cur_itr], key_len); } static void prv_get_val(SettingsFile *file, void *val, size_t val_len) { memcpy(val, s_settings_file.values[s_cur_itr], val_len); } status_t settings_file_each(SettingsFile *file, SettingsFileEachCallback cb, void *context) { for (unsigned i = 0; i < UINT8_MAX; ++i) { if (s_settings_file.keys[i] != NULL && s_settings_file.values[i] != NULL) { s_cur_itr = i; SettingsRecordInfo info = { .get_key = prv_get_key, .get_val = prv_get_val, .key_len = s_settings_file.key_lens[i], .val_len = s_settings_file.val_lens[i], .dirty = s_settings_file.dirty[i], }; if (!cb(file, &info, context)) { break; } } } return S_SUCCESS; } status_t settings_file_rewrite(SettingsFile *file, SettingsFileRewriteCallback cb, void *context) { // TODO fake_settings_file_reset(); return S_SUCCESS; } status_t settings_file_rewrite_filtered(SettingsFile *file, SettingsFileRewriteFilterCallback filter_cb, void *context) { // TODO fake_settings_file_reset(); return S_SUCCESS; }