• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "param_trie.h"
17 
18 #include <errno.h>
19 
20 #include "init_param.h"
21 #include "param_base.h"
22 #include "param_manager.h"
23 #include "param_osadp.h"
24 #include "param_utils.h"
25 
GetRealFileName(WorkSpace * workSpace,char * buffer,uint32_t size)26 static int GetRealFileName(WorkSpace *workSpace, char *buffer, uint32_t size)
27 {
28     int ret = ParamSprintf(buffer, size, "%s/%s", PARAM_STORAGE_PATH, workSpace->fileName);
29     PARAM_CHECK(ret > 0, return -1, "Failed to copy file name %s", workSpace->fileName);
30     buffer[ret] = '\0';
31     return 0;
32 }
33 
InitWorkSpace_(WorkSpace * workSpace,uint32_t spaceSize,int readOnly)34 static int InitWorkSpace_(WorkSpace *workSpace, uint32_t spaceSize, int readOnly)
35 {
36     static uint32_t startIndex = 0;
37     PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
38     PARAM_CHECK(sizeof(ParamTrieHeader) < spaceSize,
39         return PARAM_CODE_INVALID_PARAM, "Invalid spaceSize %u", spaceSize);
40     PARAM_CHECK(workSpace->allocTrieNode != NULL,
41         return PARAM_CODE_INVALID_PARAM, "Invalid allocTrieNode %s", workSpace->fileName);
42     PARAM_CHECK(workSpace->compareTrieNode != NULL,
43         return PARAM_CODE_INVALID_PARAM, "Invalid compareTrieNode %s", workSpace->fileName);
44 
45     char buffer[FILENAME_LEN_MAX] = {0};
46     int ret = GetRealFileName(workSpace, buffer, sizeof(buffer));
47     PARAM_CHECK(ret == 0, return -1, "Failed to get file name %s", workSpace->fileName);
48     void *areaAddr = GetSharedMem(buffer, &workSpace->memHandle, spaceSize, readOnly);
49     PARAM_ONLY_CHECK(areaAddr != NULL, return PARAM_CODE_ERROR_MAP_FILE);
50     if (!readOnly) {
51         workSpace->area = (ParamTrieHeader *)areaAddr;
52         ATOMIC_INIT(&workSpace->area->commitId, 0);
53         ATOMIC_INIT(&workSpace->area->commitPersistId, 0);
54         workSpace->area->trieNodeCount = 0;
55         workSpace->area->paramNodeCount = 0;
56         workSpace->area->securityNodeCount = 0;
57         workSpace->area->startIndex = startIndex;
58         startIndex += spaceSize;
59         workSpace->area->dataSize = spaceSize - sizeof(ParamTrieHeader);
60         workSpace->area->currOffset = 0;
61         uint32_t offset = workSpace->allocTrieNode(workSpace, "#", 1);
62         workSpace->area->firstNode = offset;
63     } else {
64         workSpace->area = (ParamTrieHeader *)areaAddr;
65     }
66     PARAM_LOGV("InitWorkSpace success, readOnly %d currOffset %u firstNode %u dataSize %u",
67         readOnly, workSpace->area->currOffset, workSpace->area->firstNode, workSpace->area->dataSize);
68     return 0;
69 }
70 
AllocateParamTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen)71 static uint32_t AllocateParamTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen)
72 {
73     uint32_t len = keyLen + sizeof(ParamTrieNode) + 1;
74     len = PARAM_ALIGN(len);
75     PARAM_CHECK((workSpace->area->currOffset + len) < workSpace->area->dataSize, return 0,
76         "Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize);
77     ParamTrieNode *node = (ParamTrieNode *)(workSpace->area->data + workSpace->area->currOffset);
78     node->length = keyLen;
79     int ret = ParamMemcpy(node->key, keyLen, key, keyLen);
80     PARAM_CHECK(ret == 0, return 0, "Failed to copy key");
81     node->key[keyLen] = '\0';
82     node->left = 0;
83     node->right = 0;
84     node->child = 0;
85     node->dataIndex = 0;
86     node->labelIndex = 0;
87     uint32_t offset = workSpace->area->currOffset;
88     workSpace->area->currOffset += len;
89     workSpace->area->trieNodeCount++;
90     return offset;
91 }
92 
CompareParamTrieNode(const ParamTrieNode * node,const char * key,uint32_t keyLen)93 static int CompareParamTrieNode(const ParamTrieNode *node, const char *key, uint32_t keyLen)
94 {
95     if (node->length > keyLen) {
96         return -1;
97     } else if (node->length < keyLen) {
98         return 1;
99     }
100     return strncmp(node->key, key, keyLen);
101 }
102 
InitWorkSpace(WorkSpace * workSpace,int onlyRead,uint32_t spaceSize)103 INIT_LOCAL_API int InitWorkSpace(WorkSpace *workSpace, int onlyRead, uint32_t spaceSize)
104 {
105     PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid workSpace");
106     if (PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
107         return 0;
108     }
109     workSpace->compareTrieNode = CompareParamTrieNode;
110     workSpace->allocTrieNode = AllocateParamTrieNode;
111     workSpace->area = NULL;
112     int ret = InitWorkSpace_(workSpace, spaceSize, onlyRead);
113     PARAM_ONLY_CHECK(ret == 0, return ret);
114     PARAMSPACE_AREA_INIT_LOCK(workSpace);
115     PARAM_SET_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT);
116     PARAM_LOGV("InitWorkSpace %s for %s", workSpace->fileName, (onlyRead == 0) ? "init" : "other");
117     return ret;
118 }
119 
CloseWorkSpace(WorkSpace * workSpace)120 INIT_LOCAL_API void CloseWorkSpace(WorkSpace *workSpace)
121 {
122     PARAM_CHECK(workSpace != NULL, return, "The workspace is null");
123     PARAM_LOGV("CloseWorkSpace %s", workSpace->fileName);
124     if (!PARAM_TEST_FLAG(workSpace->flags, WORKSPACE_FLAGS_INIT)) {
125         free(workSpace);
126         return;
127     }
128     OH_ListRemove(&workSpace->node);
129     PARAM_CHECK(workSpace->area != NULL, return, "The workspace area is null");
130 #ifdef WORKSPACE_AREA_NEED_MUTEX
131     ParamRWMutexDelete(&workSpace->rwlock);
132 #endif
133     FreeSharedMem(&workSpace->memHandle, workSpace->area, workSpace->area->dataSize);
134     workSpace->area = NULL;
135     free(workSpace);
136 }
137 
GetTrieRoot(const WorkSpace * workSpace)138 static ParamTrieNode *GetTrieRoot(const WorkSpace *workSpace)
139 {
140     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return NULL, "The workspace is null");
141     return (ParamTrieNode *)(workSpace->area->data + workSpace->area->firstNode);
142 }
143 
GetNextKey(const char ** remainingKey,char ** subKey,uint32_t * subKeyLen)144 static void GetNextKey(const char **remainingKey, char **subKey, uint32_t *subKeyLen)
145 {
146     *subKey = strchr(*remainingKey, '.');
147     if (*subKey != NULL) {
148         *subKeyLen = *subKey - *remainingKey;
149     } else {
150         *subKeyLen = strlen(*remainingKey);
151     }
152 }
153 
AddToSubTrie(WorkSpace * workSpace,ParamTrieNode * current,const char * key,uint32_t keyLen)154 static ParamTrieNode *AddToSubTrie(WorkSpace *workSpace, ParamTrieNode *current, const char *key, uint32_t keyLen)
155 {
156     if (current == NULL || workSpace == NULL || key == NULL) {
157         return NULL;
158     }
159     ParamTrieNode *subTrie = NULL;
160     int ret = workSpace->compareTrieNode(current, key, keyLen);
161     if (ret == 0) {
162         return current;
163     }
164     if (ret < 0) {
165         subTrie = GetTrieNode(workSpace, current->left);
166         if (subTrie == NULL) {
167             uint32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
168             PARAM_CHECK(offset != 0, return NULL,
169                 "Failed to allocate key '%s' in space '%s'", key, workSpace->fileName);
170             SaveIndex(&current->left, offset);
171             return GetTrieNode(workSpace, current->left);
172         }
173     } else {
174         subTrie = GetTrieNode(workSpace, current->right);
175         if (subTrie == NULL) {
176             uint32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
177             PARAM_CHECK(offset != 0, return NULL,
178                 "Failed to allocate key '%s' in space '%s'", key, workSpace->fileName);
179             SaveIndex(&current->right, offset);
180             return GetTrieNode(workSpace, current->right);
181         }
182     }
183     return AddToSubTrie(workSpace, subTrie, key, keyLen);
184 }
185 
AddTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen)186 ParamTrieNode *AddTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen)
187 {
188     PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid param ");
189     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid workSpace %s", key);
190     PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid param %s", key);
191     PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid param %s", key);
192     const char *remainingKey = key;
193     ParamTrieNode *current = GetTrieRoot(workSpace);
194     PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key);
195     while (1) {
196         uint32_t subKeyLen = 0;
197         char *subKey = NULL;
198         GetNextKey(&remainingKey, &subKey, &subKeyLen);
199         if (!subKeyLen) {
200             return NULL;
201         }
202         if (current->child != 0) {  // 如果child存在,则检查是否匹配
203             ParamTrieNode *next = GetTrieNode(workSpace, current->child);
204             current = AddToSubTrie(workSpace, next, remainingKey, subKeyLen);
205         } else {
206             uint32_t dataOffset = workSpace->allocTrieNode(workSpace, remainingKey, subKeyLen);
207             PARAM_CHECK(dataOffset != 0, return NULL,
208                 "Failed to allocate key '%s' in space '%s'", key, workSpace->fileName);
209             SaveIndex(&current->child, dataOffset);
210             current = (ParamTrieNode *)GetTrieNode(workSpace, current->child);
211         }
212         if (current == NULL) {
213             return NULL;
214         }
215         if (subKey == NULL || strcmp(subKey, ".") == 0) {
216             break;
217         }
218         remainingKey = subKey + 1;
219     }
220     return current;
221 }
222 
FindSubTrie(const WorkSpace * workSpace,ParamTrieNode * current,const char * key,uint32_t keyLen,uint32_t * matchLabel)223 static ParamTrieNode *FindSubTrie(const WorkSpace *workSpace,
224     ParamTrieNode *current, const char *key, uint32_t keyLen, uint32_t *matchLabel)
225 {
226     if (current == NULL) {
227         return NULL;
228     }
229     ParamTrieNode *subTrie = NULL;
230     int ret = workSpace->compareTrieNode(current, key, keyLen);
231     if (ret == 0) {
232         if (matchLabel != NULL && current->labelIndex != 0) {
233             *matchLabel = current->labelIndex;
234         }
235         return current;
236     }
237     if (ret < 0) {
238         subTrie = (ParamTrieNode *)GetTrieNode(workSpace, current->left);
239         if (subTrie == NULL) {
240             return NULL;
241         }
242     } else {
243         subTrie = (ParamTrieNode *)GetTrieNode(workSpace, current->right);
244         if (subTrie == NULL) {
245             return NULL;
246         }
247     }
248     return FindSubTrie(workSpace, subTrie, key, keyLen, matchLabel);
249 }
250 
FindTrieNode_(const WorkSpace * workSpace,const char * key,uint32_t keyLen,uint32_t * matchLabel)251 static ParamTrieNode *FindTrieNode_(const WorkSpace *workSpace, const char *key, uint32_t keyLen, uint32_t *matchLabel)
252 {
253     PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid key ");
254     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid workSpace %s", key);
255     PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid alloc function %s", key);
256     PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid compare function %s", key);
257     const char *remainingKey = key;
258     ParamTrieNode *current = GetTrieRoot(workSpace);
259     PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key);
260     if (matchLabel != NULL) {
261         *matchLabel = current->labelIndex;
262     }
263     int ret = workSpace->compareTrieNode(current, key, keyLen);
264     if (ret == 0) {
265         return current;
266     }
267     while (1) {
268         uint32_t subKeyLen = 0;
269         char *subKey = NULL;
270         GetNextKey(&remainingKey, &subKey, &subKeyLen);
271         if (!subKeyLen) {
272             return NULL;
273         }
274         if (current->child != 0) {
275             ParamTrieNode *next = GetTrieNode(workSpace, current->child);
276             current = FindSubTrie(workSpace, next, remainingKey, subKeyLen, matchLabel);
277         } else {
278             current = FindSubTrie(workSpace, current, remainingKey, subKeyLen, matchLabel);
279         }
280         if (current == NULL) {
281             return NULL;
282         } else if (matchLabel != NULL && current->labelIndex != 0) {
283             *matchLabel = current->labelIndex;
284         }
285         if (subKey == NULL || strcmp(subKey, ".") == 0) {
286             break;
287         }
288         remainingKey = subKey + 1;
289     }
290     return current;
291 }
292 
TraversalSubTrieNode(const WorkSpace * workSpace,const ParamTrieNode * current,TraversalTrieNodePtr walkFunc,const void * cookie)293 static int TraversalSubTrieNode(const WorkSpace *workSpace,
294     const ParamTrieNode *current, TraversalTrieNodePtr walkFunc, const void *cookie)
295 {
296     if (current == NULL) {
297         return 0;
298     }
299     walkFunc(workSpace, (ParamTrieNode *)current, cookie);
300     TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie);
301     TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie);
302     TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie);
303     return 0;
304 }
305 
TraversalTrieNode(const WorkSpace * workSpace,const ParamTrieNode * root,TraversalTrieNodePtr walkFunc,const void * cookie)306 INIT_LOCAL_API int TraversalTrieNode(const WorkSpace *workSpace,
307     const ParamTrieNode *root, TraversalTrieNodePtr walkFunc, const void *cookie)
308 {
309     PARAM_CHECK(walkFunc != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
310     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid workSpace");
311     ParamTrieNode *current = (ParamTrieNode *)root;
312     if (root == NULL) {
313         current = GetTrieRoot(workSpace);
314     }
315     if (current == NULL) {
316         return 0;
317     }
318     walkFunc(workSpace, (ParamTrieNode *)current, cookie);
319     TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie);
320     if (root == NULL) {
321         TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie);
322         TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie);
323     }
324     return 0;
325 }
326 
AddParamSecurityNode(WorkSpace * workSpace,const ParamAuditData * auditData)327 INIT_LOCAL_API uint32_t AddParamSecurityNode(WorkSpace *workSpace, const ParamAuditData *auditData)
328 {
329     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid param");
330     PARAM_CHECK(auditData != NULL && auditData->name != NULL, return 0, "Invalid auditData");
331     uint32_t realLen = sizeof(ParamSecurityNode);
332     PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
333         "Failed to allocate currOffset %u, dataSize %u datalen %u",
334         workSpace->area->currOffset, workSpace->area->dataSize, realLen);
335     ParamSecurityNode *node = (ParamSecurityNode *)(workSpace->area->data + workSpace->area->currOffset);
336     node->uid = auditData->dacData.uid;
337     node->gid = auditData->dacData.gid;
338     node->mode = auditData->dacData.mode;
339     node->type = auditData->dacData.paramType & PARAM_TYPE_MASK;
340     uint32_t offset = workSpace->area->currOffset;
341     workSpace->area->currOffset += realLen;
342     workSpace->area->securityNodeCount++;
343     return offset;
344 }
345 
AddParamNode(WorkSpace * workSpace,uint8_t type,const char * key,uint32_t keyLen,const char * value,uint32_t valueLen)346 INIT_LOCAL_API uint32_t AddParamNode(WorkSpace *workSpace, uint8_t type,
347     const char *key, uint32_t keyLen, const char *value, uint32_t valueLen)
348 {
349     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid param");
350     PARAM_CHECK(key != NULL && value != NULL, return 0, "Invalid param");
351 
352     uint32_t realLen = sizeof(ParamNode) + 1 + 1;
353     // for const parameter, alloc memory on demand
354     if ((valueLen > PARAM_VALUE_LEN_MAX) || IS_READY_ONLY(key)) {
355         realLen += keyLen + valueLen;
356     } else {
357         realLen += keyLen + GetParamMaxLen(type);
358     }
359     realLen = PARAM_ALIGN(realLen);
360     PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
361         "Failed to allocate currOffset %u, dataSize %u datalen %u",
362         workSpace->area->currOffset, workSpace->area->dataSize, realLen);
363 
364     ParamNode *node = (ParamNode *)(workSpace->area->data + workSpace->area->currOffset);
365     ATOMIC_INIT(&node->commitId, 0);
366 
367     node->type = type;
368     node->keyLength = keyLen;
369     node->valueLength = valueLen;
370     int ret = ParamSprintf(node->data, realLen, "%s=%s", key, value);
371     PARAM_CHECK(ret > 0, return 0, "Failed to sprint key and value");
372     uint32_t offset = workSpace->area->currOffset;
373     workSpace->area->currOffset += realLen;
374     workSpace->area->paramNodeCount++;
375     return offset;
376 }
377 
GetTrieNode(const WorkSpace * workSpace,uint32_t offset)378 INIT_LOCAL_API ParamTrieNode *GetTrieNode(const WorkSpace *workSpace, uint32_t offset)
379 {
380     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return NULL, "Invalid param");
381     if (offset == 0 || offset > workSpace->area->dataSize) {
382         return NULL;
383     }
384     return (ParamTrieNode *)(workSpace->area->data + offset);
385 }
386 
SaveIndex(uint32_t * index,uint32_t offset)387 INIT_LOCAL_API void SaveIndex(uint32_t *index, uint32_t offset)
388 {
389     PARAM_CHECK(index != NULL, return, "Invalid index");
390     *index = offset;
391 }
392 
FindTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen,uint32_t * matchLabel)393 INIT_LOCAL_API ParamTrieNode *FindTrieNode(WorkSpace *workSpace,
394     const char *key, uint32_t keyLen, uint32_t *matchLabel)
395 {
396     PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return NULL, "Invalid workSpace");
397     ParamTrieNode *node = NULL;
398     PARAMSPACE_AREA_RD_LOCK(workSpace);
399     node = FindTrieNode_(workSpace, key, keyLen, matchLabel);
400     PARAMSPACE_AREA_RW_UNLOCK(workSpace);
401     if (node != NULL && node->dataIndex != 0) {
402         ParamNode *entry = (ParamNode *)GetTrieNode(workSpace, node->dataIndex);
403         if (entry != NULL && entry->keyLength == keyLen) {
404             return node;
405         }
406         return NULL;
407     }
408     return node;
409 }
410 
GetParamMaxLen(uint8_t type)411 INIT_LOCAL_API uint32_t GetParamMaxLen(uint8_t type)
412 {
413     static const uint32_t typeLengths[] = {
414         PARAM_VALUE_LEN_MAX, 32, 8 // 8 max bool length 32 max int length
415     };
416     if (type >= ARRAY_LENGTH(typeLengths)) {
417         return PARAM_VALUE_LEN_MAX;
418     }
419     return typeLengths[type];
420 }
421 
GetParamNode(const char * spaceName,const char * name)422 INIT_LOCAL_API ParamNode *GetParamNode(const char *spaceName, const char *name)
423 {
424     uint32_t labelIndex = 0;
425     WorkSpace *space = GetWorkSpace(spaceName);
426     PARAM_CHECK(space != NULL, return NULL, "Failed to get dac space %s", name);
427     ParamTrieNode *entry = FindTrieNode(space, name, strlen(name), &labelIndex);
428     if (entry == NULL || entry->dataIndex == 0) {
429         return NULL;
430     }
431     return (ParamNode *)GetTrieNode(space, entry->dataIndex);
432 }