1/*
2 * Copyright (c) 2023-2023 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 "context_tool.h"
17
18#include <stdlib.h>
19#include <errno.h>
20#include <string.h>
21#include <limits.h>
22#include <sys/stat.h>
23#include "securec.h"
24
25#include "endian_internal.h"
26
27#ifdef SYSCAP_DEFINE_EXTERN_ENABLE
28#include "syscap_define_custom.h"
29#else
30#include "syscap_define.h"
31#endif
32
33void FreeContextBuffer(char *contextBuffer)
34{
35    if (contextBuffer != NULL) {
36        (void)free(contextBuffer);
37    }
38}
39
40int32_t GetFileContext(const char *inputFile, char **contextBufPtr, uint32_t *bufferLen)
41{
42    int32_t ret;
43    FILE *fp = NULL;
44    struct stat statBuf;
45    char *contextBuffer = NULL;
46    char path[PATH_MAX + 1] = {0x00};
47
48#ifdef _POSIX_
49    if (strlen(inputFile) > PATH_MAX || strncpy_s(path, PATH_MAX, inputFile, strlen(inputFile)) != EOK) {
50        PRINT_ERR("get path(%s) failed\n", inputFile);
51        return -1;
52    }
53#else
54    if (strlen(inputFile) > PATH_MAX || realpath(inputFile, path) == NULL) {
55        PRINT_ERR("get file(%s) real path failed\n", inputFile);
56        return -1;
57    }
58#endif
59
60    ret = stat(path, &statBuf);
61    if (ret != 0) {
62        PRINT_ERR("get file(%s) st_mode failed, errno = %d\n", path, errno);
63        return -1;
64    }
65    if (!(statBuf.st_mode & S_IRUSR)) {
66        PRINT_ERR("don't have permission to read the file(%s)\n", path);
67        return -1;
68    }
69    contextBuffer = (char *)malloc(statBuf.st_size + 1);
70    if (contextBuffer == NULL) {
71        PRINT_ERR("malloc buffer failed, size = %d, errno = %d\n", (int32_t)statBuf.st_size + 1, errno);
72        return -1;
73    }
74    fp = fopen(path, "rb");
75    if (fp == NULL) {
76        PRINT_ERR("open file(%s) failed, errno = %d\n", path, errno);
77        FreeContextBuffer(contextBuffer);
78        return -1;
79    }
80    size_t retFread = fread(contextBuffer, statBuf.st_size, 1, fp);
81    if (retFread != 1) {
82        PRINT_ERR("read file(%s) failed, errno = %d\n", path, errno);
83        FreeContextBuffer(contextBuffer);
84        (void)fclose(fp);
85        return -1;
86    }
87    contextBuffer[statBuf.st_size] = '\0';
88    (void)fclose(fp);
89
90    *contextBufPtr = contextBuffer;
91    *bufferLen = statBuf.st_size + 1;
92    return 0;
93}
94
95int32_t CheckFileAndGetFileContext(const char *inputFile, char **contextBufPtr, uint32_t *bufferLen)
96{
97    if (inputFile == NULL) {
98        PRINT_ERR("input file is NULL.\n");
99        return -1;
100    }
101    int32_t ret = GetFileContext(inputFile, contextBufPtr, bufferLen);
102    if (ret != 0) {
103        PRINT_ERR("GetFileContext failed, input file : %s\n", inputFile);
104    }
105    return ret;
106}
107
108int32_t ConvertedContextSaveAsFile(char *outDirPath, const char *filename, char *convertedBuffer, size_t contextBufLen)
109{
110    int32_t ret;
111    FILE *fp = NULL;
112    char path[PATH_MAX + 1] = {0x00};
113
114#ifdef _POSIX_
115    if (strlen(outDirPath) >= PATH_MAX || strncpy_s(path, PATH_MAX, outDirPath, strlen(outDirPath)) != EOK) {
116        PRINT_ERR("get path(%s) failed\n", outDirPath);
117        return -1;
118    }
119#else
120    if (strlen(outDirPath) >= PATH_MAX || realpath(outDirPath, path) == NULL) {
121        PRINT_ERR("get file(%s) real path failed\n", outDirPath);
122        return -1;
123    }
124#endif
125    int32_t pathLen = strlen(path);
126    if (path[pathLen - 1] != '/' && path[pathLen - 1] != '\\') {
127        path[pathLen] = '/';
128    }
129
130    if (strlen(path) + strlen(filename) + 1 > PATH_MAX) {
131        PRINT_ERR("length of path too long.\n");
132        return -1;
133    }
134    ret = strncat_s(path, PATH_MAX, filename, strlen(filename) + 1);
135    if (ret != 0) {
136        PRINT_ERR("strncat_s failed, (%s, %d, %s, %d), errno = %d\n",
137                  path, PATH_MAX, filename, (int32_t)strlen(filename) + 1, errno);
138        return -1;
139    }
140
141    fp = fopen(path, "wb");
142    if (fp == NULL) {
143        PRINT_ERR("can't create file(%s), errno = %d\n", path, errno);
144        return -1;
145    }
146
147    if (fwrite(convertedBuffer, contextBufLen, 1, fp) != 1) {
148        PRINT_ERR("can't write file(%s),errno = %d\n", path, errno);
149        (void)fclose(fp);
150        return -1;
151    }
152
153    (void)fclose(fp);
154
155    return 0;
156}
157
158int32_t CheckRpcidFormat(const char *inputFile, char **buffer, uint32_t *len)
159{
160    uint32_t bufferLen;
161    uint16_t sysCaptype, sysCapLength;
162    char *contextBuffer = NULL;
163    RPCIDHead *rpcidHeader = NULL;
164
165    if (GetFileContext(inputFile, &contextBuffer, &bufferLen)) {
166        PRINT_ERR("GetFileContext failed, input file : %s\n", inputFile);
167        return -1;
168    }
169    if (bufferLen < (2 * sizeof(uint32_t))) { // 2, header of rpcid.sc
170        PRINT_ERR("Parse file failed(format is invalid), input file : %s\n", inputFile);
171        FreeContextBuffer(contextBuffer);
172        return -1;
173    }
174    rpcidHeader = (RPCIDHead *)contextBuffer;
175    if (rpcidHeader->apiVersionType != 1) {
176        PRINT_ERR("Parse file failed(apiVersionType != 1), input file : %s\n", inputFile);
177        FreeContextBuffer(contextBuffer);
178        return -1;
179    }
180    sysCaptype = NtohsInter(*(uint16_t *)(rpcidHeader + 1));
181    if (sysCaptype != 2) { // 2, app syscap type
182        PRINT_ERR("Parse file failed(sysCaptype != 2), input file : %s\n", inputFile);
183        FreeContextBuffer(contextBuffer);
184        return -1;
185    }
186    sysCapLength = NtohsInter(*(uint16_t *)((char *)(rpcidHeader + 1) + sizeof(uint16_t)));
187    if (bufferLen < sizeof(RPCIDHead) + sizeof(uint32_t) + sysCapLength) {
188        PRINT_ERR("Parse file failed(SysCap length exceeded), input file : %s\n", inputFile);
189        FreeContextBuffer(contextBuffer);
190        return -1;
191    }
192
193    *buffer = contextBuffer;
194    *len = bufferLen;
195    return 0;
196}
197
198cJSON *CreateWholeSyscapJsonObj(void)
199{
200    cJSON *syscapJsonObj =  cJSON_CreateObject();
201    if (syscapJsonObj == NULL) {
202        PRINT_ERR("interface-create jsonObj failed.");
203        return NULL;
204    }
205
206    size_t syscapNums = sizeof(g_arraySyscap) / sizeof(SyscapWithNum);
207    for (size_t i = 0; i < syscapNums; i++) {
208        cJSON_AddItemToObject(syscapJsonObj, g_arraySyscap[i].str, cJSON_CreateNumber(g_arraySyscap[i].num));
209    }
210    return syscapJsonObj;
211}
212