• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&current->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(&current->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(&current->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