1 /*
2  * Copyright (c) 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 #ifdef HKS_CONFIG_FILE
17 #include HKS_CONFIG_FILE
18 #else
19 #include "hks_config.h"
20 #endif
21 
22 #include "hks_file_operator.h"
23 
24 #include <dirent.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <sys/stat.h>
28 #include <unistd.h>
29 
30 #include "hks_log.h"
31 #include "hks_mem.h"
32 #include "hks_template.h"
33 #include "securec.h"
34 #define REQUIRED_KEY_NOT_AVAILABLE 126
35 
GetFileName(const char * path,const char * fileName,char * fullFileName,uint32_t fullFileNameLen)36 static int32_t GetFileName(const char *path, const char *fileName, char *fullFileName, uint32_t fullFileNameLen)
37 {
38     if (path != NULL) {
39         if (strncpy_s(fullFileName, fullFileNameLen, path, strlen(path)) != EOK) {
40             return HKS_ERROR_INTERNAL_ERROR;
41         }
42 
43         if (path[strlen(path) - 1] != '/') {
44             if (strncat_s(fullFileName, fullFileNameLen, "/", strlen("/")) != EOK) {
45                 return HKS_ERROR_INTERNAL_ERROR;
46             }
47         }
48 
49         if (strncat_s(fullFileName, fullFileNameLen, fileName, strlen(fileName)) != EOK) {
50             return HKS_ERROR_INTERNAL_ERROR;
51         }
52     } else {
53         if (strncpy_s(fullFileName, fullFileNameLen, fileName, strlen(fileName)) != EOK) {
54             return HKS_ERROR_INTERNAL_ERROR;
55         }
56     }
57 
58     return HKS_SUCCESS;
59 }
60 
GetFullFileName(const char * path,const char * fileName,char ** fullFileName)61 static int32_t GetFullFileName(const char *path, const char *fileName, char **fullFileName)
62 {
63     uint32_t nameLen = HKS_MAX_FILE_NAME_LEN;
64     char *tmpFileName = (char *)HksMalloc(nameLen);
65     HKS_IF_NULL_RETURN(tmpFileName, HKS_ERROR_MALLOC_FAIL)
66     (void)memset_s(tmpFileName, nameLen, 0, nameLen);
67 
68     int32_t ret = GetFileName(path, fileName, tmpFileName, nameLen);
69     if (ret != HKS_SUCCESS) {
70         HKS_LOG_E("get full fileName failed");
71         HKS_FREE(tmpFileName);
72         return ret;
73     }
74 
75     *fullFileName = tmpFileName;
76     return HKS_SUCCESS;
77 }
78 
IsValidPath(const char * path)79 static int32_t IsValidPath(const char *path)
80 {
81     if (path == NULL) {
82         HKS_LOG_E("path is NULL!");
83         return HKS_ERROR_NULL_POINTER;
84     }
85     if (strstr(path, "../") != NULL) {
86         HKS_LOG_E("dangerous filePath, ../ is not allowed to be included");
87         return HKS_ERROR_INVALID_ARGUMENT;
88     }
89 
90     return HKS_SUCCESS;
91 }
92 
IsFileExist(const char * fileName)93 static int32_t IsFileExist(const char *fileName)
94 {
95     if (access(fileName, F_OK) != 0) {
96         return HKS_ERROR_NOT_EXIST;
97     }
98 
99     return HKS_SUCCESS;
100 }
101 
FileRead(const char * fileName,uint32_t offset,struct HksBlob * blob,uint32_t * size)102 static int32_t FileRead(const char *fileName, uint32_t offset, struct HksBlob *blob, uint32_t *size)
103 {
104     (void)offset;
105     HKS_IF_NOT_SUCC_RETURN(IsFileExist(fileName), HKS_ERROR_NOT_EXIST)
106 
107     if (strstr(fileName, "../") != NULL) {
108         HKS_LOG_E("invalid filePath, ../ is included in file path");
109         return HKS_ERROR_INVALID_ARGUMENT;
110     }
111 
112     char filePath[PATH_MAX + 1] = {0};
113     if (realpath(fileName, filePath) == NULL) {
114         HKS_LOG_E("invalid filePath, realpath failed");
115         return HKS_ERROR_INVALID_ARGUMENT;
116     }
117 
118     FILE *fp = fopen(filePath, "rb");
119     if (fp ==  NULL) {
120         if (errno == REQUIRED_KEY_NOT_AVAILABLE) {
121             HKS_LOG_E("Check Permission failed!");
122             return HKS_ERROR_NO_PERMISSION;
123         }
124         HKS_LOG_E("open file fail, errno = 0x%" LOG_PUBLIC "x", errno);
125         return HKS_ERROR_OPEN_FILE_FAIL;
126     }
127 
128     uint32_t len = fread(blob->data, 1, blob->size, fp);
129     if (fclose(fp) < 0) {
130         HKS_LOG_E("failed to close file, errno = 0x%" LOG_PUBLIC "x", errno);
131         return HKS_ERROR_CLOSE_FILE_FAIL;
132     }
133     *size = len;
134     return HKS_SUCCESS;
135 }
136 
FileSize(const char * fileName)137 static uint32_t FileSize(const char *fileName)
138 {
139     HKS_IF_NOT_SUCC_RETURN(IsFileExist(fileName), 0)
140 
141     struct stat fileStat;
142     (void)memset_s(&fileStat, sizeof(fileStat), 0, sizeof(fileStat));
143     if (stat(fileName, &fileStat) != 0) {
144         HKS_LOG_E("file stat fail, errno = 0x%" LOG_PUBLIC "x", errno);
145         return 0;
146     }
147 
148     return fileStat.st_size;
149 }
150 
GetRealPath(const char * fileName,char * filePath)151 static int32_t GetRealPath(const char *fileName, char *filePath)
152 {
153     if (memcpy_s(filePath, PATH_MAX, fileName, strlen(fileName)) != EOK) {
154         return HKS_ERROR_INSUFFICIENT_MEMORY;
155     }
156 
157     if (strstr(filePath, "../") != NULL) {
158         HKS_LOG_E("invalid filePath!");
159         return HKS_ERROR_INVALID_KEY_FILE;
160     }
161     return HKS_SUCCESS;
162 }
163 
FileWrite(const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len)164 static int32_t FileWrite(const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len)
165 {
166     (void)offset;
167     char filePath[PATH_MAX + 1] = {0};
168     int32_t ret = GetRealPath(fileName, filePath);
169     HKS_IF_NOT_SUCC_LOGE(ret, "get real path faild")
170 
171     (void)realpath(fileName, filePath);
172 
173     /* caller function ensures that the folder exists */
174     FILE *fp = fopen(filePath, "wb+");
175     if (fp ==  NULL) {
176         if (errno == REQUIRED_KEY_NOT_AVAILABLE) {
177             HKS_LOG_E("Check Permission failed!");
178             return HKS_ERROR_NO_PERMISSION;
179         }
180         HKS_LOG_E("open file fail, errno = 0x%" LOG_PUBLIC "x", errno);
181         return HKS_ERROR_OPEN_FILE_FAIL;
182     }
183 
184     if (chmod(filePath, S_IRUSR | S_IWUSR) < 0) {
185         HKS_LOG_E("chmod file fail, errno = 0x%" LOG_PUBLIC "x", errno);
186         fclose(fp);
187         return HKS_ERROR_OPEN_FILE_FAIL;
188     }
189 
190     uint32_t size = fwrite(buf, 1, len, fp);
191     if (size != len) {
192         HKS_LOG_E("write file size fail, errno = 0x%" LOG_PUBLIC "x", errno);
193         fclose(fp);
194         return HKS_ERROR_WRITE_FILE_FAIL;
195     }
196 
197     if (fflush(fp) < 0) {
198         HKS_LOG_E("fflush file fail, errno = 0x%" LOG_PUBLIC "x", errno);
199         fclose(fp);
200         return HKS_ERROR_WRITE_FILE_FAIL;
201     }
202 
203     int fd = fileno(fp);
204     if (fd < 0) {
205         HKS_LOG_E("fileno fail, errno = 0x%" LOG_PUBLIC "x", errno);
206         fclose(fp);
207         return HKS_ERROR_WRITE_FILE_FAIL;
208     }
209 
210     if (fsync(fd) < 0) {
211         HKS_LOG_E("sync file fail, errno = 0x%" LOG_PUBLIC "x", errno);
212         fclose(fp);
213         return HKS_ERROR_WRITE_FILE_FAIL;
214     }
215 
216     if (fclose(fp) < 0) {
217         HKS_LOG_E("failed to close file, errno = 0x%" LOG_PUBLIC "x", errno);
218         return HKS_ERROR_CLOSE_FILE_FAIL;
219     }
220 
221     return HKS_SUCCESS;
222 }
223 
FileRemove(const char * fileName)224 static int32_t FileRemove(const char *fileName)
225 {
226     int32_t ret = IsFileExist(fileName);
227     HKS_IF_NOT_SUCC_RETURN(ret, HKS_SUCCESS) /* if file not exist, return ok */
228 
229     struct stat tmp;
230     if (stat(fileName, &tmp) != 0) {
231         return HKS_ERROR_INTERNAL_ERROR;
232     }
233 
234     if (S_ISDIR(tmp.st_mode)) {
235         return HKS_ERROR_INVALID_ARGUMENT;
236     }
237 
238     if ((unlink(fileName) != 0) && (errno != ENOENT)) {
239         HKS_LOG_E("failed to remove file: errno = 0x%" LOG_PUBLIC "x", errno);
240         return HKS_ERROR_REMOVE_FILE_FAIL;
241     }
242 
243     return HKS_SUCCESS;
244 }
245 
HksFileRemove(const char * path,const char * fileName)246 int32_t HksFileRemove(const char *path, const char *fileName)
247 {
248     HKS_IF_NULL_RETURN(fileName, HKS_ERROR_INVALID_ARGUMENT)
249 
250     char *fullFileName = NULL;
251     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
252     HKS_IF_NOT_SUCC_RETURN(ret, ret)
253     if (IsValidPath(fullFileName) != HKS_SUCCESS) {
254         HKS_FREE(fullFileName);
255         return HKS_ERROR_INVALID_ARGUMENT;
256     }
257 
258     ret = FileRemove(fullFileName);
259     HKS_FREE(fullFileName);
260     return ret;
261 }
262 
HksIsFileExist(const char * path,const char * fileName)263 int32_t HksIsFileExist(const char *path, const char *fileName)
264 {
265     HKS_IF_NULL_RETURN(fileName, HKS_ERROR_NULL_POINTER)
266 
267     char *fullFileName = NULL;
268     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
269     HKS_IF_NOT_SUCC_RETURN(ret, ret)
270     if (IsValidPath(fullFileName) != HKS_SUCCESS) {
271         HKS_FREE(fullFileName);
272         return HKS_ERROR_INVALID_ARGUMENT;
273     }
274 
275     ret = IsFileExist(fullFileName);
276     HKS_FREE(fullFileName);
277     return ret;
278 }
279 
HksIsDirExist(const char * path)280 int32_t HksIsDirExist(const char *path)
281 {
282     HKS_IF_NULL_RETURN(path, HKS_ERROR_NULL_POINTER)
283     if (IsValidPath(path) != HKS_SUCCESS) {
284         return HKS_ERROR_INVALID_ARGUMENT;
285     }
286     return IsFileExist(path);
287 }
288 
HksMakeDir(const char * path)289 int32_t HksMakeDir(const char *path)
290 {
291     if (IsValidPath(path) != HKS_SUCCESS) {
292         return HKS_ERROR_INVALID_ARGUMENT;
293     }
294     int result = mkdir(path, S_IRWXU);
295     if (result == 0) {
296         return HKS_SUCCESS;
297     } else {
298         switch (errno) {
299             case EEXIST:
300                 return HKS_ERROR_ALREADY_EXISTS;
301             default:
302                 return HKS_ERROR_MAKE_DIR_FAIL;
303         }
304     }
305 }
306 
HksOpenDir(const char * path)307 void *HksOpenDir(const char *path)
308 {
309     if (IsValidPath(path) != HKS_SUCCESS) {
310         return NULL;
311     }
312     return (void *)opendir(path);
313 }
314 
HksCloseDir(void * dirp)315 int32_t HksCloseDir(void *dirp)
316 {
317     return closedir((DIR *)dirp);
318 }
319 
HksGetDirFile(void * dirp,struct HksFileDirentInfo * direntInfo)320 int32_t HksGetDirFile(void *dirp, struct HksFileDirentInfo *direntInfo)
321 {
322     DIR *dir = (DIR *)dirp;
323     struct dirent *dire = readdir(dir);
324 
325     while (dire != NULL) {
326         if (dire->d_type != DT_REG) { /* only care about files. */
327             dire = readdir(dir);
328             continue;
329         }
330 
331         uint32_t len = strlen(dire->d_name);
332         if (memcpy_s(direntInfo->fileName, sizeof(direntInfo->fileName) - 1, dire->d_name, len) != EOK) {
333             return HKS_ERROR_INSUFFICIENT_MEMORY;
334         }
335         direntInfo->fileName[len] = '\0';
336         return HKS_SUCCESS;
337     }
338 
339     return HKS_ERROR_NOT_EXIST;
340 }
341 
HksRemoveDir(const char * dirPath)342 int32_t HksRemoveDir(const char *dirPath)
343 {
344     if (IsValidPath(dirPath) != HKS_SUCCESS) {
345         return HKS_ERROR_INVALID_ARGUMENT;
346     }
347     struct stat fileStat;
348     int32_t ret = stat(dirPath, &fileStat);
349     if (ret != 0) {
350         HKS_LOG_E("file stat failed");
351         return HKS_FAILURE;
352     }
353 
354     if (!S_ISDIR(fileStat.st_mode)) {
355         HKS_LOG_E("path is not dir");
356         return HKS_FAILURE;
357     }
358 
359     DIR *dir = opendir(dirPath);
360     HKS_IF_NULL_LOGE_RETURN(dir, HKS_ERROR_OPEN_FILE_FAIL, "open dir failed")
361 
362     struct dirent *dire = readdir(dir);
363     while (dire != NULL) {
364         if (dire->d_type == DT_REG) { /* only care about files. */
365             ret = HksFileRemove(dirPath, dire->d_name);
366             HKS_IF_NOT_SUCC_LOGE(ret, "remove file failed when remove dir files, ret = %" LOG_PUBLIC "d.", ret)
367         }
368         dire = readdir(dir);
369     }
370 
371     closedir(dir);
372     return HKS_SUCCESS;
373 }
374 
HksDeletDirPartTwo(const char * path)375 static int32_t HksDeletDirPartTwo(const char *path)
376 {
377     int32_t ret;
378     char deletePath[HKS_MAX_FILE_NAME_LEN] = {0};
379     DIR *dir = opendir(path);
380     HKS_IF_NULL_LOGE_RETURN(dir, HKS_ERROR_OPEN_FILE_FAIL, "open dir failed")
381     struct dirent *dire = readdir(dir);
382     while (dire != NULL) {
383         if (strncpy_s(deletePath, sizeof(deletePath), path, strlen(path)) != EOK) {
384             closedir(dir);
385             return HKS_ERROR_INTERNAL_ERROR;
386         }
387 
388         if (deletePath[strlen(deletePath) - 1] != '/') {
389             if (strncat_s(deletePath, sizeof(deletePath), "/", strlen("/")) != EOK) {
390                 closedir(dir);
391                 return HKS_ERROR_INTERNAL_ERROR;
392             }
393         }
394 
395         if (strncat_s(deletePath, sizeof(deletePath), dire->d_name, strlen(dire->d_name)) != EOK) {
396             closedir(dir);
397             return HKS_ERROR_INTERNAL_ERROR;
398         }
399 
400         if ((strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
401             (void)remove(deletePath);
402         }
403         dire = readdir(dir);
404     }
405     closedir(dir);
406     ret = remove(path);
407     return ret;
408 }
409 
HksDeletDirPartOne(const char * path)410 static int32_t HksDeletDirPartOne(const char *path)
411 {
412     int32_t ret;
413     char deletePath[HKS_MAX_FILE_NAME_LEN] = {0};
414     DIR *dir = opendir(path);
415     HKS_IF_NULL_LOGE_RETURN(dir, HKS_ERROR_OPEN_FILE_FAIL, "open dir failed")
416     struct dirent *dire = readdir(dir);
417     while (dire != NULL) {
418         if (strncpy_s(deletePath, sizeof(deletePath), path, strlen(path)) != EOK) {
419             closedir(dir);
420             return HKS_ERROR_INTERNAL_ERROR;
421         }
422 
423         if (deletePath[strlen(deletePath) - 1] != '/') {
424             if (strncat_s(deletePath, sizeof(deletePath), "/", strlen("/")) != EOK) {
425                 closedir(dir);
426                 return HKS_ERROR_INTERNAL_ERROR;
427             }
428         }
429 
430         if (strncat_s(deletePath, sizeof(deletePath), dire->d_name, strlen(dire->d_name)) != EOK) {
431             closedir(dir);
432             return HKS_ERROR_INTERNAL_ERROR;
433         }
434 
435         if (dire->d_type == DT_DIR && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
436             HksDeletDirPartTwo(deletePath);
437         } else if (dire->d_type != DT_DIR) {
438             (void)remove(deletePath);
439         }
440         dire = readdir(dir);
441     }
442     closedir(dir);
443     ret = remove(path);
444     return ret;
445 }
446 
HksDeleteDir(const char * path)447 int32_t HksDeleteDir(const char *path)
448 {
449     if (IsValidPath(path) != HKS_SUCCESS) {
450         return HKS_ERROR_INVALID_ARGUMENT;
451     }
452     int32_t ret;
453     char deletePath[HKS_MAX_FILE_NAME_LEN] = { 0 };
454 
455     DIR *dir = opendir(path);
456     HKS_IF_NULL_LOGE_RETURN(dir, HKS_ERROR_OPEN_FILE_FAIL, "open dir failed")
457     struct dirent *dire = readdir(dir);
458     while (dire != NULL) {
459         if (strncpy_s(deletePath, sizeof(deletePath), path, strlen(path)) != EOK) {
460             closedir(dir);
461             return HKS_ERROR_INTERNAL_ERROR;
462         }
463 
464         if (deletePath[strlen(deletePath) - 1] != '/') {
465             if (strncat_s(deletePath, sizeof(deletePath), "/", strlen("/")) != EOK) {
466                 closedir(dir);
467                 return HKS_ERROR_INTERNAL_ERROR;
468             }
469         }
470 
471         if (strncat_s(deletePath, sizeof(deletePath), dire->d_name, strlen(dire->d_name)) != EOK) {
472             closedir(dir);
473             return HKS_ERROR_INTERNAL_ERROR;
474         }
475 
476         if (dire->d_type == DT_DIR && (strcmp("..", dire->d_name) != 0) && (strcmp(".", dire->d_name) != 0)) {
477             HksDeletDirPartOne(deletePath);
478         } else if (dire->d_type != DT_DIR) {
479             (void)remove(deletePath);
480         }
481         dire = readdir(dir);
482     }
483     closedir(dir);
484     ret = remove(path);
485     return ret;
486 }
487 
HksFileRead(const char * path,const char * fileName,uint32_t offset,struct HksBlob * blob,uint32_t * size)488 int32_t HksFileRead(const char *path, const char *fileName, uint32_t offset, struct HksBlob *blob, uint32_t *size)
489 {
490     if ((fileName == NULL) || (blob == NULL) || (blob->data == NULL) || (blob->size == 0) || (size == NULL)) {
491         return HKS_ERROR_INVALID_ARGUMENT;
492     }
493 
494     char *fullFileName = NULL;
495     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
496     HKS_IF_NOT_SUCC_RETURN(ret, ret)
497     if (IsValidPath(fullFileName) != HKS_SUCCESS) {
498         HKS_FREE(fullFileName);
499         return HKS_ERROR_INVALID_ARGUMENT;
500     }
501 
502     ret = FileRead(fullFileName, offset, blob, size);
503     HKS_FREE(fullFileName);
504     return ret;
505 }
506 
HksFileWrite(const char * path,const char * fileName,uint32_t offset,const uint8_t * buf,uint32_t len)507 int32_t HksFileWrite(const char *path, const char *fileName, uint32_t offset, const uint8_t *buf, uint32_t len)
508 {
509     if ((fileName == NULL) || (buf == NULL) || (len == 0)) {
510         return HKS_ERROR_INVALID_ARGUMENT;
511     }
512 
513     char *fullFileName = NULL;
514     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
515     HKS_IF_NOT_SUCC_RETURN(ret, ret)
516     if (IsValidPath(fullFileName) != HKS_SUCCESS) {
517         HKS_FREE(fullFileName);
518         return HKS_ERROR_INVALID_ARGUMENT;
519     }
520 
521     ret = FileWrite(fullFileName, offset, buf, len);
522     HKS_FREE(fullFileName);
523     return ret;
524 }
525 
HksFileSize(const char * path,const char * fileName)526 uint32_t HksFileSize(const char *path, const char *fileName)
527 {
528     HKS_IF_NULL_RETURN(fileName, 0)
529 
530     char *fullFileName = NULL;
531     int32_t ret = GetFullFileName(path, fileName, &fullFileName);
532     HKS_IF_NOT_SUCC_RETURN(ret, 0)
533     if (IsValidPath(fullFileName) != HKS_SUCCESS) {
534         HKS_FREE(fullFileName);
535         return 0;
536     }
537 
538     uint32_t size = FileSize(fullFileName);
539     HKS_FREE(fullFileName);
540     return size;
541 }
542 
HksGetFileName(const char * path,const char * fileName,char * fullFileName,uint32_t fullFileNameLen)543 int32_t HksGetFileName(const char *path, const char *fileName, char *fullFileName, uint32_t fullFileNameLen)
544 {
545     return GetFileName(path, fileName, fullFileName, fullFileNameLen);
546 }