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(¤t->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(¤t->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(¤t->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 }