1 /*
2 * Copyright (c) 2021 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 #include <fcntl.h>
20 #include <string.h>
21 #include <sys/mman.h>
22 #include <sys/stat.h>
23 #include <sys/time.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26
27 #include "param_utils.h"
28 #include "sys_param.h"
29
InitWorkSpace_(WorkSpace * workSpace,int mode,int prot,uint32_t spaceSize,int readOnly)30 static int InitWorkSpace_(WorkSpace *workSpace, int mode, int prot, uint32_t spaceSize, int readOnly)
31 {
32 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
33 PARAM_CHECK(spaceSize <= PARAM_WORKSPACE_MAX, return PARAM_CODE_INVALID_PARAM, "Invalid workSpace");
34 PARAM_CHECK(workSpace->allocTrieNode != NULL,
35 return PARAM_CODE_INVALID_PARAM, "Invalid allocTrieNode %s", workSpace->fileName);
36 PARAM_CHECK(workSpace->compareTrieNode != NULL,
37 return PARAM_CODE_INVALID_PARAM, "Invalid compareTrieNode %s", workSpace->fileName);
38 PARAM_LOGV("InitWorkSpace %s readOnly %d", workSpace->fileName, readOnly);
39 CheckAndCreateDir(workSpace->fileName);
40
41 int fd = open(workSpace->fileName, mode, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
42 PARAM_CHECK(fd >= 0, return PARAM_CODE_INVALID_NAME,
43 "Open file %s mode %x fail error %d", workSpace->fileName, mode, errno);
44
45 if (!readOnly) {
46 ftruncate(fd, spaceSize);
47 }
48 void *areaAddr = (void *)mmap(NULL, spaceSize, prot, MAP_SHARED, fd, 0);
49 PARAM_CHECK(areaAddr != MAP_FAILED && areaAddr != NULL, close(fd);
50 return PARAM_CODE_ERROR_MAP_FILE, "Failed to map memory error %d", errno);
51 close(fd);
52
53 if (!readOnly) {
54 workSpace->area = (ParamTrieHeader *)areaAddr;
55 workSpace->area->trieNodeCount = 0;
56 workSpace->area->paramNodeCount = 0;
57 workSpace->area->securityNodeCount = 0;
58 workSpace->area->dataSize = spaceSize - sizeof(ParamTrieHeader);
59 workSpace->area->currOffset = 0;
60 uint32_t offset = workSpace->allocTrieNode(workSpace, "#", 1);
61 workSpace->area->firstNode = offset;
62 } else {
63 workSpace->area = (ParamTrieHeader *)areaAddr;
64 }
65 PARAM_LOGV("InitWorkSpace success, readOnly %d currOffset %u firstNode %u dataSize %u",
66 readOnly, workSpace->area->currOffset, workSpace->area->firstNode, workSpace->area->dataSize);
67 return 0;
68 }
69
AllocateParamTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen)70 static uint32_t AllocateParamTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen)
71 {
72 uint32_t len = keyLen + sizeof(ParamTrieNode) + 1;
73 len = PARAM_ALIGN(len);
74 PARAM_CHECK((workSpace->area->currOffset + len) < workSpace->area->dataSize, return 0,
75 "Failed to allocate currOffset %d, dataSize %d", workSpace->area->currOffset, workSpace->area->dataSize);
76 ParamTrieNode *node = (ParamTrieNode*)(workSpace->area->data + workSpace->area->currOffset);
77 node->length = keyLen;
78 int ret = memcpy_s(node->key, keyLen, key, keyLen);
79 PARAM_CHECK(ret == EOK, return 0, "Failed to copy key");
80 node->key[keyLen] = '\0';
81 node->left = 0;
82 node->right = 0;
83 node->child = 0;
84 node->dataIndex = 0;
85 node->labelIndex = 0;
86 uint32_t offset = workSpace->area->currOffset;
87 workSpace->area->currOffset += len;
88 workSpace->area->trieNodeCount++;
89 return offset;
90 }
91
CompareParamTrieNode(const ParamTrieNode * node,const char * key,uint32_t keyLen)92 static int CompareParamTrieNode(const ParamTrieNode *node, const char *key, uint32_t keyLen)
93 {
94 if (node->length > keyLen) {
95 return -1;
96 } else if (node->length < keyLen) {
97 return 1;
98 }
99 return strncmp(node->key, key, keyLen);
100 }
101
InitWorkSpace(const char * fileName,WorkSpace * workSpace,int onlyRead)102 int InitWorkSpace(const char *fileName, WorkSpace *workSpace, int onlyRead)
103 {
104 PARAM_CHECK(fileName != NULL, return PARAM_CODE_INVALID_NAME, "Invalid fileName");
105 PARAM_CHECK(workSpace != NULL, return PARAM_CODE_INVALID_NAME, "Invalid workSpace");
106 if (workSpace->area != NULL) {
107 return 0;
108 }
109 workSpace->compareTrieNode = CompareParamTrieNode;
110 workSpace->allocTrieNode = AllocateParamTrieNode;
111 int ret = strcpy_s(workSpace->fileName, sizeof(workSpace->fileName), fileName);
112 PARAM_CHECK(ret == 0, return ret, "Failed to copy file name %s", fileName);
113 int openMode;
114 int prot = PROT_READ;
115 if (onlyRead) {
116 openMode = O_RDONLY;
117 } else {
118 openMode = O_CREAT | O_RDWR | O_TRUNC;
119 prot = PROT_READ | PROT_WRITE;
120 }
121 ret = InitWorkSpace_(workSpace, openMode, prot, PARAM_WORKSPACE_MAX, onlyRead);
122 PARAM_CHECK(ret == 0, return ret, "Failed to init workspace %s", workSpace->fileName);
123 return ret;
124 }
125
CloseWorkSpace(WorkSpace * workSpace)126 void CloseWorkSpace(WorkSpace *workSpace)
127 {
128 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return, "The workspace is null");
129 munmap((char *)workSpace->area, workSpace->area->dataSize);
130 workSpace->area = NULL;
131 }
132
GetTrieRoot(const WorkSpace * workSpace)133 static ParamTrieNode *GetTrieRoot(const WorkSpace *workSpace)
134 {
135 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return NULL, "The workspace is null");
136 return (ParamTrieNode *)(workSpace->area->data + workSpace->area->firstNode);
137 }
138
GetNextKey(const char ** remainingKey,char ** subKey,uint32_t * subKeyLen)139 static void GetNextKey(const char **remainingKey, char **subKey, uint32_t *subKeyLen)
140 {
141 *subKey = strchr(*remainingKey, '.');
142 if (*subKey != NULL) {
143 *subKeyLen = *subKey - *remainingKey;
144 } else {
145 *subKeyLen = strlen(*remainingKey);
146 }
147 }
148
AddToSubTrie(WorkSpace * workSpace,ParamTrieNode * current,const char * key,uint32_t keyLen)149 static ParamTrieNode *AddToSubTrie(WorkSpace *workSpace, ParamTrieNode *current, const char *key, uint32_t keyLen)
150 {
151 if (current == NULL || workSpace == NULL || key == NULL) {
152 return NULL;
153 }
154 ParamTrieNode *subTrie = NULL;
155 int ret = workSpace->compareTrieNode(current, key, keyLen);
156 if (ret == 0) {
157 return current;
158 }
159 if (ret < 0) {
160 subTrie = GetTrieNode(workSpace, current->left);
161 if (subTrie == NULL) {
162 uint32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
163 PARAM_CHECK(offset != 0, return NULL, "Failed to allocate key %s", key);
164 SaveIndex(¤t->left, offset);
165 return GetTrieNode(workSpace, current->left);
166 }
167 } else {
168 subTrie = GetTrieNode(workSpace, current->right);
169 if (subTrie == NULL) {
170 uint32_t offset = workSpace->allocTrieNode(workSpace, key, keyLen);
171 PARAM_CHECK(offset != 0, return NULL, "Failed to allocate key %s", key);
172 SaveIndex(¤t->right, offset);
173 return GetTrieNode(workSpace, current->right);
174 }
175 }
176 return AddToSubTrie(workSpace, subTrie, key, keyLen);
177 }
178
AddTrieNode(WorkSpace * workSpace,const char * key,uint32_t keyLen)179 ParamTrieNode *AddTrieNode(WorkSpace *workSpace, const char *key, uint32_t keyLen)
180 {
181 PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid param ");
182 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid workSpace %s", key);
183 PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid param %s", key);
184 PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid param %s", key);
185 const char *remainingKey = key;
186 ParamTrieNode *current = GetTrieRoot(workSpace);
187 PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key);
188 while (1) {
189 uint32_t subKeyLen = 0;
190 char *subKey = NULL;
191 GetNextKey(&remainingKey, &subKey, &subKeyLen);
192 if (!subKeyLen) {
193 return NULL;
194 }
195 if (current->child != 0) { // 如果child存在,则检查是否匹配
196 ParamTrieNode *next = GetTrieNode(workSpace, current->child);
197 current = AddToSubTrie(workSpace, next, remainingKey, subKeyLen);
198 } else {
199 uint32_t dataOffset = workSpace->allocTrieNode(workSpace, remainingKey, subKeyLen);
200 PARAM_CHECK(dataOffset != 0, return NULL, "Failed to allocate key %s", key);
201 SaveIndex(¤t->child, dataOffset);
202 current = (ParamTrieNode *)GetTrieNode(workSpace, current->child);
203 }
204 if (current == NULL) {
205 return NULL;
206 }
207 if (subKey == NULL || strcmp(subKey, ".") == 0) {
208 break;
209 }
210 remainingKey = subKey + 1;
211 }
212 return current;
213 }
214
FindSubTrie(const WorkSpace * workSpace,ParamTrieNode * current,const char * key,uint32_t keyLen,uint32_t * matchLabel)215 static ParamTrieNode *FindSubTrie(const WorkSpace *workSpace,
216 ParamTrieNode *current, const char *key, uint32_t keyLen, uint32_t *matchLabel)
217 {
218 if (current == NULL) {
219 return NULL;
220 }
221
222 ParamTrieNode *subTrie = NULL;
223 int ret = workSpace->compareTrieNode(current, key, keyLen);
224 if (ret == 0) {
225 if (matchLabel != NULL && current->labelIndex != 0) { // 有效前缀
226 *matchLabel = current->labelIndex;
227 }
228 return current;
229 }
230 if (ret < 0) {
231 subTrie = (ParamTrieNode *)GetTrieNode(workSpace, current->left);
232 if (subTrie == NULL) {
233 return NULL;
234 }
235 } else {
236 subTrie = (ParamTrieNode *)GetTrieNode(workSpace, current->right);
237 if (subTrie == NULL) {
238 return NULL;
239 }
240 }
241 return FindSubTrie(workSpace, subTrie, key, keyLen, matchLabel);
242 }
243
FindTrieNode(const WorkSpace * workSpace,const char * key,uint32_t keyLen,uint32_t * matchLabel)244 ParamTrieNode *FindTrieNode(const WorkSpace *workSpace, const char *key, uint32_t keyLen, uint32_t *matchLabel)
245 {
246 PARAM_CHECK(key != NULL && keyLen > 0, return NULL, "Invalid key ");
247 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid workSpace %s", key);
248 PARAM_CHECK(workSpace->allocTrieNode != NULL, return NULL, "Invalid alloc function %s", key);
249 PARAM_CHECK(workSpace->compareTrieNode != NULL, return NULL, "Invalid compare function %s", key);
250 const char *remainingKey = key;
251 ParamTrieNode *current = GetTrieRoot(workSpace);
252 PARAM_CHECK(current != NULL, return NULL, "Invalid current param %s", key);
253 if (matchLabel != NULL) {
254 *matchLabel = current->labelIndex;
255 }
256 int ret = workSpace->compareTrieNode(current, key, keyLen);
257 if (ret == 0) {
258 return current;
259 }
260 while (1) {
261 uint32_t subKeyLen = 0;
262 char *subKey = NULL;
263 GetNextKey(&remainingKey, &subKey, &subKeyLen);
264 if (!subKeyLen) {
265 return NULL;
266 }
267 if (current->child != 0) {
268 ParamTrieNode *next = GetTrieNode(workSpace, current->child);
269 current = FindSubTrie(workSpace, next, remainingKey, subKeyLen, matchLabel);
270 } else {
271 current = FindSubTrie(workSpace, current, remainingKey, subKeyLen, matchLabel);
272 }
273 if (current == NULL) {
274 return NULL;
275 } else if (matchLabel != NULL && current->labelIndex != 0) {
276 *matchLabel = current->labelIndex;
277 }
278 if (subKey == NULL || strcmp(subKey, ".") == 0) {
279 break;
280 }
281 remainingKey = subKey + 1;
282 }
283 return current;
284 }
285
TraversalSubTrieNode(const WorkSpace * workSpace,const ParamTrieNode * current,TraversalTrieNodePtr walkFunc,void * cookie)286 static int TraversalSubTrieNode(const WorkSpace *workSpace,
287 const ParamTrieNode *current, TraversalTrieNodePtr walkFunc, void *cookie)
288 {
289 if (current == NULL) {
290 return 0;
291 }
292 walkFunc(workSpace, (ParamTrieNode *)current, cookie);
293 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie);
294 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie);
295 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie);
296 return 0;
297 }
298
TraversalTrieNode(const WorkSpace * workSpace,const ParamTrieNode * root,TraversalTrieNodePtr walkFunc,void * cookie)299 int TraversalTrieNode(const WorkSpace *workSpace,
300 const ParamTrieNode *root, TraversalTrieNodePtr walkFunc, void *cookie)
301 {
302 PARAM_CHECK(walkFunc != NULL, return PARAM_CODE_INVALID_PARAM, "Invalid param");
303 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid workSpace");
304 ParamTrieNode *current = (ParamTrieNode *)root;
305 if (root == NULL) {
306 current = GetTrieRoot(workSpace);
307 }
308 if (current == NULL) {
309 return 0;
310 }
311 walkFunc(workSpace, (ParamTrieNode *)current, cookie);
312 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->child), walkFunc, cookie);
313 if (root == NULL) {
314 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->left), walkFunc, cookie);
315 TraversalSubTrieNode(workSpace, GetTrieNode(workSpace, current->right), walkFunc, cookie);
316 }
317 return 0;
318 }
319
AddParamSecruityNode(WorkSpace * workSpace,const ParamAuditData * auditData)320 uint32_t AddParamSecruityNode(WorkSpace *workSpace, const ParamAuditData *auditData)
321 {
322 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return 0, "Invalid param");
323 PARAM_CHECK(auditData != NULL && auditData->name != NULL, return 0, "Invalid auditData");
324 const uint32_t labelLen = (auditData->label == NULL) ? 0 : strlen(auditData->label);
325 uint32_t realLen = sizeof(ParamSecruityNode) + PARAM_ALIGN(labelLen + 1);
326 PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
327 "Failed to allocate currOffset %u, dataSize %u datalen %u",
328 workSpace->area->currOffset, workSpace->area->dataSize, realLen);
329
330 ParamSecruityNode *node = (ParamSecruityNode *)(workSpace->area->data + workSpace->area->currOffset);
331 node->uid = auditData->dacData.uid;
332 node->gid = auditData->dacData.gid;
333 node->mode = auditData->dacData.mode;
334 node->length = 0;
335 if (labelLen != 0) {
336 int ret = memcpy_s(node->data, labelLen, auditData->label, labelLen);
337 PARAM_CHECK(ret == EOK, return 0, "Failed to copy key");
338 node->data[labelLen] = '\0';
339 node->length = labelLen;
340 }
341 uint32_t offset = workSpace->area->currOffset;
342 workSpace->area->currOffset += realLen;
343 workSpace->area->securityNodeCount++;
344 return offset;
345 }
346
AddParamNode(WorkSpace * workSpace,const char * key,uint32_t keyLen,const char * value,uint32_t valueLen)347 uint32_t AddParamNode(WorkSpace *workSpace, 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 if (valueLen > PARAM_VALUE_LEN_MAX) {
354 realLen += keyLen + valueLen;
355 } else {
356 realLen += keyLen + PARAM_VALUE_LEN_MAX;
357 }
358 realLen = PARAM_ALIGN(realLen);
359 PARAM_CHECK((workSpace->area->currOffset + realLen) < workSpace->area->dataSize, return 0,
360 "Failed to allocate currOffset %u, dataSize %u datalen %u",
361 workSpace->area->currOffset, workSpace->area->dataSize, realLen);
362
363 ParamNode *node = (ParamNode *)(workSpace->area->data + workSpace->area->currOffset);
364 atomic_init(&node->commitId, 0);
365
366 node->keyLength = keyLen;
367 node->valueLength = valueLen;
368 int ret = sprintf_s(node->data, realLen - 1, "%s=%s", key, value);
369 PARAM_CHECK(ret > EOK, return 0, "Failed to sprint key and value");
370 uint32_t offset = workSpace->area->currOffset;
371 workSpace->area->currOffset += realLen;
372 workSpace->area->paramNodeCount++;
373 return offset;
374 }
375
GetTrieNode(const WorkSpace * workSpace,uint32_t offset)376 ParamTrieNode *GetTrieNode(const WorkSpace *workSpace, uint32_t offset)
377 {
378 PARAM_CHECK(workSpace != NULL && workSpace->area != NULL, return NULL, "Invalid param");
379 if (offset == 0 || offset > workSpace->area->dataSize) {
380 return NULL;
381 }
382 return (ParamTrieNode *)(workSpace->area->data + offset);
383 }
384
SaveIndex(uint32_t * index,uint32_t offset)385 void SaveIndex(uint32_t *index, uint32_t offset)
386 {
387 PARAM_CHECK(index != NULL, return, "Invalid index");
388 *index = offset;
389 }
390