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