• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this list of
9  *    conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice, this list
12  *    of conditions and the following disclaimer in the documentation and/or other materials
13  *    provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its contributors may be used
16  *    to endorse or promote products derived from this software without specific prior written
17  *    permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include "stdio.h"
33 #include "stdlib.h"
34 #include "string.h"
35 #include "errno.h"
36 #include "limits.h"
37 #include "los_process_pri.h"
38 #include "fs/fd_table.h"
39 #include "fs/file.h"
40 
41 #ifdef LOSCFG_SHELL
42 #include "shell.h"
43 #endif
44 
45 
46 #ifdef LOSCFG_SHELL
47 #define TEMP_PATH_MAX (PATH_MAX + SHOW_MAX_LEN)
48 #else
49 #define TEMP_PATH_MAX  PATH_MAX
50 #endif
51 
vfs_strnlen(const char * str,size_t maxlen)52 static unsigned int vfs_strnlen(const char *str, size_t maxlen)
53 {
54     const char *p = NULL;
55 
56     for (p = str; ((maxlen-- != 0) && (*p != '\0')); ++p) {}
57 
58     return p - str;
59 }
60 
61 /* abandon the redundant '/' in the path, only keep one. */
62 
str_path(char * path)63 static char *str_path(char *path)
64 {
65     char *dest = path;
66     char *src = path;
67 
68     while (*src != '\0') {
69         if (*src == '/') {
70             *dest++ = *src++;
71             while (*src == '/') {
72                 src++;
73             }
74             continue;
75         }
76         *dest++ = *src++;
77     }
78     *dest = '\0';
79     return path;
80 }
81 
str_remove_path_end_slash(char * dest,const char * fullpath)82 static void str_remove_path_end_slash(char *dest, const char *fullpath)
83 {
84     if ((*dest == '.') && (*(dest - 1) == '/')) {
85         *dest = '\0';
86         dest--;
87     }
88     if ((dest != fullpath) && (*dest == '/')) {
89         *dest = '\0';
90     }
91 }
92 
str_normalize_path(char * fullpath)93 static char *str_normalize_path(char *fullpath)
94 {
95     char *dest = fullpath;
96     char *src = fullpath;
97 
98     /* 2: The position of the path character: / and the end character /0 */
99 
100     while (*src != '\0') {
101         if (*src == '.') {
102             if (*(src + 1) == '/') {
103                 src += 2;
104                 continue;
105             } else if (*(src + 1) == '.') {
106                 if ((*(src + 2) == '/') || (*(src + 2) == '\0')) {
107                     src += 2;
108                 } else {
109                     while ((*src != '\0') && (*src != '/')) {
110                         *dest++ = *src++;
111                     }
112                     continue;
113                 }
114             } else {
115                 *dest++ = *src++;
116                 continue;
117             }
118         } else {
119             *dest++ = *src++;
120             continue;
121         }
122 
123         if ((dest - 1) != fullpath) {
124             dest--;
125         }
126 
127         while ((dest > fullpath) && (*(dest - 1) != '/')) {
128             dest--;
129         }
130 
131         if (*src == '/') {
132             src++;
133         }
134     }
135 
136     *dest = '\0';
137 
138     /* remove '/' in the end of path if exist */
139 
140     dest--;
141 
142     str_remove_path_end_slash(dest, fullpath);
143     return dest;
144 }
145 
vfs_normalize_path_parame_check(const char * filename,char ** pathname)146 static int vfs_normalize_path_parame_check(const char *filename, char **pathname)
147 {
148     int namelen;
149     char *name = NULL;
150 
151     if (pathname == NULL) {
152         return -EINVAL;
153     }
154 
155     /* check parameters */
156 
157     if (filename == NULL) {
158         *pathname = NULL;
159         return -EINVAL;
160     }
161 
162     namelen = vfs_strnlen(filename, PATH_MAX);
163     if (!namelen) {
164         *pathname = NULL;
165         return -EINVAL;
166     } else if (namelen >= PATH_MAX) {
167         *pathname = NULL;
168         return -ENAMETOOLONG;
169     }
170 
171     for (name = (char *)filename + namelen; ((name != filename) && (*name != '/')); name--) {
172         if (strlen(name) > NAME_MAX) {
173             *pathname = NULL;
174             return -ENAMETOOLONG;
175         }
176     }
177 
178     return namelen;
179 }
180 
vfs_not_absolute_path(const char * directory,const char * filename,char ** pathname,int namelen)181 static char *vfs_not_absolute_path(const char *directory, const char *filename, char **pathname, int namelen)
182 {
183     int ret;
184     char *fullpath = NULL;
185 
186     /* 2: The position of the path character: / and the end character /0 */
187 
188     if ((namelen > 1) && (filename[0] == '.') && (filename[1] == '/')) {
189         filename += 2;
190     }
191 
192     fullpath = (char *)malloc(strlen(directory) + namelen + 2);
193     if (fullpath == NULL) {
194         *pathname = NULL;
195         set_errno(ENOMEM);
196         return (char *)NULL;
197     }
198 
199     /* join path and file name */
200 
201     ret = snprintf_s(fullpath, strlen(directory) + namelen + 2, strlen(directory) + namelen + 1,
202                      "%s/%s", directory, filename);
203     if (ret < 0) {
204         *pathname = NULL;
205         free(fullpath);
206         set_errno(ENAMETOOLONG);
207         return (char *)NULL;
208     }
209 
210     return fullpath;
211 }
212 
vfs_normalize_fullpath(const char * directory,const char * filename,char ** pathname,int namelen)213 static char *vfs_normalize_fullpath(const char *directory, const char *filename, char **pathname, int namelen)
214 {
215     char *fullpath = NULL;
216 
217     if (filename[0] != '/') {
218         /* not a absolute path */
219 
220         fullpath = vfs_not_absolute_path(directory, filename, pathname, namelen);
221         if (fullpath == NULL) {
222             return (char *)NULL;
223         }
224     } else {
225         /* it's a absolute path, use it directly */
226 
227         fullpath = strdup(filename); /* copy string */
228         if (fullpath == NULL) {
229             *pathname = NULL;
230             set_errno(ENOMEM);
231             return (char *)NULL;
232         }
233         if (filename[1] == '/') {
234             *pathname = NULL;
235             free(fullpath);
236             set_errno(EINVAL);
237             return (char *)NULL;
238         }
239     }
240 
241     return fullpath;
242 }
243 
vfs_normalize_path(const char * directory,const char * filename,char ** pathname)244 int vfs_normalize_path(const char *directory, const char *filename, char **pathname)
245 {
246     char *fullpath = NULL;
247     int namelen;
248 #ifdef VFS_USING_WORKDIR
249     UINTPTR lock_flags;
250     LosProcessCB *curr = OsCurrProcessGet();
251     BOOL dir_flags = (directory == NULL) ? TRUE : FALSE;
252 #endif
253 
254     namelen = vfs_normalize_path_parame_check(filename, pathname);
255     if (namelen < 0) {
256         return namelen;
257     }
258 
259 #ifdef VFS_USING_WORKDIR
260     if (directory == NULL) {
261         spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
262         directory = curr->files->workdir;
263     }
264 #else
265     if ((directory == NULL) && (filename[0] != '/')) {
266         PRINT_ERR("NO_WORKING_DIR\n");
267         *pathname = NULL;
268         return -EINVAL;
269     }
270 #endif
271 
272     /* 2: The position of the path character: / and the end character /0 */
273 
274     if ((filename[0] != '/') && (strlen(directory) + namelen + 2 > TEMP_PATH_MAX)) {
275 #ifdef VFS_USING_WORKDIR
276         if (dir_flags == TRUE) {
277             spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
278         }
279 #endif
280         return -ENAMETOOLONG;
281     }
282 
283     fullpath = vfs_normalize_fullpath(directory, filename, pathname, namelen);
284 #ifdef VFS_USING_WORKDIR
285     if (dir_flags == TRUE) {
286         spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
287     }
288 #endif
289     if (fullpath == NULL) {
290         return -get_errno();
291     }
292 
293     (void)str_path(fullpath);
294     (void)str_normalize_path(fullpath);
295     if (strlen(fullpath) >= PATH_MAX) {
296         *pathname = NULL;
297         free(fullpath);
298         return -ENAMETOOLONG;
299     }
300 
301     *pathname = fullpath;
302     return ENOERR;
303 }
304 
vfs_normalize_pathat(int dirfd,const char * filename,char ** pathname)305 int vfs_normalize_pathat(int dirfd, const char *filename, char **pathname)
306 {
307     /* Get path by dirfd */
308     char *relativeoldpath = NULL;
309     char *fullpath = NULL;
310     int ret = 0;
311 
312     ret = get_path_from_fd(dirfd, &relativeoldpath);
313     if (ret < 0) {
314         return ret;
315     }
316 
317     ret = vfs_normalize_path((const char *)relativeoldpath, filename, &fullpath);
318     if (relativeoldpath) {
319         free(relativeoldpath);
320     }
321 
322     if (ret < 0) {
323         return ret;
324     }
325 
326     *pathname = fullpath;
327     return ret;
328 }
329 
330