#include "property.h" #include #include #include #include #include "errcode_inc.h" #if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0)) // #include "ff.h" #if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0)) #include "sha2.h" #endif #endif #if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0)) #include "mod_bus.h" #endif #if (((!defined PROPERTY_PROV_FS_EN) || (PROPERTY_PROV_FS_EN == 0)) && ((!defined PROPERTY_PROV_REMOTE_EN) || (PROPERTY_PROV_REMOTE_EN == 0))) #error "define PROPERTY_PROV_FS_EN or PROPERTY_PROV_REMOTE_EN in config.h" #endif /** * 引入pthread库,确保线程安全 */ #ifdef __linux__ #include #include static pthread_mutex_t prop_mutex; void prop_lock() { pthread_mutex_lock(&prop_mutex); } void prop_unlock() { pthread_mutex_unlock(&prop_mutex); } void prop_lock_init() { pthread_mutex_init(&prop_mutex, NULL); } void prop_wait(INT32U time) { } #else #include #include void prop_lock() { ; } void prop_unlock() { ; } void prop_lock_init() { ; } void prop_wait(INT32U time) { ; } #endif #define config_path "./conf" #define COPY_BUF_SIZE 1024 #define FLOAT_STRING_LEN 32 #define UPDATE_LOG "0:/conf/update.%d.log" typedef struct { const char *key; const char *value; INT8U success : 1; } property_string_item; typedef INT32U (*property_get)(const char *store, const char *id, const char *key, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj); typedef INT32U (*property_set)(const char *store, const char *id, property_string_item *list, INT32U count, void *obj); typedef INT32U (*property_clear_cache)(const char *store, const char *id, void *obj); typedef struct _sbt_node { struct _sbt_node *ch[2]; INT8U valid : 1; INT8U tryLocal : 1; INT8U isLocal : 1; char *key; char *value; INT32U size; } sbt_node; static sbt_node sbt_nil = {{&sbt_nil, &sbt_nil}, 0, 0, 0, NULL, NULL, 0}; typedef struct _prop_cache { char *store; char *id; sbt_node *sbt; struct _prop_cache *next; } prop_cache; typedef struct { struct { INT32U init : 1; INT32U initPending : 1; INT32U cache : 1; INT32U lock : 1; } flag; char *id; #if (defined RTOS_UCOS) OS_EVENT *sem; #endif property_get get; property_set set; property_clear_cache clear; prop_cache *cache; void *obj; } property_provider; static property_provider pp[PROPERTY_PROVIDER_MAX]; static INT8U file_test_random = 0; #if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0)) static INT32U FilePropertyInit(INT32U providerId, const PropertyInitParam *param); #endif #if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0)) static INT32U RemotePropertyInit(INT32U providerId, const PropertyInitParam *param); #endif // linux下malloc是线程安全的 static void *malloc_mt(size_t size) { return malloc(size); } // linux下malloc是线程安全的 static void free_mt(void *ptr) { free(ptr); } /** * SBT(Spine Binary Tree)是一种特殊的二叉树结构,它主要用于处理字符串模式匹配问题。 SBT的特点是将所有模式字符串的字符按照字典序排列,并将它们连接成一个字符串作为树的主干(Spine),每个模式字符串作为树的一个分支。在SBT中,模式字符串的公共前缀被共享,从而减少了树的高度,提高了匹配效率。 */ static void SBT_Rotate(sbt_node **x, BOOL flag) { // 旋转:flag == 0为左旋,否则为右旋 sbt_node *y = (*x)->ch[!flag]; (*x)->ch[!flag] = y->ch[flag]; y->ch[flag] = *x; y->size = (*x)->size; (*x)->size = (*x)->ch[0]->size + (*x)->ch[1]->size + 1; *x = y; } static void SBT_Maintain(sbt_node **t, BOOL flag) { // 维护操作的核心:保持 if ((*t)->ch[flag]->ch[flag]->size > (*t)->ch[!flag]->size) { // 情况1 SBT_Rotate(t, !flag); } else if ((*t)->ch[flag]->ch[!flag]->size > (*t)->ch[!flag]->size) { // 情况2 SBT_Rotate(&(*t)->ch[flag], flag); SBT_Rotate(t, !flag); } else { // 无需修复 return; } SBT_Maintain(&(*t)->ch[0], 0); // 修复左子树 SBT_Maintain(&(*t)->ch[1], 1); // 修复右子树 SBT_Maintain(t, 0); // 修复整棵树 SBT_Maintain(t, 1); } static INT32U SBT_Depth(sbt_node *t) { INT32U d[2]; if (t == &sbt_nil) return 0; d[0] = SBT_Depth(t->ch[0]); d[1] = SBT_Depth(t->ch[1]); if (d[0] > d[1]) return (d[0] + 1); return (d[1] + 1); } // static INT32U SBT_Check(sbt_node* t) { // if (((INT32U)t < 0xa0000000) || ((INT32U)t >= 0xa0800000)) // return RET_OS_HEAP_CORRUPTED; // if (t == &sbt_nil) // return RET_EXT_NO_ERROR; // if (!SBT_Check(t->ch[0])) // return RET_OS_HEAP_CORRUPTED; // if (!SBT_Check(t->ch[1])) // return RET_OS_HEAP_CORRUPTED; // return RET_EXT_NO_ERROR; // } static int SBT_NodeCmp(sbt_node *x, BOOL yl, const char *ykey) { if ((x->tryLocal != 0) && (yl == 0)) return 1; if ((x->tryLocal == 0) && (yl != 0)) return -1; if (x->key == ykey) // 两者均为NULL返回0 return 0; if (ykey == NULL) // 至少有一个不为NULL, y->key == NULL 则 x->key != NULL return 1; if (x->key == NULL) return -1; return strcmp(x->key, ykey); } static sbt_node *SBT_Search(sbt_node *t, BOOL local, const char *key) { // 在T中中寻找关键字为key的结点 // 若能找到则返回指向它的指针,否则返回NULL int cmp; if (t == &sbt_nil) return NULL; cmp = SBT_NodeCmp(t, local, key); if (cmp == 0) return t; return SBT_Search(t->ch[cmp < 0], local, key); } static void SBT_Insert(sbt_node **t, sbt_node *x) { // 将节点x插入树中 if ((*t) == &sbt_nil) { (*t) = x; } else { int cmp = SBT_NodeCmp(x, (*t)->tryLocal, (*t)->key); if (cmp == 0) { sbt_node *old = *t; x->ch[0] = old->ch[0]; x->ch[1] = old->ch[1]; *t = x; free_mt(old->key); if (old->value != NULL) free_mt(old->value); free_mt(old); } else { (*t)->size++; SBT_Insert(&(*t)->ch[cmp > 0], x); SBT_Maintain(t, (cmp > 0)); } } } static void SBT_Delete(sbt_node *t) { if (t == &sbt_nil) return; SBT_Delete(t->ch[0]); SBT_Delete(t->ch[1]); free_mt(t->key); if (t->value != NULL) free_mt(t->value); } /** * ram缓存 */ static sbt_node *CacheGet(property_provider *p, const char *store, const char *id, BOOL local, const char *key) { prop_cache *ptr; sbt_node *node; if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return NULL; for (ptr = p->cache; ptr != NULL; ptr = ptr->next) if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0)))) break; if (ptr == NULL) return NULL; node = SBT_Search(ptr->sbt, local, key); if (node == NULL) return NULL; if (!node->valid) return NULL; return node; } static INT32U CacheSet(property_provider *p, const char *store, const char *id, BOOL tryLocal, const char *key, const char *value, BOOL isLocal) { prop_cache *ptr; sbt_node *node; INT32U keyLen, valLen; if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return RET_OS_INVALID_PARAM; node = (sbt_node *)malloc_mt(sizeof(sbt_node)); if (node == NULL) return RET_PROPERTY_HEAP_FULL; keyLen = strlen(key); valLen = strlen(value); node->ch[0] = &sbt_nil; node->ch[1] = &sbt_nil; node->valid = TRUE; node->tryLocal = tryLocal; node->isLocal = isLocal; node->size = 1; node->key = (char *)malloc_mt(keyLen + 1); if (node->key == NULL) { free_mt(node); return RET_PROPERTY_HEAP_FULL; } else { strncpy(node->key, key, keyLen); node->key[keyLen] = 0; } if (value == NULL) { node->value = NULL; } else { node->value = (char *)malloc_mt(valLen + 1); if (value == NULL) { free_mt(node->key); free_mt(node); return RET_PROPERTY_HEAP_FULL; } else { strncpy(node->value, value, valLen); node->value[valLen] = 0; } } for (ptr = p->cache; ptr != NULL; ptr = ptr->next) if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0)))) break; if (ptr == NULL) { ptr = (prop_cache *)malloc_mt(sizeof(prop_cache)); if (ptr != NULL) { BOOL mallocErr = FALSE; ptr->store = NULL; ptr->id = NULL; if ((id != NULL) && (*id != 0)) { INT32U idLen = strlen(id); ptr->id = (char *)malloc_mt(idLen + 1); if (ptr->id == NULL) { mallocErr = TRUE; } else { strncpy(ptr->id, id, idLen); ptr->id[idLen] = 0; } } if (!mallocErr) { INT32U storeLen = strlen(store); ptr->store = (char *)malloc_mt(storeLen + 1); if (ptr->store == NULL) { mallocErr = TRUE; } else { strncpy(ptr->store, store, storeLen); ptr->store[storeLen] = 0; } } if (mallocErr) { if (ptr->store != NULL) free_mt(ptr->store); if (ptr->id != NULL) free_mt(ptr->id); free_mt(ptr); ptr = NULL; } else { ptr->sbt = &sbt_nil; ptr->next = p->cache; p->cache = ptr; } } } if (ptr == NULL) { free_mt(node->key); if (node->value != NULL) free_mt(node->value); free_mt(node); return RET_PROPERTY_HEAP_FULL; } SBT_Insert(&ptr->sbt, node); return RET_EXT_NO_ERROR; } static INT32U CacheInvalid(property_provider *p, const char *store, const char *id, BOOL tryLocal, const char *key) { prop_cache *ptr; sbt_node *node; if ((p == NULL) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return RET_OS_INVALID_PARAM; for (ptr = p->cache; ptr != NULL; ptr = ptr->next) if ((strcmp(store, ptr->store) == 0) && ((((id == NULL) || (*id == 0)) && ((ptr->id == NULL) || (*ptr->id == 0))) || ((id != NULL) && (ptr->id != NULL) && (strcmp(id, ptr->id) == 0)))) break; if (ptr == NULL) return RET_EXT_NO_ERROR; node = SBT_Search(ptr->sbt, tryLocal, key); if (node != NULL) node->valid = FALSE; return RET_EXT_NO_ERROR; } // store == NULL时清除全部cache // store != NULL && id == NULL时清除store相关的全部cache // store != NULL && id != NULL时清除(store, id)的cache static INT32U CacheClear(property_provider *p, const char *store, const char *id) { if (p == NULL) return NULL; if ((store == NULL) || (*store == 0)) { prop_cache *ptr; for (ptr = p->cache; ptr != NULL;) { prop_cache *tmp = ptr; ptr = ptr->next; free_mt(tmp->store); if (tmp->id != NULL) free_mt(tmp->id); SBT_Delete(tmp->sbt); free_mt(tmp); } p->cache = NULL; } else if ((id == NULL) || (*id == 0)) { prop_cache *ptr; prop_cache *tail = NULL; for (ptr = p->cache; ptr != NULL;) { if (strcmp(store, ptr->store) == 0) { prop_cache *tmp = ptr; if (ptr == p->cache) p->cache = ptr->next; else tail->next = ptr->next; ptr = ptr->next; free_mt(tmp->store); if (tmp->id != NULL) free_mt(tmp->id); SBT_Delete(tmp->sbt); free_mt(tmp); } else { tail = ptr; ptr = ptr->next; } } } else { prop_cache *ptr; prop_cache *tail = NULL; for (ptr = p->cache; ptr != NULL; tail = ptr, ptr = ptr->next) if ((strcmp(store, ptr->store) == 0) && ((ptr->id != NULL) && (strcmp(id, ptr->id) == 0))) break; if (ptr != NULL) { if (ptr == p->cache) p->cache = ptr->next; else tail->next = ptr->next; free_mt(ptr->store); if (ptr->id != NULL) free_mt(ptr->id); SBT_Delete(ptr->sbt); free_mt(ptr); } } return RET_EXT_NO_ERROR; } static void CheckInit(void) { static INT8U init = 0; prop_lock(); if (init == 0) { INT8U i; for (i = 0; i < PROPERTY_PROVIDER_MAX; i++) { pp[i].flag.init = 0; pp[i].flag.initPending = 0; pp[i].flag.cache = 0; pp[i].id = NULL; pp[i].get = NULL; pp[i].set = NULL; pp[i].clear = NULL; pp[i].cache = NULL; pp[i].obj = NULL; } init = 1; } prop_unlock(); } // key规则检查 static INT32U CheckKey(const char *key) { if ((key == NULL) || (*key == '\0')) return RET_OS_INVALID_PARAM; if (((key[0] >= 'a') && (key[0] <= 'z')) || ((key[0] >= 'A') && (key[0] <= 'Z'))) { INT32U i; for (i = 1; key[i] != '\0'; i++) { if (((key[i] >= 'a') && (key[i] <= 'z')) || ((key[i] >= 'A') && (key[i] <= 'Z')) || ((key[i] >= '0') && (key[i] <= '9')) || (key[i] == '-') || (key[i] == '_') || (key[i] == '.') || (key[i] == '[') || (key[i] == ']')) continue; return RET_PROPERTY_INVALID_KEY; } } else { return RET_PROPERTY_INVALID_KEY; } // printf("key name is ok\n"); return RET_EXT_NO_ERROR; } // TODO: INT32U PropertyInit(INT32U providerId, const PropertyInitParam *param) { INT32U ret = RET_EXT_NO_ERROR; BOOL doInit = FALSE; CheckInit(); if ((providerId >= PROPERTY_PROVIDER_MAX) || (param == NULL) || ((param->id != NULL) && (strlen(param->id) > PROPERTY_ID_MAX))) return RET_OS_INVALID_PARAM; #if 0 // 这段代码没必要存在 CheckInit()——>pp[providerId].flag.initPending=0 for (;;) { BOOL quit = FALSE; prop_lock(); if (pp[providerId].flag.initPending == 0) { if (pp[providerId].flag.init == 0) { doInit = TRUE; pp[providerId].flag.initPending = 1; } quit = TRUE; } prop_unlock(); if (quit) break; prop_wait(1000); } #else // 直接启动初始化 doInit = TRUE; #endif if (doInit) { char *id = NULL; if ((ret == RET_EXT_NO_ERROR) && (param->id != NULL) && (*param->id != 0)) { INT32U idLen = strlen(param->id); id = (char *)malloc_mt(idLen + 1); if (id == NULL) { ret = RET_PROPERTY_HEAP_FULL; } else { strncpy(id, param->id, idLen); id[idLen] = 0; } } if (ret == RET_EXT_NO_ERROR) { pp[providerId].id = id; if (param->type == PropertyTypeFS) { #if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0)) // 锁初始化 prop_lock_init(); ret = FilePropertyInit(providerId, param); #else ret = RET_OS_NOT_IMPLEMENT; #endif } else if (param->type == PropertyTypeRemote) { #if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0)) #if (defined RTOS_UCOS) pp[providerId].sem = OSSemCreate(1); if (pp[providerId].sem == NULL) { ret = RET_OS_NO_AVAILABLE_EVENT_CTRL_BLK; } else { #endif ret = RemotePropertyInit(providerId, param); #if (defined RTOS_UCOS) if (ret != RET_EXT_NO_ERROR) { INT8U osErr = OS_ERR_NONE; OSSemDel(pp[providerId].sem, OS_DEL_ALWAYS, &osErr); pp[providerId].sem = NULL; } } #endif #else ret = RET_OS_NOT_IMPLEMENT; #endif } else { ret = RET_OS_INVALID_PARAM; } } if (ret != RET_EXT_NO_ERROR) { if (id != NULL) free_mt(id); pp[providerId].id = NULL; } pp[providerId].flag.initPending = 0; } // PROP_ENABLE_IRQ(); return ret; } INT32U GetProperty(INT32U providerId, const char *store, const char *id, const char *key, BOOL tryLocal, char *value, INT32U sizeOfValue, BOOL *isLocal) { INT32U ret = RET_EXT_NO_ERROR; sbt_node *node = NULL; if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (value == NULL) || (sizeOfValue == 0)) return RET_OS_INVALID_PARAM; // 检查key命名规范 ret = CheckKey(key); if (ret != RET_EXT_NO_ERROR) return ret; // 检查是否init CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; if (pp[providerId].get == NULL) return RET_PROPERTY_NOT_INIT; if ((id == NULL) || (*id == 0)) id = pp[providerId].id; if (tryLocal && ((id == NULL) || (*id == 0))) return RET_PROPERTY_INVALID_STORE_ID; // 加锁 prop_lock(); if (pp[providerId].flag.cache) node = CacheGet(&pp[providerId], store, id, tryLocal, key); if (node == NULL) { BOOL lt = TRUE; ret = pp[providerId].get(store, key, (tryLocal ? id : NULL), value, sizeOfValue, <, pp[providerId].obj); if (pp[providerId].flag.cache) { if (ret == RET_EXT_NO_ERROR) CacheSet(&pp[providerId], store, id, tryLocal, key, value, lt); else if (ret == RET_PROPERTY_NOT_FOUND) CacheSet(&pp[providerId], store, id, tryLocal, key, NULL, lt); } if (isLocal != NULL) *isLocal = lt; } else if (node->value == NULL) { ret = RET_PROPERTY_NOT_FOUND; } else { INT32U valLen = strlen(node->value); if (valLen > sizeOfValue - 1) { valLen = sizeOfValue - 1; ret = RET_PROPERTY_OUT_OF_VAL_BUF; } strncpy(value, node->value, valLen); value[valLen] = 0; if (isLocal != NULL) *isLocal = node->isLocal; } prop_unlock(); return ret; } INT32U SetProperty(INT32U providerId, const char *store, const char *id, const char *key, const char *value) { PropertyItem item; if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return RET_OS_INVALID_PARAM; CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; item.key = key; if (value == NULL) { item.type = VT_NULL; item.value.str = NULL; } else { item.type = VT_STR; item.value.str = value; } item.success = 0; return SetPropertyList(providerId, store, id, &item, 1); } INT32U SetPropertyList(INT32U providerId, const char *store, const char *id, PropertyItem *list, INT32U count) { INT32U ret = RET_EXT_NO_ERROR; property_string_item *bufList; char *stringList; BOOL fpChked = FALSE; INT32U idx; if (providerId >= PROPERTY_PROVIDER_MAX) return RET_OS_INVALID_PARAM; CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; if (pp[providerId].set == NULL) return RET_PROPERTY_NOT_INIT; if ((id == NULL) || (*id == 0)) id = pp[providerId].id; if ((id == NULL) || (*id == 0)) return RET_PROPERTY_INVALID_STORE_ID; if (count == 0) return RET_EXT_NO_ERROR; bufList = (property_string_item *)malloc_mt(sizeof(property_string_item) * count); stringList = ((bufList == NULL) ? NULL : (char *)malloc_mt((FLOAT_STRING_LEN + 1) * count)); if ((bufList == NULL) || (stringList == NULL)) { if (bufList != NULL) free_mt(bufList); if (stringList != NULL) free_mt(stringList); return RET_PROPERTY_HEAP_FULL; } memset(stringList, 0, ((FLOAT_STRING_LEN + 1) * count)); for (idx = 0; idx < count; idx++) { ret = CheckKey(list[idx].key); if (ret != RET_EXT_NO_ERROR) break; bufList[idx].key = list[idx].key; switch (list[idx].type) { case VT_NULL: bufList[idx].value = NULL; break; case VT_I4: bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i4); break; case VT_I2: bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i2); break; case VT_I1: bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%d", list[idx].value.i1); break; case VT_UI4: bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui4); break; case VT_UI2: bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui2); break; case VT_UI1: bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", list[idx].value.ui1); break; case VT_R4: if (!fpChked) { char str[10]; snprintf(str, sizeof(str), "%e", PI); if (strncmp(str, "3.14159", strlen("3.14159")) == 0) fpChked = TRUE; else ret = RET_OS_FLOAT_TEST_FAILED; } if (ret == RET_EXT_NO_ERROR) { bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "%e", ((isfinite(list[idx].value.r4) || isinf(list[idx].value.r4)) ? list[idx].value.r4 : NAN)); } break; case VT_STR: bufList[idx].value = list[idx].value.str; break; case VT_BIT4: bufList[idx].value = &stringList[(FLOAT_STRING_LEN + 1) * idx]; snprintf(&stringList[(FLOAT_STRING_LEN + 1) * idx], FLOAT_STRING_LEN, "0x%08x", ((GetUnsigned(providerId, store, list[idx].key, TRUE, 0, NULL, NULL) & (~list[idx].value.bit4.mask)) | (list[idx].value.bit4.val & list[idx].value.bit4.mask))); break; } if (ret != RET_EXT_NO_ERROR) break; bufList[idx].success = 0; } prop_lock(); if (ret == RET_EXT_NO_ERROR) { if (ret == RET_EXT_NO_ERROR) ret = pp[providerId].set(store, id, bufList, count, pp[providerId].obj); if (ret == RET_EXT_NO_ERROR) { for (idx = 0; idx < count; idx++) { if ((bufList[idx].value == NULL) || (CacheSet(&pp[providerId], store, id, TRUE, bufList[idx].key, bufList[idx].value, TRUE) != RET_EXT_NO_ERROR)) CacheInvalid(&pp[providerId], store, id, TRUE, bufList[idx].key); } } } prop_unlock(); free_mt(bufList); free_mt(stringList); return ret; } INT32S GetInteger(INT32U providerId, const char *store, const char *key, BOOL tryLocal, INT32S defaultValue, INT32U *retCode, BOOL *isLocal) { char result[PROPERTY_LINE_MAX + 1]; INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal); INT32S val = 0; if (ret == RET_EXT_NO_ERROR) { char *endptr = NULL; val = strtol(result, &endptr, 0); if (endptr == result) { ret = RET_PROPERTY_EFORMAT; } else { for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++) ; if (*endptr != 0) ret = RET_PROPERTY_EFORMAT; else if ((errno == ERANGE) && ((val == LONG_MIN) || (val == LONG_MAX))) ret = RET_PROPERTY_ERANGE; } } if (ret != RET_EXT_NO_ERROR) val = defaultValue; if (retCode != NULL) *retCode = ret; return val; } INT32U GetUnsigned(INT32U providerId, const char *store, const char *key, BOOL tryLocal, INT32U defaultValue, INT32U *retCode, BOOL *isLocal) { char result[PROPERTY_LINE_MAX + 1]; INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal); INT32U val = 0; if (ret == RET_EXT_NO_ERROR) { char *endptr = NULL; val = strtoul(result, &endptr, 0); if (endptr == result) { ret = RET_PROPERTY_EFORMAT; } else { for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++) ; if (*endptr != 0) ret = RET_PROPERTY_EFORMAT; else if ((errno == ERANGE) && (val == ULONG_MAX)) ret = RET_PROPERTY_ERANGE; } } if (ret != RET_EXT_NO_ERROR) val = defaultValue; if (retCode != NULL) *retCode = ret; return val; } FP32 GetFloat(INT32U providerId, const char *store, const char *key, BOOL tryLocal, FP32 defaultValue, INT32U *retCode, BOOL *isLocal) { char result[PROPERTY_LINE_MAX + 1]; INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal); FP32 val = FP_ZERO; if (ret == RET_EXT_NO_ERROR) { char *endptr = NULL; val = strtof(result, &endptr); if (!isfinite(val) && !isinf(val)) { ret = RET_PROPERTY_EFORMAT; } else if (endptr == result) { ret = RET_PROPERTY_EFORMAT; } else { for (; ((*endptr == ' ') || (*endptr == '\t')); endptr++) ; if (*endptr != 0) ret = RET_PROPERTY_EFORMAT; else if ((errno == ERANGE) && isinf(val)) ret = RET_PROPERTY_ERANGE; } } if (ret != RET_EXT_NO_ERROR) val = defaultValue; if (retCode != NULL) *retCode = ret; return val; } BOOL GetBoolean(INT32U providerId, const char *store, const char *key, BOOL tryLocal, BOOL defaultValue, INT32U *retCode, BOOL *isLocal) { INT32U i; char result[PROPERTY_LINE_MAX + 1]; INT32U ret = GetProperty(providerId, store, NULL, key, tryLocal, result, sizeof(result), isLocal); BOOL val = defaultValue; if (ret == RET_EXT_NO_ERROR) { for (i = 0; ((i < sizeof(result)) && (result[i] != '\0')); i++) if ((result[i] >= 'A') && (result[i] <= 'Z')) result[i] += ('a' - 'A'); if ((strcmp("true", result) == 0) || (strcmp("yes", result) == 0) || (strcmp("1", result) == 0)) { val = TRUE; } else if ((strcmp("false", result) == 0) || (strcmp("no", result) == 0) || (strcmp("0", result) == 0)) { val = FALSE; } else { ret = RET_PROPERTY_EFORMAT; } } if (ret != RET_EXT_NO_ERROR) val = defaultValue; if (retCode != NULL) *retCode = ret; return val; } INT32U SetInteger(INT32U providerId, const char *store, const char *key, INT32S value) { PropertyItem item; if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return RET_OS_INVALID_PARAM; CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; item.key = key; item.type = VT_I4; item.value.i4 = value; item.success = 0; return SetPropertyList(providerId, store, NULL, &item, 1); } INT32U SetUnsigned(INT32U providerId, const char *store, const char *key, INT32U value) { PropertyItem item; if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return RET_OS_INVALID_PARAM; CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; item.key = key; item.type = VT_UI4; item.value.ui4 = value; item.success = 0; return SetPropertyList(providerId, store, NULL, &item, 1); } INT32U SetFloat(INT32U providerId, const char *store, const char *key, FP32 value) { PropertyItem item; if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return RET_OS_INVALID_PARAM; CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; item.key = key; item.type = VT_R4; item.value.r4 = value; item.success = 0; return SetPropertyList(providerId, store, NULL, &item, 1); } INT32U SetBits(INT32U providerId, const char *store, const char *key, INT32U value, INT32U mask) { PropertyItem item; if ((providerId >= PROPERTY_PROVIDER_MAX) || (store == NULL) || (*store == 0) || (key == NULL) || (*key == 0)) return RET_OS_INVALID_PARAM; CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; if (mask == 0) return RET_EXT_NO_ERROR; item.key = key; item.type = VT_BIT4; item.value.bit4.val = value; item.value.bit4.mask = mask; item.success = 0; return SetPropertyList(providerId, store, NULL, &item, 1); } INT32U ClearPropertyCache(INT32U providerId, const char *store, const char *id) { INT32U ret = RET_EXT_NO_ERROR; if (providerId >= PROPERTY_PROVIDER_MAX) return RET_OS_INVALID_PARAM; CheckInit(); if (pp[providerId].flag.init == 0) return RET_PROPERTY_NOT_INIT; if (pp[providerId].clear == NULL) return RET_EXT_NO_ERROR; if ((id == NULL) || (*id == 0)) id = pp[providerId].id; if ((id == NULL) || (*id == 0)) id = NULL; prop_lock(); CacheClear(&pp[providerId], store, id); ret = pp[providerId].clear(store, id, pp[providerId].obj); prop_unlock(); return ret; } INT32U SetPropertyTestCase(INT32U caseId) { if (caseId == 1) file_test_random = 1; // 随机数设为非0表示启用测试, 也可以设成其他非0值, 该值在测试过程中会被随机更新 else file_test_random = 0; // 随机数设为0表示禁用测试, 不会再被更新 return RET_EXT_NO_ERROR; } // INT32U VerifyPropertyCache(INT32U providerId) { // INT32U ret = RET_EXT_NO_ERROR; // prop_cache* ptr; // #if (defined RTOS_UCOS) // INT8U osErr = OS_ERR_NONE; // #endif // // if (providerId >= PROPERTY_PROVIDER_MAX) // return RET_OS_INVALID_PARAM; // CheckInit(); // if (pp[providerId].flag.init == 0) // return RET_PROPERTY_NOT_INIT; // // #if (defined RTOS_UCOS) // OSSemPend(pp[providerId].sem, OSmsToTick(1000UL), &osErr); // if (osErr != OS_ERR_NONE) // return RET_OS_SYNC_OBJ_FAILED; // #elif ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1)) // PROP_DISABLE_IRQ(); // if (pp[providerId].flag.lock != 0) // ret = RET_OS_SYNC_OBJ_FAILED; // else // pp[providerId].flag.lock = 1; // PROP_ENABLE_IRQ(); // if (ret != RET_EXT_NO_ERROR) // return ret; // #else // #error "Target error" // #endif // // for (ptr = pp[providerId].cache; ptr != NULL; ptr = ptr->next) { // if (((INT32U)ptr < 0xa0000000) || ((INT32U)ptr >= 0xa0800000)) { // ret = RET_OS_HEAP_CORRUPTED; // break; // } // ret = SBT_Check(ptr->sbt); // if (ret != RET_EXT_NO_ERROR) // break; // } // // PROP_UNLOCK(pp[providerId]); // // return ret; //} #if ((defined PROPERTY_PROV_FS_EN) && (PROPERTY_PROV_FS_EN != 0)) /************************************************************** * File property provider ************************************************************* */ typedef struct _fileprop_cache { char *key; char *value; INT32U size; struct _fileprop_cache *next; } fileprop_cache; typedef struct _file_cache { BOOL allCache; char *store; char *id; fileprop_cache *cache; struct _file_cache *next; } file_cache; typedef struct { #if (!defined RTOS_UCOS) && ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1)) struct { INT8U lock : 1; } flag; #endif struct { INT8U cache : 1; INT8U prefetch : 1; } config; #if (defined RTOS_UCOS) OS_EVENT *sem; #endif file_cache *cache; struct { INT32U flag; #if 1 FILE *fil; FILE *tmp; #endif } stream; } file_provider; #define STREAM_FLAG_FOPEN (1UL << 0) static INT32U FileCacheGet(file_cache **head, const char *store, const char *id, const char *key, char *value, INT32U size, BOOL *isNull) { file_cache *fc; fileprop_cache *pc; for (fc = *head; fc != NULL; fc = fc->next) { if ((strcmp(store, fc->store) == 0) && ((((id == NULL) || (*id == 0)) && ((fc->id == NULL) || (*fc->id == 0))) || ((id != NULL) && (fc->id != NULL) && (strcmp(id, fc->id) == 0)))) break; } if (fc == NULL) return RET_PROPERTY_NOT_FOUND; *isNull = TRUE; for (pc = fc->cache; pc != NULL; pc = pc->next) { if (strcmp(key, pc->key) == 0) { INT32U ret = RET_EXT_NO_ERROR; if (pc->value != NULL) { INT32U cpLen = pc->size; if (cpLen > size - 1) { cpLen = size - 1; ret = RET_PROPERTY_OUT_OF_VAL_BUF; } *isNull = FALSE; strncpy(value, pc->value, cpLen); value[cpLen] = 0; } return ret; } } if (fc->allCache) return RET_EXT_NO_ERROR; return RET_PROPERTY_NOT_FOUND; } static INT32U FileCacheTouch(file_cache **head, const char *store, const char *id, BOOL allCache, file_cache **found) { INT32U ret = RET_EXT_NO_ERROR; file_cache *fc; for (fc = *head; fc != NULL; fc = fc->next) { if ((strcmp(store, fc->store) == 0) && ((((id == NULL) || (*id == 0)) && ((fc->id == NULL) || (*fc->id == 0))) || ((id != NULL) && (fc->id != NULL) && (strcmp(id, fc->id) == 0)))) break; } if (fc == NULL) { BOOL fail = FALSE; fc = (file_cache *)malloc_mt(sizeof(file_cache)); if (fc == NULL) fail = TRUE; else memset(fc, 0, sizeof(file_cache)); if (!fail) { INT32U lenStore = strlen(store); fc->store = (char *)malloc_mt(lenStore + 1); if (fc->store == NULL) { fail = TRUE; } else { strncpy(fc->store, store, lenStore); fc->store[lenStore] = 0; } } if (!fail && (id != NULL) && (*id != 0)) { INT32U lenId = strlen(id); fc->id = (char *)malloc_mt(lenId + 1); if (fc->id == NULL) { fail = TRUE; } else { strncpy(fc->id, id, lenId); fc->id[lenId] = 0; } } if (fail) { if (fc != NULL) { if (fc->store != NULL) free_mt(fc->store); if (fc->id != NULL) free_mt(fc->id); free_mt(fc); fc = NULL; } ret = RET_PROPERTY_HEAP_FULL; } else { fc->allCache = allCache; fc->next = *head; *head = fc; } } if (found != NULL) *found = fc; return ret; } static INT32U FileCacheSet(file_cache **head, const char *store, const char *id, const char *key, const char *value, BOOL allCache) { INT32U ret = RET_EXT_NO_ERROR; file_cache *fc = NULL; ret = FileCacheTouch(head, store, id, allCache, &fc); if ((ret == RET_EXT_NO_ERROR) && (fc != NULL)) { fileprop_cache *pc; fileprop_cache *ptail = NULL; for (pc = fc->cache; pc != NULL; ptail = pc, pc = pc->next) { if (strcmp(key, pc->key) == 0) break; } if (pc == NULL) { BOOL fail = FALSE; pc = (fileprop_cache *)malloc_mt(sizeof(fileprop_cache)); if (pc == NULL) fail = TRUE; else memset(pc, 0, sizeof(fileprop_cache)); if (!fail) { INT32U keyLen = strlen(key); pc->key = (char *)malloc_mt(keyLen + 1); if (pc->key == NULL) { fail = TRUE; } else { strncpy(pc->key, key, keyLen); pc->key[keyLen] = 0; } } if (!fail && (value != NULL)) { pc->size = strlen(value); pc->value = (char *)malloc_mt(pc->size + 1); if (pc->value == NULL) { fail = TRUE; } else { strncpy(pc->value, value, pc->size); pc->value[pc->size] = 0; } } if (fail) { if (pc != NULL) { if (pc->key != NULL) free_mt(pc->key); if (pc->value != NULL) free_mt(pc->value); free_mt(pc); pc = NULL; } fc->allCache = FALSE; ret = RET_PROPERTY_HEAP_FULL; } else { pc->next = fc->cache; fc->cache = pc; } } else { BOOL alloc = FALSE; if (value == NULL) { free_mt(pc->key); if (pc->value != NULL) free_mt(pc->value); if (pc == fc->cache) fc->cache = pc->next; else ptail->next = pc->next; free_mt(pc); } else if (pc->value == NULL) { alloc = TRUE; } else if (pc->size >= strlen(value)) { strncpy(pc->value, value, strlen(value)); } else { if (pc->value != NULL) free_mt(pc->value); pc->value = NULL; pc->size = 0; alloc = TRUE; } if (alloc) { pc->size = strlen(value); pc->value = (char *)malloc_mt(pc->size + 1); if (pc->value == NULL) { free_mt(pc->key); if (pc == fc->cache) fc->cache = pc->next; else ptail->next = pc->next; free_mt(pc); fc->allCache = FALSE; ret = RET_PROPERTY_HEAP_FULL; } else { strncpy(pc->value, value, pc->size); pc->value[pc->size] = 0; } } } } return ret; } static INT32U FileCacheClearLinkList(fileprop_cache *ptr) { for (; ptr != NULL;) { fileprop_cache *tmp = ptr; ptr = ptr->next; free_mt(tmp->key); if (tmp->value != NULL) free_mt(tmp->value); free_mt(tmp); } return RET_EXT_NO_ERROR; } static INT32U FileCacheClear(file_cache **head, const char *store, const char *id) { file_cache *fc; if ((store == NULL) || (*store == 0)) { for (fc = *head; fc != NULL;) { file_cache *tmp = fc; fc = fc->next; FileCacheClearLinkList(tmp->cache); free_mt(tmp->store); if (tmp->id != NULL) free_mt(tmp->id); free_mt(tmp); } *head = NULL; } else if ((id == NULL) || (*id == 0)) { file_cache *ftail = NULL; for (fc = *head; fc != NULL;) { if (strcmp(store, fc->store) == 0) { file_cache *del = fc; FileCacheClearLinkList(fc->cache); free_mt(fc->store); if (fc->id != NULL) free_mt(fc->id); if (fc == *head) *head = fc->next; else ftail->next = fc->next; fc = fc->next; free_mt(del); } else { ftail = fc; fc = fc->next; } } } else { file_cache *ftail = NULL; for (fc = *head; fc != NULL; ftail = fc, fc = fc->next) { if ((strcmp(store, fc->store) == 0) && ((fc->id != NULL) && (strcmp(id, fc->id) == 0))) break; } if (fc != NULL) { FileCacheClearLinkList(fc->cache); free_mt(fc->store); if (fc->id != NULL) free_mt(fc->id); if (fc == *head) *head = fc->next; else ftail->next = fc->next; free_mt(fc); } } return RET_EXT_NO_ERROR; } static INT32U INT32U2err(INT32U fres) { #if 0 switch (fres) { case FR_OK: return RET_EXT_NO_ERROR; case FR_DISK_ERR: return RET_FILE_FR_DISK_ERR; case FR_INT_ERR: return RET_FILE_FR_INT_ERR; case FR_NOT_READY: return RET_FILE_FR_NOT_READY; case FR_NO_FILE: return RET_FILE_FR_NO_FILE; case FR_NO_PATH: return RET_FILE_FR_NO_PATH; case FR_INVALID_NAME: return RET_FILE_FR_INVALID_NAME; case FR_DENIED: return RET_FILE_FR_DENIED; case FR_EXIST: return RET_FILE_FR_EXIST; case FR_INVALID_OBJECT: return RET_FILE_FR_INVALID_OBJECT; case FR_WRITE_PROTECTED: return RET_FILE_FR_WRITE_PROTECTED; case FR_INVALID_DRIVE: return RET_FILE_FR_INVALID_DRIVE; case FR_NOT_ENABLED: return RET_FILE_FR_NOT_ENABLED; case FR_NO_FILESYSTEM: return RET_FILE_FR_NO_FILESYSTEM; case FR_MKFS_ABORTED: return RET_FILE_FR_MKFS_ABORTED; case FR_TIMEOUT: return RET_FILE_FR_TIMEOUT; // case FR_LOCKED: // return RET_FILE_FR_LOCKED; // case FR_NOT_ENOUGH_CORE: // return RET_FILE_FR_NOT_ENOUGH_CORE; // case FR_TOO_MANY_OPEN_FILES: // return RET_FILE_FR_TOO_MANY_OPEN_FILES; // case FR_INVALID_PARAMETER: // return RET_FILE_FR_INVALID_PARAMETER; } return RET_FILE_UNKNOWN; #else return 0; #endif } static void FILE_TEST_RANDOM(INT8U max) { if ((file_test_random > 0) && (max > 0)) { file_test_random = (rand() % max) + 1; printf("[TEST] file_test_random = %d", file_test_random); } } static void FILE_TEST_RESET(INT8U num) { #if 0 if (file_test_random == num) { printf("[TEST] swReset() called. file_test_random = %d", file_test_random); swReset(); } #endif } static INT32U f_copy(const char *src, const char *dest) { #if 0 FIL filSrc, filDest; INT32U fres; BYTE *buf; INT32U ret = RET_EXT_NO_ERROR; fres = f_open(&filSrc, src, FA_OPEN_EXISTING | FA_READ); if (fres != FR_OK) return INT32U2err(fres); fres = f_open(&filDest, dest, FA_CREATE_ALWAYS | FA_WRITE); if (fres != FR_OK) { f_close(&filSrc); return INT32U2err(fres); } buf = malloc_mt(COPY_BUF_SIZE); if (buf == NULL) { f_close(&filSrc); f_close(&filDest); return RET_OS_HEAP_FULL; } for (;;) { INT32U rsize, wsize; fres = f_read(&filSrc, buf, COPY_BUF_SIZE, &rsize); if (fres != FR_OK) { ret = INT32U2err(fres); break; } if (rsize == 0) break; fres = f_write(&filDest, buf, rsize, &wsize); if (rsize != wsize) { ret = RET_FILE_DISK_FULL; break; } if (fres != FR_OK) { ret = INT32U2err(fres); break; } } free_mt(buf); f_close(&filSrc); f_close(&filDest); return ret; #else return 0; #endif } static INT32U PropWriteLogClear(INT32U providerId) { #if 0 INT32U fres; char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; snprintf(logname, sizeof(logname), UPDATE_LOG, providerId); fres = f_unlink(logname); if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH)) return RET_PROPERTY_FILE_WRITE_ERR; return RET_EXT_NO_ERROR; #else return 0; #endif } static INT32U PropWriteLogWrite(INT32U providerId, const char *path) { #if 0 FIL fil; INT32U fres; char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; INT32U wsize; if (path == NULL) return RET_OS_INVALID_PARAM; snprintf(logname, sizeof(logname), UPDATE_LOG, providerId); fres = f_open(&fil, logname, FA_CREATE_ALWAYS | FA_WRITE); if (fres != FR_OK) return INT32U2err(fres); fres = f_write(&fil, path, strlen(path), &wsize); f_close(&fil); if ((fres == FR_OK) && (wsize != strlen(path))) return RET_FILE_DISK_FULL; return INT32U2err(fres); #else return 0; #endif } static INT32U PropWriteLogLoad(INT32U providerId, char *path, INT32U size) { #if 0 FIL fil; INT32U fres; INT32U rsize = 0; INT32U i; char logname[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; if (path == NULL || size == 0) return RET_OS_INVALID_PARAM; path[0] = '\0'; snprintf(logname, sizeof(logname), UPDATE_LOG, providerId); fres = f_open(&fil, logname, FA_OPEN_EXISTING | FA_READ); if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH)) return RET_EXT_NO_ERROR; if (fres != FR_OK) return INT32U2err(fres); fres = f_read(&fil, path, size, &rsize); f_close(&fil); if (rsize == size) path[size - 1] = '\0'; for (i = 0; path[i] != '\0'; i++) if (path[i] == '\r' || path[i] == '\n') { path[i] = '\0'; break; } if (fres == FR_OK) { char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; snprintf(filetmp, sizeof(filetmp), "%s.tmp", path); fres = f_open(&fil, filetmp, FA_OPEN_EXISTING | FA_READ); f_close(&fil); if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH)) { fres = FR_OK; path[0] = '\0'; } } if (fres != FR_OK) path[0] = '\0'; return INT32U2err(fres); #else return 0; #endif } static INT32U PropWriteLogCommit(INT32U providerId, const char *filename) { #if 0 INT32U ret = RET_EXT_NO_ERROR; INT32U fres; char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; snprintf(filetmp, sizeof(filetmp), "%s.tmp", filename); FILE_TEST_RESET(1); fres = f_unlink(filename); if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH)) ret = RET_PROPERTY_FILE_WRITE_ERR; FILE_TEST_RESET(2); if (ret == RET_EXT_NO_ERROR) ret = f_copy(filetmp, filename); FILE_TEST_RESET(3); if (ret == RET_EXT_NO_ERROR) ret = PropWriteLogClear(providerId); FILE_TEST_RESET(4); if (ret == RET_EXT_NO_ERROR) { INT32U fres = f_unlink(filetmp); if ((fres != FR_OK) && (fres != FR_NO_FILE) && (fres != FR_NO_PATH)) ret = RET_PROPERTY_FILE_WRITE_ERR; } FILE_TEST_RESET(5); return ret; #else return 0; #endif } #if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0)) static void FormatSHA1sum(char *buf, INT32U lenOfBuf, INT8U *sig, INT32U lenOfSig) { INT8U i = 0; for (i = 0; i < lenOfSig; i++) snprintf(&buf[i << 1], (lenOfBuf - (i << 1)), "%02x", sig[i]); buf[lenOfBuf - 1] = '\0'; } #endif // TODO:启用sha校验 static INT32U FileStreamChecksum(const char *filename) { #if (((defined DISTRIBUTION) || (PROPERTY_CHECKSUM_ENABLED != 0)) && (PROPERTY_CHECKSUM_DISABLED == 0)) FIL fil; INT8U buf[128]; INT8U hash[32]; char sigStr[sizeof(hash) * 2 + 1]; char sigName[PROPERTY_STORE_MAX + 20]; sha2_context ctx; INT32U fres; INT32U br; INT32U ret = RET_EXT_NO_ERROR; if ((filename == NULL) || (*filename == 0)) return RET_EXT_NO_ERROR; fres = f_open(&fil, filename, FA_OPEN_EXISTING | FA_READ); if ((fres == FR_NO_FILE) || (fres == FR_NO_PATH)) return RET_EXT_NO_ERROR; if (fres != FR_OK) return RET_PROPERTY_INVALID_SIGNATURE; // RET_PROPERTY_FILE_OPEN_ERR sha2_starts(&ctx, 0); // TODO: 加入其他信息校验信息 for (;;) { if (f_read(&fil, buf, sizeof(buf), &br) != FR_OK) { ret = RET_PROPERTY_INVALID_SIGNATURE; // RET_PROPERTY_FILE_READ_ERR break; } if (br == 0) break; // TODO: 加入加密算法 sha2_update(&ctx, buf, br); } f_close(&fil); sha2_finish(&ctx, hash); if (ret != RET_EXT_NO_ERROR) return ret; snprintf(sigName, sizeof(sigName), "%s.sig", filename); fres = f_open(&fil, sigName, FA_OPEN_EXISTING | FA_READ); if (fres != FR_OK) return RET_PROPERTY_INVALID_SIGNATURE; if ((f_read(&fil, sigStr, (sizeof(hash) * 2), &br) != FR_OK) || (br != (sizeof(hash) * 2))) ret = RET_PROPERTY_INVALID_SIGNATURE; f_close(&fil); sigStr[sizeof(hash) * 2] = '\0'; if (ret == RET_EXT_NO_ERROR) { char hashStr[sizeof(hash) * 2 + 1]; FormatSHA1sum(hashStr, sizeof(hashStr), hash, sizeof(hash)); if (strcmp(hashStr, sigStr) != 0) ret = RET_PROPERTY_INVALID_SIGNATURE; } return ret; #else return RET_EXT_NO_ERROR; #endif } static INT32U FileStreamOpen(const char *filename, file_provider *fp) { #if 0 INT32U ret = RET_EXT_NO_ERROR; INT32U fres; if ((filename == NULL) || (*filename == 0) || (fp == NULL)) return RET_OS_INVALID_PARAM; fp->stream.flag = 0; fres = f_open(&fp->stream.fil, filename, FA_OPEN_EXISTING | FA_READ); if (fres == FR_OK) { fp->stream.flag |= STREAM_FLAG_FOPEN; } else if ((fres != FR_NO_FILE) && (fres != FR_NO_PATH)) { ret = RET_PROPERTY_FILE_OPEN_ERR; } return ret; #else INT32U ret = RET_EXT_NO_ERROR; INT32U fres; if ((filename == NULL) || (*filename == 0) || (fp == NULL)) return RET_OS_INVALID_PARAM; fp->stream.flag = 0; fp->stream.fil = fopen(filename, "r"); // printf("file name : %s\n",filename); if (fp->stream.fil != NULL) { // printf("file read ok \n"); // 读取到文件了 fp->stream.flag |= STREAM_FLAG_FOPEN; } else { ret = RET_PROPERTY_FILE_OPEN_ERR; } return ret; #endif } static INT32U FileStreamClose(file_provider *fp) { #if 0 if (fp == NULL) return RET_OS_INVALID_PARAM; if ((fp->stream.flag & STREAM_FLAG_FOPEN) != 0) f_close(&fp->stream.fil); fp->stream.flag = 0; return RET_EXT_NO_ERROR; #else // 指针检查 if (fp == NULL) return RET_OS_INVALID_PARAM; // 关闭文件 if ((fp->stream.flag & STREAM_FLAG_FOPEN) != 0) fclose(fp->stream.fil); fp->stream.fil = NULL; fp->stream.flag = 0; return 0; #endif } static INT32U FileStreamGet(char *ch, file_provider *fp) { #if 0 if ((ch == NULL) || (fp == NULL)) return RET_OS_INVALID_PARAM; if ((fp->stream.flag & STREAM_FLAG_FOPEN) == 0) { *ch = 0; } else { INT32U br; if (f_read(&fp->stream.fil, ch, 1, &br) != FR_OK) return RET_PROPERTY_FILE_READ_ERR; if (br == 0) *ch = 0; } return RET_EXT_NO_ERROR; #else // 指针检查 if ((ch == NULL) || (fp == NULL)) return RET_OS_INVALID_PARAM; // 检查下文件是否打开 if ((fp->stream.flag & STREAM_FLAG_FOPEN) == 0) { // ch = 0 的话,后续程序会直接退出 *ch = 0; } else { *ch = fgetc(fp->stream.fil); // 检查是是否读取错误 if (ferror(fp->stream.fil) != 0) { *ch = 0; } } return 0; #endif } static INT32U FileStreamParseLine(BOOL *eof, BOOL *valid, char *lineBuffer, INT32U bufferSize, INT32U *keyIndex, INT32U *keyLen, INT32U *valIndex, INT32U *valLen, file_provider *fp) { #if 0 static const INT8U PARSE_STATE_NEW = 0; static const INT8U PARSE_STATE_SKIP = 1; static const INT8U PARSE_STATE_KEY_READING = 2; static const INT8U PARSE_STATE_KEY_FINISHED = 3; static const INT8U PARSE_STATE_STRING_TRIM = 4; static const INT8U PARSE_STATE_STRING_READING = 5; INT8U state = PARSE_STATE_NEW; INT32U ptr = 0; BOOL stop = FALSE; if ((eof == NULL) || (valid == NULL) || (lineBuffer == NULL) || (bufferSize == 0) || (keyIndex == NULL) || (keyLen == NULL) || (valIndex == NULL) || (valLen == NULL) || (fp == NULL)) return RET_OS_INVALID_PARAM; *valid = FALSE; for (; !stop;) { char ch = 0; INT32U ret = FileStreamGet(&ch, fp); if (ret != RET_EXT_NO_ERROR) return ret; if (ch != 0) { if (ptr < bufferSize - 1) { lineBuffer[ptr++] = ch; } else { if (((ch == '\r') || (ch == '\n')) && (ptr == bufferSize - 1)) lineBuffer[ptr - 1] = ch; state = PARSE_STATE_SKIP; *valid = FALSE; } } switch (state) { case PARSE_STATE_NEW: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { *keyIndex = ptr - 1; state = PARSE_STATE_KEY_READING; } else if (ch == ' ' || ch == '\t') { // do nothing } else if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else { state = PARSE_STATE_SKIP; } break; case PARSE_STATE_KEY_READING: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '.') || (ch == '-') || (ch == '_') || (ch == '[') || (ch == ']')) { } else if (ch == '=') { *keyLen = ptr - *keyIndex - 1; state = PARSE_STATE_STRING_TRIM; } else if (ch == ' ' || ch == '\t') { *keyLen = ptr - *keyIndex - 1; state = PARSE_STATE_KEY_FINISHED; } else if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else { state = PARSE_STATE_SKIP; } break; case PARSE_STATE_KEY_FINISHED: if (ch == '=') { state = PARSE_STATE_STRING_TRIM; } else if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else if (ch != ' ' && ch != '\t') { state = PARSE_STATE_SKIP; } break; case PARSE_STATE_STRING_TRIM: if (ch == '\r' || ch == '\n' || ch == 0) { *valIndex = ptr - 1; *valLen = 0; *valid = TRUE; *eof = (ch == 0); stop = TRUE; } else if (ch != ' ' && ch != '\t') { *valIndex = ptr - 1; *valLen = 1; *valid = TRUE; state = PARSE_STATE_STRING_READING; } break; case PARSE_STATE_STRING_READING: if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else if ((ch != ' ') && (ch != '\t')) { *valLen = ptr - *valIndex; } break; case PARSE_STATE_SKIP: default: if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } // state = PARSE_STATE_SKIP; break; } } lineBuffer[ptr] = 0; return RET_EXT_NO_ERROR; #else #define PARSE_STATE_NEW 0 #define PARSE_STATE_SKIP 1 #define PARSE_STATE_KEY_READING 2 #define PARSE_STATE_KEY_FINISHED 3 #define PARSE_STATE_STRING_TRIM 4 #define PARSE_STATE_STRING_READING 5 INT8U state = PARSE_STATE_NEW; INT32U ptr = 0; BOOL stop = FALSE; if ((eof == NULL) || (valid == NULL) || (lineBuffer == NULL) || (bufferSize == 0) || (keyIndex == NULL) || (keyLen == NULL) || (valIndex == NULL) || (valLen == NULL) || (fp == NULL)) return RET_OS_INVALID_PARAM; *valid = FALSE; for (; !stop;) { char ch = 0; INT32U ret = FileStreamGet(&ch, fp); if (ret != RET_EXT_NO_ERROR) return ret; if (ch != 0) { if (ptr < bufferSize - 1) { lineBuffer[ptr++] = ch; } else { if (((ch == '\r') || (ch == '\n')) && (ptr == bufferSize - 1)) lineBuffer[ptr - 1] = ch; state = PARSE_STATE_SKIP; *valid = FALSE; } } switch (state) { case PARSE_STATE_NEW: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) { *keyIndex = ptr - 1; state = PARSE_STATE_KEY_READING; } else if (ch == ' ' || ch == '\t') { // do nothing } else if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else { state = PARSE_STATE_SKIP; } break; case PARSE_STATE_KEY_READING: if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9') || (ch == '.') || (ch == '-') || (ch == '_') || (ch == '[') || (ch == ']')) { } else if (ch == '=') { *keyLen = ptr - *keyIndex - 1; state = PARSE_STATE_STRING_TRIM; } else if (ch == ' ' || ch == '\t') { *keyLen = ptr - *keyIndex - 1; state = PARSE_STATE_KEY_FINISHED; } else if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else { state = PARSE_STATE_SKIP; } break; case PARSE_STATE_KEY_FINISHED: if (ch == '=') { state = PARSE_STATE_STRING_TRIM; } else if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else if (ch != ' ' && ch != '\t') { state = PARSE_STATE_SKIP; } break; case PARSE_STATE_STRING_TRIM: if (ch == '\r' || ch == '\n' || ch == 0) { *valIndex = ptr - 1; *valLen = 0; *valid = TRUE; *eof = (ch == 0); stop = TRUE; } else if (ch != ' ' && ch != '\t') { *valIndex = ptr - 1; *valLen = 1; *valid = TRUE; state = PARSE_STATE_STRING_READING; } break; case PARSE_STATE_STRING_READING: if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } else if ((ch != ' ') && (ch != '\t')) { *valLen = ptr - *valIndex; } break; case PARSE_STATE_SKIP: default: if (ch == '\r' || ch == '\n' || ch == 0) { *eof = (ch == 0); stop = TRUE; } // state = PARSE_STATE_SKIP; break; } } lineBuffer[ptr] = 0; #undef PARSE_STATE_NEW #undef PARSE_STATE_SKIP #undef PARSE_STATE_KEY_READING #undef PARSE_STATE_KEY_FINISHED #undef PARSE_STATE_STRING_TRIM #undef PARSE_STATE_STRING_READING return RET_EXT_NO_ERROR; #endif } static INT32U FileStreamPropertyGet(const char *store, const char *id, const char *key, char *value, INT32U size, BOOL *isNull, file_provider *fp) { #if 0 char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; char buffer[PROPERTY_LINE_MAX + 2]; INT32U ret = RET_EXT_NO_ERROR; #if (defined RTOS_UCOS) INT8U osRet = OS_ERR_NONE; #endif if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (fp == NULL) || (isNull == NULL)) return RET_OS_INVALID_PARAM; if ((id == NULL) || (*id == 0)) snprintf(filename, sizeof(filename), "0:/conf/%s.conf", store); else snprintf(filename, sizeof(filename), "0:/conf/%s.%s.conf", store, id); #if (defined RTOS_UCOS) OSSemPend(fp->sem, OSmsToTick(1000UL), &osRet); if (osRet != OS_ERR_NONE) return RET_OS_SYNC_OBJ_FAILED; #elif ((defined TARGET_LPC11XX) || (defined TARGET_STM32F1)) PROP_DISABLE_IRQ(); if (pp[providerId].flag.lock != 0) ret = RET_OS_SYNC_OBJ_FAILED; else pp[providerId].flag.lock = 1; PROP_ENABLE_IRQ(); if (ret != RET_EXT_NO_ERROR) return ret; #else #error "Target error" #endif ret = FileCacheGet(&fp->cache, store, id, key, value, size, isNull); if ((ret != RET_EXT_NO_ERROR) && (ret != RET_PROPERTY_OUT_OF_VAL_BUF)) { *isNull = TRUE; if ((id == NULL) || (*id == 0)) // global config file, checksum is required. ret = FileStreamChecksum(filename); else ret = RET_EXT_NO_ERROR; if (ret == RET_EXT_NO_ERROR) ret = FileStreamOpen(filename, fp); if (ret == RET_EXT_NO_ERROR) { for (;;) { BOOL eof = FALSE; BOOL valid = FALSE; INT32U keyIndex = 0; INT32U keyLen = 0; INT32U valIndex = 0; INT32U valLen = 0; ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp); if (ret != RET_EXT_NO_ERROR) break; if (valid) { BOOL match = FALSE; if ((keyLen == strlen(key)) && (strncmp(&buffer[keyIndex], key, keyLen) == 0)) { if (valLen > size - 1) { valLen = size - 1; ret = RET_PROPERTY_OUT_OF_VAL_BUF; } *isNull = FALSE; strncpy(value, &buffer[valIndex], valLen); value[valLen] = 0; match = TRUE; } if (fp->config.cache && (match || fp->config.prefetch)) { buffer[keyIndex + keyLen] = 0; buffer[valIndex + valLen] = 0; FileCacheSet(&fp->cache, store, id, &buffer[keyIndex], &buffer[valIndex], fp->config.prefetch); } if (match && !fp->config.prefetch) break; } if (eof) break; } if ((ret == RET_EXT_NO_ERROR) && fp->config.prefetch) { file_cache *cache = NULL; FileCacheTouch(&fp->cache, store, id, TRUE, &cache); if (cache != NULL) cache->allCache = TRUE; } } FileStreamClose(fp); } PROP_UNLOCK(*fp); return ret; #else char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; char buffer[PROPERTY_LINE_MAX + 2]; INT32U ret = RET_EXT_NO_ERROR; if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (fp == NULL) || (isNull == NULL)) return RET_OS_INVALID_PARAM; if ((id == NULL) || (*id == 0)) snprintf(filename, sizeof(filename), "%s/%s.conf", config_path, store); ret = FileCacheGet(&fp->cache, store, id, key, value, size, isNull); if ((ret != RET_EXT_NO_ERROR) && (ret != RET_PROPERTY_OUT_OF_VAL_BUF)) { *isNull = TRUE; // TODO: #if 0 if ((id == NULL) || (*id == 0)) // global config file, checksum is required. ret = FileStreamChecksum(filename); else ret = RET_EXT_NO_ERROR; #else ret = RET_EXT_NO_ERROR; #endif if (ret == RET_EXT_NO_ERROR) { // 打开文件 ret = FileStreamOpen(filename, fp); // printf("ret = %d\n", ret); } if (ret == RET_EXT_NO_ERROR) { #if 0 //逻辑重写 for (;;) { BOOL eof = FALSE; BOOL valid = FALSE; INT32U keyIndex = 0; INT32U keyLen = 0; INT32U valIndex = 0; INT32U valLen = 0; // 读取单条 ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp); if (ret != RET_EXT_NO_ERROR) break; if (valid) { BOOL match = FALSE; if ((keyLen == strlen(key)) && (strncmp(&buffer[keyIndex], key, keyLen) == 0)) { if (valLen > size - 1) { valLen = size - 1; ret = RET_PROPERTY_OUT_OF_VAL_BUF; } *isNull = FALSE; strncpy(value, &buffer[valIndex], valLen); value[valLen] = 0; match = TRUE; } if (fp->config.cache && (match || fp->config.prefetch)) { buffer[keyIndex + keyLen] = 0; buffer[valIndex + valLen] = 0; FileCacheSet(&fp->cache, store, id, &buffer[keyIndex], &buffer[valIndex], fp->config.prefetch); } if (match && !fp->config.prefetch) break; } if (eof) break; } #else while (1) { char temp[100]; void *result = fgets(temp, sizeof(temp), fp->stream.fil); if (result != NULL) { // printf("%s\n", temp); // 搜索到正常的头部 if ((temp[0] >= 'a' && temp[0] <= 'z') || (temp[0] >= 'A' && temp[0] <= 'Z')) { // 比对key的情况,key必须顶格写 int i = 0; int result = 1; while (key[i] != '\0') { if (temp[i] != key[i]) { result = 0; break; } if (temp[i] == '=') { result = 0; break; } i++; } // 防守配置文件里面的key更长,但是后面不相符的情况 if (temp[i] != '=') { result = 0; } //截断字符串 temp[i] = '\0'; // printf("result : %d ; key = %s ; serch = %s\n", result, key, temp); // 找到目标 if (result == 1) { // 将值拷贝出去 *isNull = FALSE; i++; int j = 0; while (1) { value[j] = temp[i]; j++; i++; if (temp[i] == ' ' || temp[i] == '\r' || temp[i] == '\t' || temp[i] == '\n') { break; } if (j >= (size - 1)) { // 给的缓存太小了,报个错 return RET_PROPERTY_OUT_OF_VAL_BUF; } } value[j] = '\0'; printf("get value = %s\n", value); // 设置chache if (fp->config.cache && (fp->config.prefetch)) { FileCacheSet(&fp->cache, store, id, temp, value, fp->config.prefetch); } } } // 说明读到尾部了 if (feof(fp->stream.fil) == 1) { // printf("file end\n"); break; } } else { // 读取失败,退出循环 // printf("file read error\n"); break; } } #endif if ((ret == RET_EXT_NO_ERROR) && fp->config.prefetch) { file_cache *cache = NULL; FileCacheTouch(&fp->cache, store, id, TRUE, &cache); if (cache != NULL) cache->allCache = TRUE; } } FileStreamClose(fp); } return ret; #endif } static INT32U FileStreamPropertySet(const char *store, const char *id, property_string_item *list, INT32U count, file_provider *fp) { #if 0 char filename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; char filetmp[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 20]; char buffer[PROPERTY_LINE_MAX + 2]; INT32U ret = RET_EXT_NO_ERROR; #if (defined RTOS_UCOS) INT8U osRet = OS_ERR_NONE; #endif BOOL newLine = FALSE; BOOL changed = FALSE; INT32U idx; if ((store == NULL) || (*store == 0) || (list == NULL) || (count == 0) || (fp == NULL)) return RET_OS_INVALID_PARAM; if ((id == NULL) || (*id == 0)) return RET_PROPERTY_INVALID_STORE_ID; for (idx = 0; idx < count; idx++) { if ((list[idx].key == NULL) || (*list[idx].key == 0)) return RET_OS_INVALID_PARAM; list[idx].success = 0; } snprintf(filename, sizeof(filename), "%s/%s.%s.conf", config_path, store, id); snprintf(filetmp, sizeof(filetmp), "%s/%s.%s.conf.tmp", config_path, store, id); FILE_TEST_RANDOM(8); if (f_open(&fp->stream.tmp, filetmp, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) ret = RET_PROPERTY_FILE_OPEN_ERR; if (ret == RET_EXT_NO_ERROR) { ret = FileStreamOpen(filename, fp); if (ret == RET_EXT_NO_ERROR) { for (;;) { BOOL skip = FALSE; BOOL eof = FALSE; BOOL valid = FALSE; INT32U keyIndex = 0; INT32U keyLen = 0; INT32U valIndex = 0; INT32U valLen = 0; INT32U bw; char lastCh; ret = FileStreamParseLine(&eof, &valid, buffer, sizeof(buffer), &keyIndex, &keyLen, &valIndex, &valLen, fp); if (ret != RET_EXT_NO_ERROR) break; bw = strlen(buffer); lastCh = ((bw > 0) ? buffer[bw - 1] : '\0'); if ((lastCh != '\r') && (lastCh != '\n') && (bw > 0)) newLine = TRUE; if (valid) { for (idx = 0; idx < count; idx++) { if (list[idx].success) continue; if ((keyLen != strlen(list[idx].key)) || (strncmp(&buffer[keyIndex], list[idx].key, keyLen) != 0)) continue; if (list[idx].value == NULL) { skip = TRUE; } else { if ((lastCh == '\r') || (lastCh == '\n')) snprintf(buffer, sizeof(buffer), "%s=%s%c", list[idx].key, list[idx].value, lastCh); else snprintf(buffer, sizeof(buffer), "%s=%s", list[idx].key, list[idx].value); bw = strlen(buffer); } if (fp->config.cache) FileCacheSet(&fp->cache, store, id, list[idx].key, list[idx].value, FALSE); list[idx].success = 1; changed = TRUE; break; } } if (!skip) { if (f_write(&fp->stream.tmp, buffer, bw, &bw) != FR_OK) { ret = RET_PROPERTY_FILE_WRITE_ERR; break; } } if (eof) break; } } if (ret == RET_EXT_NO_ERROR) { for (idx = 0; idx < count; idx++) { INT32U bw; if (list[idx].success) continue; if (list[idx].value == NULL) { list[idx].success = 1; continue; } if (newLine) { newLine = FALSE; bw = strlen("\r\n"); if (f_write(&fp->stream.tmp, "\r\n", bw, &bw) != FR_OK) { ret = RET_PROPERTY_FILE_WRITE_ERR; break; } } snprintf(buffer, sizeof(buffer), "%s=%s\r\n", list[idx].key, list[idx].value); bw = strlen(buffer); if (f_write(&fp->stream.tmp, buffer, bw, &bw) != 0) { ret = RET_PROPERTY_FILE_WRITE_ERR; break; } if (fp->config.cache) FileCacheSet(&fp->cache, store, id, list[idx].key, list[idx].value, FALSE); list[idx].success = 1; changed = TRUE; } } FileStreamClose(fp); f_close(&fp->stream.tmp); // a. 将修改后的配置写入*.conf.tmp // b. 将字符串"*.conf"写入update.log // c. 删除*.conf // d. 复制*.conf.tmp-> *.conf // e. 删除update.log // f. 删除 *.conf.tmp if (ret == RET_EXT_NO_ERROR) ret = PropWriteLogWrite(0, filename); if (ret == RET_EXT_NO_ERROR) PropWriteLogCommit(0, filename); } if (changed && (ret != RET_EXT_NO_ERROR)) FileCacheClear(&fp->cache, store, id); PROP_UNLOCK(*fp); if (ret != RET_EXT_NO_ERROR) { for (idx = 0; idx < count; idx++) list[idx].success = 0; } return ret; #else return 0; #endif } /** function comment * @description: * @param {char} *store * @param {char} *key * @param {char} *id 看上去没有用,直接用的NULL * @param {char} *value * @param {INT32U} sizeOfValue * @param {BOOL} *isLocal * @param {void} *obj * @return {*} */ static INT32U FilePropertyGet(const char *store, const char *key, const char *id, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj) { BOOL isNull = TRUE; INT32U ret = RET_PROPERTY_NOT_FOUND; file_provider *fp = (file_provider *)obj; if (fp == NULL) return RET_OS_INVALID_PARAM; if (isLocal != NULL) *isLocal = FALSE; // id在实际应用中没有找到 if ((id != NULL) && (*id != 0)) { ret = FileStreamPropertyGet(store, id, key, value, sizeOfValue, &isNull, fp); if ((ret == RET_EXT_NO_ERROR) && isNull) ret = RET_PROPERTY_NOT_FOUND; if ((ret == RET_EXT_NO_ERROR) && (isLocal != NULL)) *isLocal = TRUE; } if (ret == RET_PROPERTY_NOT_FOUND) { ret = FileStreamPropertyGet(store, NULL, key, value, sizeOfValue, &isNull, fp); if ((ret == RET_EXT_NO_ERROR) && isNull) ret = RET_PROPERTY_NOT_FOUND; } return ret; } static INT32U FilePropertySet(const char *store, const char *id, property_string_item *list, INT32U count, void *obj) { file_provider *fp = (file_provider *)obj; if (fp == NULL) return RET_OS_INVALID_PARAM; if ((id != NULL) && (*id != 0)) return FileStreamPropertySet(store, id, list, count, fp); else return RET_PROPERTY_INVALID_STORE_ID; } static INT32U FilePropertyClear(const char *store, const char *id, void *obj) { INT32U ret = RET_EXT_NO_ERROR; file_provider *fp = (file_provider *)obj; if (fp == NULL) return RET_OS_INVALID_PARAM; if (!fp->config.cache) return RET_EXT_NO_ERROR; if ((id == NULL) || (*id == 0)) id = NULL; if (ret == RET_EXT_NO_ERROR) ret = FileCacheClear(&fp->cache, store, id); return ret; } static INT32U FilePropertyInit(INT32U providerId, const PropertyInitParam *param) { INT32U ret = RET_EXT_NO_ERROR; file_provider *fp = NULL; if (ret == RET_EXT_NO_ERROR) { fp = (file_provider *)malloc_mt(sizeof(file_provider)); if (fp == NULL) ret = RET_PROPERTY_HEAP_FULL; } if (ret == RET_EXT_NO_ERROR) { char storename[PROPERTY_STORE_MAX + PROPERTY_ID_MAX + 16]; INT32U ret2 = RET_EXT_NO_ERROR; memset(fp, 0, sizeof(file_provider)); fp->config.cache = param->config.cache; fp->config.prefetch = (param->config.cache && param->config.prefetch); fp->cache = NULL; pp[providerId].get = FilePropertyGet; pp[providerId].set = FilePropertySet; pp[providerId].clear = FilePropertyClear; pp[providerId].obj = fp; pp[providerId].flag.cache = param->config.cache; pp[providerId].flag.init = 1; #if 0 // 意义不明,没有storename ret2 = PropWriteLogLoad(providerId, storename, sizeof(storename)); if ((ret2 == RET_EXT_NO_ERROR) && (storename[0] != '\0')) { printf("PropWriteLogCommit(providerId=%d, storename=%s)\n\r", providerId, storename); PropWriteLogCommit(providerId, storename); } #endif } else { if (fp != NULL) free_mt(fp); } return ret; } #endif #if ((defined PROPERTY_PROV_REMOTE_EN) && (PROPERTY_PROV_REMOTE_EN != 0)) /************************************************************** * Remote property provider ************************************************************* */ typedef struct { INT32U destId; } remote_provider; static INT32U RemotePropertyGet(const char *store, const char *key, const char *id, char *value, INT32U sizeOfValue, BOOL *isLocal, void *obj) { INT8U outBuf[PROPERTY_LINE_MAX + sizeof(INT32U)]; INT8U *inBuf; INT8U *ptr; INT32U sizeOfIn; INT32U sizeOfOut; INT32U ret = RET_EXT_NO_ERROR; if ((store == NULL) || (*store == 0) || (key == NULL) || (*key == 0) || (value == NULL) || (obj == NULL)) return RET_OS_INVALID_PARAM; sizeOfIn = strlen(store) + strlen(key) + 3; if (id != NULL) sizeOfIn += strlen(id); inBuf = (INT8U *)malloc_mt(sizeOfIn); if (inBuf == NULL) return RET_PROPERTY_HEAP_FULL; ptr = inBuf; memcpy(ptr, store, (strlen(store) + 1)); ptr += (strlen(store) + 1); if (id == NULL) { *ptr = 0; ptr++; } else { memcpy(ptr, id, (strlen(id) + 1)); ptr += (strlen(id) + 1); } memcpy(ptr, key, (strlen(key) + 1)); sizeOfOut = (PROPERTY_LINE_MAX + sizeof(INT32U)); ret = bus_host_execute(((remote_provider *)obj)->destId, 2, CMD_mgrGetProp, inBuf, sizeOfIn, outBuf, &sizeOfOut, NULL, NULL, NULL, NULL); if (ret == RET_EXT_NO_ERROR) { if ((sizeOfOut > sizeof(INT32U)) && (outBuf[sizeOfOut - 1] == '\0')) { if (isLocal != NULL) *isLocal = (((outBuf[0] & 0x01) == 0) ? FALSE : TRUE); strncpy(value, (const char *)&outBuf[sizeof(INT32U)], sizeOfValue); value[sizeOfValue - 1] = 0; } else { ret = RET_BUS_INVALID_RET_FORMAT; } } free_mt(inBuf); return ret; } static INT32U RemotePropertySet(const char *store, const char *id, property_string_item *list, INT32U count, void *obj) { INT32U i; INT8U *inBuf; INT8U *ptr; INT32U sizeOfIn; INT32U sizeOfOut = 0; INT32U ret = RET_EXT_NO_ERROR; if ((store == NULL) || (*store == 0) || (list == NULL) || (count == 0) || (obj == NULL)) return RET_OS_INVALID_PARAM; if (count > 0xff) return RET_PROPERTY_SETP_LIST_EXCEED_MAX; sizeOfIn = (strlen(store) + 2); if ((id != NULL) && (*id != 0)) sizeOfIn += strlen(id); sizeOfIn += sizeof(INT8U); for (i = 0; i < count; i++) { if ((list[i].key == NULL) || (*list[i].key == 0)) return RET_OS_INVALID_PARAM; sizeOfIn += sizeof(INT8U); sizeOfIn += (strlen(list[i].key) + 2); if ((list[i].value != NULL) && (*list[i].value != 0)) sizeOfIn += strlen(list[i].value); } inBuf = (INT8U *)malloc_mt(sizeOfIn); if (inBuf == NULL) return RET_PROPERTY_HEAP_FULL; ptr = inBuf; memcpy(ptr, store, (strlen(store) + 1)); ptr += (strlen(store) + 1); if (id == NULL) { *ptr = 0; ptr++; } else { memcpy(ptr, id, (strlen(id) + 1)); ptr += (strlen(id) + 1); } *ptr = (count & 0xff); ptr++; for (i = 0; i < count; i++) { list[i].success = 0; if (list[i].value == NULL) *ptr = 0x01; // clear property else *ptr = 0x00; // set property ptr++; memcpy(ptr, list[i].key, (strlen(list[i].key) + 1)); ptr += (strlen(list[i].key) + 1); if (list[i].value == NULL) { *ptr = 0; ptr++; } else { memcpy(ptr, list[i].value, (strlen(list[i].value) + 1)); ptr += (strlen(list[i].value) + 1); } } ret = bus_host_execute(((remote_provider *)obj)->destId, 2, CMD_mgrSetPropL, inBuf, sizeOfIn, NULL, &sizeOfOut, NULL, NULL, NULL, NULL); if (ret == RET_EXT_NO_ERROR) { for (i = 0; i < count; i++) list[i].success = 0; } free_mt(inBuf); return ret; } static INT32U RemotePropertyClear(const char *store, const char *id, void *obj) { // RemotePropertyClear(), 远端缓存不需要客户端清除, 由远端根据实际情况自行决定 return RET_EXT_NO_ERROR; } static INT32U RemotePropertyInit(INT32U providerId, const PropertyInitParam *param) { INT32U ret = RET_EXT_NO_ERROR; remote_provider *rp = (remote_provider *)malloc_mt(sizeof(remote_provider)); if (rp == NULL) ret = RET_PROPERTY_HEAP_FULL; if (ret == RET_EXT_NO_ERROR) { memset(rp, 0, sizeof(remote_provider)); rp->destId = param->destId; pp[providerId].get = RemotePropertyGet; pp[providerId].set = RemotePropertySet; pp[providerId].clear = RemotePropertyClear; pp[providerId].obj = rp; pp[providerId].flag.cache = param->config.cache; pp[providerId].flag.init = 1; } else { if (rp != NULL) free_mt(rp); } return ret; } #endif #if 1 // store name static char propStoreSystem[40] = "0x1820_system"; static char propStorePanel[40] = "0x1820_0x0000_panel"; static char propStoreTarget[40] = "0x1820_0x0000_target"; static char propStorePipette[40] = "0x1820_0x0000_pipette"; static char propStoreTip[40] = "0x1820_0x0000_tip"; static char propStoreContainer[40] = "0x1820_0x0000_container"; static char propStoreMotor[40] = "0x1820_0x0000_motor"; static char propStoreDispense[40] = "0x1820_0x0000_dispense"; static char propStoreDevMapping[40] = "0x1820_0x0000_dm"; static char propStoreRoute[40] = "0x1820_0x0000_route"; static char propStoreDiv[40] = "0x1820_0x0000_div"; static char propStoreModule[40] = "0x1820_0x0000_module"; static char propStoreWash[40] = "0x1820_0x0000_wash"; static char propStoreRea[40] = "0x1820_0x0000_reagentplate"; const char *GetStoreName(const char *store) { if (store == NULL) return NULL; if (strcmp(store, "motor") == 0) return propStoreMotor; if (strcmp(store, "panel") == 0) return propStorePanel; if (strcmp(store, "target") == 0) return propStoreTarget; if (strcmp(store, "pipette") == 0) return propStorePipette; if (strcmp(store, "tip") == 0) return propStoreTip; if (strcmp(store, "container") == 0) return propStoreContainer; if (strcmp(store, "dispense") == 0) return propStoreDispense; if (strcmp(store, "module") == 0) return propStoreModule; if (strcmp(store, "dm") == 0) return propStoreDevMapping; if (strcmp(store, "route") == 0) return propStoreRoute; if (strcmp(store, "div") == 0) return propStoreDiv; if (strcmp(store, "system") == 0) return propStoreSystem; if (strcmp(store, "wash") == 0) return propStoreWash; return NULL; } //unit test int main(void) { INT32U retCode = RET_EXT_NO_ERROR; PropertyInitParam param; param.config.cache = 1; param.config.prefetch = 1; param.id = 0; param.type = PropertyTypeFS; PropertyInit(0, ¶m); INT32U ret = 0; INT32U val = GetUnsigned(0, "0x1820_0x0000_container", "Container0.Bottom", 0, 0, &ret, NULL); printf("%d,%d\n", val, ret); val = GetUnsigned(0, "0x1820_0x0000_container", "Container0.Bottom", 0, 0, &ret, NULL); printf("%d,%d\n", val, ret); } #endif