• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
3  * Copyright (c) 2020-2021 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 
229         if (fullpath == NULL) {
230             *pathname = NULL;
231             set_errno(ENOMEM);
232             return (char *)NULL;
233         }
234         if (filename[1] == '/') {
235             *pathname = NULL;
236             free(fullpath);
237             set_errno(EINVAL);
238             return (char *)NULL;
239         }
240     }
241 
242     return fullpath;
243 }
244 
vfs_normalize_path(const char * directory,const char * filename,char ** pathname)245 int vfs_normalize_path(const char *directory, const char *filename, char **pathname)
246 {
247     char *fullpath = NULL;
248     int namelen;
249 #ifdef VFS_USING_WORKDIR
250     UINTPTR lock_flags;
251     LosProcessCB *curr = OsCurrProcessGet();
252     BOOL dir_flags = (directory == NULL) ? TRUE : FALSE;
253 #endif
254 
255     namelen = vfs_normalize_path_parame_check(filename, pathname);
256     if (namelen < 0) {
257         return namelen;
258     }
259 
260 #ifdef VFS_USING_WORKDIR
261     if (directory == NULL)
262       {
263         spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
264         directory = curr->files->workdir;
265       }
266 #else
267     if ((directory == NULL) && (filename[0] != '/')) {
268         PRINT_ERR("NO_WORKING_DIR\n");
269         *pathname = NULL;
270         return -EINVAL;
271     }
272 #endif
273 
274     /* 2: The position of the path character: / and the end character /0 */
275 
276     if ((filename[0] != '/') && (strlen(directory) + namelen + 2 > TEMP_PATH_MAX)) {
277 #ifdef VFS_USING_WORKDIR
278         if (dir_flags == TRUE)
279           {
280             spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
281           }
282 #endif
283         return -ENAMETOOLONG;
284     }
285 
286     fullpath = vfs_normalize_fullpath(directory, filename, pathname, namelen);
287 #ifdef VFS_USING_WORKDIR
288     if (dir_flags == TRUE)
289       {
290         spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
291       }
292 #endif
293     if (fullpath == NULL) {
294         return -get_errno();
295     }
296 
297     (void)str_path(fullpath);
298     (void)str_normalize_path(fullpath);
299     if (strlen(fullpath) >= PATH_MAX) {
300         *pathname = NULL;
301         free(fullpath);
302         return -ENAMETOOLONG;
303     }
304 
305     *pathname = fullpath;
306     return ENOERR;
307 }
308 
vfs_normalize_pathat(int dirfd,const char * filename,char ** pathname)309 int vfs_normalize_pathat(int dirfd, const char *filename, char **pathname)
310 {
311     /* Get path by dirfd*/
312     char *relativeoldpath = NULL;
313     char *fullpath = NULL;
314     int ret = 0;
315 
316     ret = get_path_from_fd(dirfd, &relativeoldpath);
317     if (ret < 0) {
318         return ret;
319     }
320 
321     ret = vfs_normalize_path((const char *)relativeoldpath, filename, &fullpath);
322     if (relativeoldpath) {
323         free(relativeoldpath);
324     }
325 
326     if (ret < 0) {
327         return ret;
328     }
329 
330     *pathname = fullpath;
331     return ret;
332 }
333 
334