1 /*
2  * Copyright (c) 2024 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 <stdio.h>
17 #include <stdlib.h>
18 #include <limits.h>
19 #include <errno.h>
20 
21 #include <dirent.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24 #ifdef _WIN32
25 #include <windows.h>
26 #endif
27 
28 #include "hnp_base.h"
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
GetFileSizeByHandle(FILE * file,int * size)34 int GetFileSizeByHandle(FILE *file, int *size)
35 {
36     int ret;
37     int len;
38 
39     ret = fseek(file, 0, SEEK_END);
40     if (ret != 0) {
41         HNP_LOGE("fseek end unsuccess.");
42         return HNP_ERRNO_BASE_FILE_SEEK_FAILED;
43     }
44     len = ftell(file);
45     if (len < 0) {
46         HNP_LOGE("ftell unsuccess. len=%{public}d", len);
47         return HNP_ERRNO_BASE_FILE_TELL_FAILED;
48     }
49     ret = fseek(file, 0, SEEK_SET);
50     if (ret != 0) {
51         HNP_LOGE("fseek set unsuccess. ");
52         return HNP_ERRNO_BASE_FILE_SEEK_FAILED;
53     }
54     *size = len;
55     return 0;
56 }
57 
ReadFileToStream(const char * filePath,char ** stream,int * streamLen)58 int ReadFileToStream(const char *filePath, char **stream, int *streamLen)
59 {
60     int ret;
61     FILE *file;
62     int size = 0;
63     char *streamTmp;
64 
65     file = fopen(filePath, "rb");
66     if (file == NULL) {
67         HNP_LOGE("open file[%{public}s] unsuccess. ", filePath);
68         return HNP_ERRNO_BASE_FILE_OPEN_FAILED;
69     }
70     ret = GetFileSizeByHandle(file, &size);
71     if (ret != 0) {
72         HNP_LOGE("get file[%{public}s] size unsuccess.", filePath);
73         (void)fclose(file);
74         return ret;
75     }
76     if (size == 0) {
77         HNP_LOGE("get file[%{public}s] size is null.", filePath);
78         (void)fclose(file);
79         return HNP_ERRNO_BASE_GET_FILE_LEN_NULL;
80     }
81     streamTmp = (char*)malloc(size);
82     if (streamTmp == NULL) {
83         HNP_LOGE("malloc unsuccess. size%{public}d", size);
84         (void)fclose(file);
85         return HNP_ERRNO_NOMEM;
86     }
87     size_t readLen = fread(streamTmp, sizeof(char), size, file);
88     if (readLen != (size_t)size) {
89         HNP_LOGE("fread unsuccess. readLen=%{public}zu, size=%{public}d", readLen, size);
90         (void)fclose(file);
91         free(streamTmp);
92         return HNP_ERRNO_BASE_FILE_READ_FAILED;
93     }
94     *stream = streamTmp;
95     *streamLen = size;
96     (void)fclose(file);
97     return 0;
98 }
99 
GetRealPath(char * srcPath,char * realPath)100 int GetRealPath(char *srcPath, char *realPath)
101 {
102     char dstTmpPath[MAX_FILE_PATH_LEN];
103 
104     if (srcPath == NULL || realPath == NULL) {
105         return HNP_ERRNO_PARAM_INVALID;
106     }
107 #ifdef _WIN32
108     // 使用wchar_t支持处理字符串长度超过260的路径字符串
109     wchar_t wideSrcPath[MAX_FILE_PATH_LEN] = {0};
110     wchar_t wideDstPathExt[MAX_FILE_PATH_LEN] = {0};
111     MultiByteToWideChar(CP_ACP, 0, srcPath, -1, wideSrcPath, MAX_FILE_PATH_LEN);
112     DWORD ret = GetFullPathNameW(wideSrcPath, MAX_FILE_PATH_LEN, wideDstPathExt, NULL);
113     WideCharToMultiByte(CP_ACP, 0, wideDstPathExt, -1, dstTmpPath, MAX_FILE_PATH_LEN, NULL, NULL);
114 #else
115     char *ret = realpath(srcPath, dstTmpPath);
116 #endif
117     if (ret == 0) {
118         HNP_LOGE("realpath unsuccess. path=%{public}s", srcPath);
119         return HNP_ERRNO_BASE_REALPATHL_FAILED;
120     }
121     if (strlen(dstTmpPath) >= MAX_FILE_PATH_LEN) {
122         HNP_LOGE("realpath over max path len. len=%{public}d", (int)strlen(dstTmpPath));
123         return HNP_ERRNO_BASE_STRING_LEN_OVER_LIMIT;
124     }
125     if (strcpy_s(realPath, MAX_FILE_PATH_LEN, dstTmpPath) != EOK) {
126         HNP_LOGE("strcpy unsuccess.");
127         return HNP_ERRNO_BASE_COPY_FAILED;
128     }
129     return 0;
130 }
131 
HnpDeleteAllFileInPath(const char * path,DIR * dir)132 static int HnpDeleteAllFileInPath(const char *path, DIR *dir)
133 {
134     int ret = 0;
135 #ifdef _WIN32
136     return ret;
137 #else
138     struct dirent *entry;
139     struct stat statbuf;
140     char filePath[MAX_FILE_PATH_LEN];
141 
142     while ((entry = readdir(dir)) != NULL) {
143         if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) {
144             continue;
145         }
146 
147         ret = sprintf_s(filePath, MAX_FILE_PATH_LEN, "%s/%s", path, entry->d_name);
148         if (ret < 0) {
149             HNP_LOGE("delete folder sprintf path[%{public}s], file[%{public}s] unsuccess.", path, entry->d_name);
150             return HNP_ERRNO_BASE_SPRINTF_FAILED;
151         }
152 
153         if (lstat(filePath, &statbuf) < 0) {
154             unlink(filePath); // 如果是已被删除源文件的软链,是获取不到文件信息的,此处作删除处理
155             continue;
156         }
157 
158         if (S_ISDIR(statbuf.st_mode)) {
159             /* 如果是文件夹,递归删除 */
160             ret = HnpDeleteFolder(filePath);
161             if (ret != 0) {
162                 return ret;
163             }
164         } else {
165             ret = unlink(filePath);
166             if (ret != 0) {
167                 HNP_LOGE("delete file unsuccess.ret=%{public}d, path=%{public}s, errno=%{public}d", ret, filePath,
168                     errno);
169                 return HNP_ERRNO_BASE_UNLINK_FAILED;
170             }
171         }
172     }
173 
174     return 0;
175 #endif
176 }
177 
HnpDeleteFolder(const char * path)178 int HnpDeleteFolder(const char *path)
179 {
180     if (access(path, F_OK) != 0) {
181         return 0;
182     }
183     DIR *dir = opendir(path);
184     if (dir == NULL) {
185         HNP_LOGE("delete folder open dir=%{public}s unsuccess ", path);
186         return HNP_ERRNO_BASE_DIR_OPEN_FAILED;
187     }
188 
189     int ret = HnpDeleteAllFileInPath(path, dir);
190     closedir(dir);
191     if (ret != 0) {
192         return ret;
193     }
194 
195     ret = rmdir(path);
196     if (ret != 0) {
197         HNP_LOGE("rmdir path unsuccess.ret=%{public}d, path=%{public}s, errno=%{public}d", ret, path, errno);
198     }
199     return ret;
200 }
201 
HnpCreateFolder(const char * path)202 int HnpCreateFolder(const char* path)
203 {
204     int ret = 0;
205 #ifdef _WIN32
206     return ret;
207 #else
208     char *p = NULL;
209     struct stat buffer;
210 
211     if (path == NULL) {
212         HNP_LOGE("delete folder param path is null");
213         return HNP_ERRNO_BASE_PARAMS_INVALID;
214     }
215 
216     /* 如果目录存在,则返回 */
217     if (stat(path, &buffer) == 0) {
218         return 0;
219     }
220 
221     p = strdup(path);
222     if (p == NULL) {
223         HNP_LOGE("delete folder strdup unsuccess, path=%{public}s, errno=%{public}d", path, errno);
224         return HNP_ERRNO_BASE_STRDUP_FAILED;
225     }
226 
227     for (char *q = p + 1; *q; q++) {
228         if (*q != '/') {
229             continue;
230         }
231         *q = '\0';
232         if (stat(path, &buffer) != 0) {
233             ret = mkdir(p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
234             if ((ret != 0) && (errno != EEXIST)) {
235                 HNP_LOGE("delete folder unsuccess, ret=%{public}d, p=%{public}s, errno:%{public}d", ret, p, errno);
236             }
237         }
238         *q = '/';
239     }
240 
241     if (path[strlen(path) - 1] != '/') {
242         ret = mkdir(p, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
243         if ((ret != 0) && (errno != EEXIST)) {
244             HNP_LOGE("delete folder unsuccess, ret=%{public}d, path=%{public}s, errno:%{public}d", ret, path, errno);
245         }
246     }
247     free(p);
248 
249     if (errno == EEXIST) {
250         ret = 0;
251     }
252     return ret;
253 #endif
254 }
255 
256 #ifdef __cplusplus
257 }
258 #endif