1 /*
2 * Copyright (c) 2020 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 "nativeapi_fs_impl.h"
17 #include <ctype.h>
18 #include <dirent.h>
19 #include <fcntl.h>
20 #include <limits.h>
21 #include <securec.h>
22 #include <stdbool.h>
23 #include <sys/stat.h>
24 #include <sys/types.h>
25 #include <unistd.h>
26 #include "nativeapi_config.h"
27 #if (defined _WIN32 || defined _WIN64)
28 #include "shlwapi.h"
29 #endif
30
31 #define BUFFER_SIZE 512
32
IsValidPath(const char * path)33 static bool IsValidPath(const char* path)
34 {
35 if (path == NULL) {
36 return false;
37 }
38 size_t pathLen = strnlen(path, FILE_NAME_MAX_LEN + 1);
39 if ((pathLen == 0) || (pathLen > FILE_NAME_MAX_LEN)) {
40 return false;
41 }
42 return true;
43 }
44
GetRealPath(const char * originPath,char * trustPath,size_t tPathLen)45 static int GetRealPath(const char* originPath, char* trustPath, size_t tPathLen)
46 {
47 #if (defined _WIN32 || defined _WIN64)
48 if (PathCanonicalize(trustPath, originPath)) {
49 return NATIVE_SUCCESS;
50 }
51 #else
52 if (realpath(originPath, trustPath) != NULL) {
53 return NATIVE_SUCCESS;
54 }
55 #endif
56
57 if (errno == ENOENT) {
58 if (strncpy_s(trustPath, tPathLen, originPath, strlen(originPath)) == EOK) {
59 return NATIVE_SUCCESS;
60 }
61 }
62 return ERROR_CODE_GENERAL;
63 }
64
RmdirRecursive(const char * fileName)65 static int RmdirRecursive(const char* fileName)
66 {
67 if (!IsValidPath(fileName)) {
68 return ERROR_CODE_PARAM;
69 }
70 int ret = ERROR_CODE_GENERAL;
71 DIR* fileDir = opendir(fileName);
72 if (fileDir == NULL) {
73 return ret;
74 }
75 struct dirent* dir = readdir(fileDir);
76 struct stat info = { 0 };
77 char* fullPath = (char *)malloc(FILE_NAME_MAX_LEN + 1);
78 if (fullPath == NULL) {
79 goto MALLOC_ERROR;
80 }
81 while (dir != NULL) {
82 if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
83 dir = readdir(fileDir);
84 continue;
85 }
86 if (memset_s(fullPath, FILE_NAME_MAX_LEN + 1, 0x0, FILE_NAME_MAX_LEN + 1) != EOK) {
87 goto EXIT;
88 }
89 if (sprintf_s(fullPath, FILE_NAME_MAX_LEN + 1, "%s/%s", fileName, dir->d_name) < 0) {
90 goto EXIT;
91 }
92 if (stat(fullPath, &info) != 0) {
93 goto EXIT;
94 }
95 if (S_ISDIR(info.st_mode)) {
96 ret = RmdirRecursive(fullPath);
97 } else {
98 ret = unlink(fullPath);
99 }
100 if (ret != NATIVE_SUCCESS) {
101 goto EXIT;
102 }
103 dir = readdir(fileDir);
104 }
105 ret = rmdir(fileName);
106
107 EXIT:
108 free(fullPath);
109 MALLOC_ERROR:
110 closedir(fileDir);
111 return ret;
112 }
113
MakeParent(const char * path,char * firstPath,size_t fPathLen,int * dirNum)114 static int MakeParent(const char* path, char* firstPath, size_t fPathLen, int* dirNum)
115 {
116 size_t pathLen = strlen(path) + 1;
117 char* fullPath = (char *)malloc(pathLen);
118 if (fullPath == NULL) {
119 return ERROR_CODE_GENERAL;
120 }
121 if (strcpy_s(fullPath, pathLen, path) != EOK) {
122 free(fullPath);
123 return ERROR_CODE_GENERAL;
124 }
125 int ret = NATIVE_SUCCESS;
126 if (AccessImpl(fullPath) != NATIVE_SUCCESS) {
127 char* sep = strrchr(fullPath, '/');
128 if (sep != NULL) {
129 *sep = 0;
130 MakeParent(fullPath, firstPath, fPathLen, dirNum);
131 *sep = '/';
132 }
133 (*dirNum)++;
134 if (*dirNum > DIR_LEVEL) {
135 free(fullPath);
136 return ERROR_CODE_PARAM;
137 }
138 #if (defined _WIN32 || defined _WIN64)
139 ret = mkdir(fullPath);
140 #else
141 ret = mkdir(fullPath, S_IRUSR | S_IWUSR | S_IXUSR);
142 #endif
143 if ((ret == NATIVE_SUCCESS) && (*dirNum == 1)) {
144 if ((strcpy_s(firstPath, fPathLen, fullPath) != EOK)) {
145 free(fullPath);
146 return ERROR_CODE_GENERAL;
147 }
148 }
149 }
150 free(fullPath);
151 return ret;
152 }
153
MkdirRecursive(const char * path)154 static int MkdirRecursive(const char* path)
155 {
156 char* firstPath = (char *)malloc(FILE_NAME_MAX_LEN + 1);
157 if (firstPath == NULL) {
158 return ERROR_CODE_GENERAL;
159 }
160 if (memset_s(firstPath, FILE_NAME_MAX_LEN + 1, 0x0, FILE_NAME_MAX_LEN + 1) != EOK) {
161 free(firstPath);
162 return ERROR_CODE_GENERAL;
163 }
164 int dirNum = 0;
165 int ret = MakeParent(path, firstPath, FILE_NAME_MAX_LEN + 1, &dirNum);
166 if (ret != NATIVE_SUCCESS) {
167 RmdirRecursive(firstPath);
168 }
169 free(firstPath);
170 return ret;
171 }
172
DoCopyFile(int fdSrc,int fdDest)173 static int DoCopyFile(int fdSrc, int fdDest)
174 {
175 char* dataBuf = (char *)malloc(BUFFER_SIZE);
176 if (dataBuf == NULL) {
177 return ERROR_CODE_GENERAL;
178 }
179 int nLen = read(fdSrc, dataBuf, BUFFER_SIZE);
180 while (nLen > 0) {
181 if (write(fdDest, dataBuf, nLen) != nLen) {
182 free(dataBuf);
183 return ERROR_CODE_IO;
184 }
185 nLen = read(fdSrc, dataBuf, BUFFER_SIZE);
186 }
187 free(dataBuf);
188 return (nLen < 0) ? ERROR_CODE_IO : NATIVE_SUCCESS;
189 }
190
StatImpl(const char * path,struct stat * buf)191 int StatImpl(const char* path, struct stat* buf)
192 {
193 if (!IsValidPath(path) || (buf == NULL)) {
194 return ERROR_CODE_PARAM;
195 }
196
197 if (stat(path, buf) != NATIVE_SUCCESS) {
198 return (-errno);
199 }
200 return NATIVE_SUCCESS;
201 }
202
DeleteFileImpl(const char * src)203 int DeleteFileImpl(const char* src)
204 {
205 if (!IsValidPath(src)) {
206 return ERROR_CODE_PARAM;
207 }
208
209 if (unlink(src) != NATIVE_SUCCESS) {
210 return (-errno);
211 }
212 return NATIVE_SUCCESS;
213 }
214
CopyFileImpl(const char * src,const char * dest)215 int CopyFileImpl(const char* src, const char* dest)
216 {
217 if (!IsValidPath(src) || !IsValidPath(dest)) {
218 return ERROR_CODE_PARAM;
219 }
220 char* realSrc = (char *)malloc(PATH_MAX);
221 if (realSrc == NULL) {
222 return ERROR_CODE_GENERAL;
223 }
224 if (GetRealPath(src, realSrc, PATH_MAX) != NATIVE_SUCCESS) {
225 free(realSrc);
226 return ERROR_CODE_GENERAL;
227 }
228 int fdSrc = open(realSrc, O_RDONLY, S_IRUSR);
229 free(realSrc);
230 realSrc = NULL;
231 if (fdSrc < 0) {
232 return (-errno);
233 }
234 char* realDest = (char *)malloc(PATH_MAX);
235 if (realDest == NULL) {
236 close(fdSrc);
237 return ERROR_CODE_GENERAL;
238 }
239 if (GetRealPath(dest, realDest, PATH_MAX) != NATIVE_SUCCESS) {
240 close(fdSrc);
241 free(realDest);
242 return ERROR_CODE_GENERAL;
243 }
244 int fdDest = open(realDest, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
245 free(realDest);
246 realDest = NULL;
247 if (fdDest < 0) {
248 close(fdSrc);
249 return (-errno);
250 }
251 int ret = DoCopyFile(fdSrc, fdDest);
252 close(fdSrc);
253 close(fdDest);
254 if (ret != NATIVE_SUCCESS) {
255 unlink(dest);
256 }
257 return ret;
258 }
259
WriteTextFile(const char * fileName,const void * buf,size_t len,bool append)260 int WriteTextFile(const char* fileName, const void* buf, size_t len, bool append)
261 {
262 if (!IsValidPath(fileName) || (buf == NULL)) {
263 return ERROR_CODE_PARAM;
264 }
265 char* resolvePath = (char *)malloc(PATH_MAX);
266 if (resolvePath == NULL) {
267 return ERROR_CODE_GENERAL;
268 }
269 if (GetRealPath(fileName, resolvePath, PATH_MAX) != NATIVE_SUCCESS) {
270 free(resolvePath);
271 return ERROR_CODE_GENERAL;
272 }
273 int fileHandle = -1;
274 if (append) {
275 fileHandle = open(resolvePath, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
276 } else {
277 fileHandle = open(resolvePath, O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
278 }
279 free(resolvePath);
280 if (fileHandle < 0) {
281 return (-errno);
282 }
283 int writeLen = write(fileHandle, buf, len);
284 close(fileHandle);
285 return (writeLen != len) ? ERROR_CODE_IO : NATIVE_SUCCESS;
286 }
287
WriteArrayFile(const char * fileName,const void * buf,size_t len,unsigned int position,bool append)288 int WriteArrayFile(const char* fileName, const void* buf, size_t len, unsigned int position, bool append)
289 {
290 if (!IsValidPath(fileName) || (buf == NULL)) {
291 return ERROR_CODE_PARAM;
292 }
293 char* resolvePath = (char *)malloc(PATH_MAX);
294 if (resolvePath == NULL) {
295 return ERROR_CODE_GENERAL;
296 }
297 if (GetRealPath(fileName, resolvePath, PATH_MAX) != NATIVE_SUCCESS) {
298 free(resolvePath);
299 return ERROR_CODE_GENERAL;
300 }
301 int fileHandle = -1;
302 if (append) {
303 fileHandle = open(resolvePath, O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
304 free(resolvePath);
305 resolvePath = NULL;
306 if (fileHandle < 0) {
307 return (-errno);
308 }
309 } else {
310 fileHandle = open(resolvePath, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
311 free(resolvePath);
312 resolvePath = NULL;
313 if (fileHandle < 0) {
314 return (-errno);
315 }
316 if (lseek(fileHandle, position, SEEK_SET) != position) {
317 close(fileHandle);
318 return ERROR_CODE_IO;
319 }
320 }
321 int writeLen = write(fileHandle, buf, len);
322 close(fileHandle);
323 return (writeLen != len) ? ERROR_CODE_IO : NATIVE_SUCCESS;
324 }
325
ReadFileImpl(const char * fileName,void * text,size_t len,unsigned int position,size_t * actualLen)326 int ReadFileImpl(const char* fileName, void* text, size_t len, unsigned int position, size_t* actualLen)
327 {
328 if (!IsValidPath(fileName) || (text == NULL)) {
329 return ERROR_CODE_PARAM;
330 }
331 char* resolvePath = (char *)malloc(PATH_MAX);
332 if (resolvePath == NULL) {
333 return ERROR_CODE_GENERAL;
334 }
335 if (GetRealPath(fileName, resolvePath, PATH_MAX) != NATIVE_SUCCESS) {
336 free(resolvePath);
337 return ERROR_CODE_GENERAL;
338 }
339 int fileHandle = open(resolvePath, O_RDONLY, S_IRUSR);
340 free(resolvePath);
341 resolvePath = NULL;
342 if (fileHandle < 0) {
343 return (-errno);
344 }
345 struct stat info = { 0 };
346 if (fstat(fileHandle, &info) != 0) {
347 close(fileHandle);
348 return ERROR_CODE_IO;
349 }
350 if (position >= info.st_size) {
351 close(fileHandle);
352 return ERROR_CODE_PARAM;
353 }
354 if (len == 0) {
355 len = info.st_size - position;
356 }
357 if (lseek(fileHandle, position, SEEK_SET) != position) {
358 close(fileHandle);
359 return ERROR_CODE_IO;
360 }
361 int readLen = read(fileHandle, text, len);
362 close(fileHandle);
363 *actualLen = readLen;
364 return (readLen < 0) ? ERROR_CODE_IO : NATIVE_SUCCESS;
365 }
366
GetFileListImpl(const char * dirName,FileMetaInfo * fileList,unsigned int listNum)367 int GetFileListImpl(const char* dirName, FileMetaInfo* fileList, unsigned int listNum)
368 {
369 if (!IsValidPath(dirName) || (fileList == NULL)) {
370 return ERROR_CODE_PARAM;
371 }
372 int ret = ERROR_CODE_GENERAL;
373 DIR* fileDir = opendir(dirName);
374 if (fileDir == NULL) {
375 return ret;
376 }
377 int fileIndex = 0;
378 struct dirent* dir = readdir(fileDir);
379 struct stat fileStat = { 0 };
380 char* fullFileName = (char *)malloc(FILE_NAME_MAX_LEN + 1);
381 if (fullFileName == NULL) {
382 goto EXIT;
383 }
384 while ((dir != NULL) && (fileIndex < listNum)) {
385 if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
386 dir = readdir(fileDir);
387 continue;
388 }
389 if (memset_s(fullFileName, FILE_NAME_MAX_LEN + 1, 0x0, FILE_NAME_MAX_LEN + 1) != EOK) {
390 goto EXIT;
391 }
392 if (sprintf_s(fullFileName, FILE_NAME_MAX_LEN + 1, "%s/%s", dirName, dir->d_name) < 0) {
393 goto EXIT;
394 }
395 if (stat(fullFileName, &fileStat) != 0) {
396 goto EXIT;
397 }
398 if (strcpy_s(fileList[fileIndex].fileName, FILE_NAME_MAX_LEN + 1, fullFileName) != EOK) {
399 goto EXIT;
400 }
401 fileList[fileIndex].fileSize = fileStat.st_size;
402 fileList[fileIndex].fileMtime = fileStat.st_mtime;
403 fileList[fileIndex].fileMode = fileStat.st_mode;
404 fileIndex++;
405 dir = readdir(fileDir);
406 }
407 ret = NATIVE_SUCCESS;
408 EXIT:
409 free(fullFileName);
410 closedir(fileDir);
411 return ret;
412 }
413
GetFileNum(const char * dirName)414 int GetFileNum(const char* dirName)
415 {
416 int ret = AccessImpl(dirName);
417 if (ret != NATIVE_SUCCESS) {
418 return ret;
419 }
420 DIR* fileDir = opendir(dirName);
421 if (fileDir == NULL) {
422 return ERROR_CODE_PARAM;
423 }
424 struct dirent* dir = readdir(fileDir);
425 int sum = 0;
426 while (dir != NULL) {
427 if (strcmp(dir->d_name, ".") == 0 || strcmp(dir->d_name, "..") == 0) {
428 dir = readdir(fileDir);
429 continue;
430 }
431 sum++;
432 dir = readdir(fileDir);
433 }
434 closedir(fileDir);
435 return (sum == 0) ? ERROR_CODE_IO : sum;
436 }
437
AccessImpl(const char * fileName)438 int AccessImpl(const char* fileName)
439 {
440 if (!IsValidPath(fileName)) {
441 return ERROR_CODE_PARAM;
442 }
443 if (access(fileName, F_OK) == F_OK) {
444 return NATIVE_SUCCESS;
445 }
446 return (-errno);
447 }
448
CreateDirImpl(const char * fileName,bool recursive)449 int CreateDirImpl(const char* fileName, bool recursive)
450 {
451 if (!IsValidPath(fileName)) {
452 return ERROR_CODE_PARAM;
453 }
454 if (AccessImpl(fileName) == NATIVE_SUCCESS) {
455 return NATIVE_SUCCESS;
456 }
457 if (recursive) {
458 return MkdirRecursive(fileName);
459 }
460 #if (defined _WIN32 || defined _WIN64)
461 int ret = mkdir(fileName);
462 #else
463 int ret = mkdir(fileName, S_IRUSR | S_IWUSR | S_IXUSR);
464 #endif
465 if (ret != NATIVE_SUCCESS) {
466 return (-errno);
467 }
468 return NATIVE_SUCCESS;
469 }
470
RemoveDirImpl(const char * fileName,bool recursive)471 int RemoveDirImpl(const char* fileName, bool recursive)
472 {
473 int ret = AccessImpl(fileName);
474 if (ret != NATIVE_SUCCESS) {
475 return ret;
476 }
477 if (recursive) {
478 return RmdirRecursive(fileName);
479 }
480 if (rmdir(fileName) != NATIVE_SUCCESS) {
481 return (-errno);
482 }
483 return NATIVE_SUCCESS;
484 }