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 }