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 <securec.h>
33 #include "stdio.h"
34 #include "stdlib.h"
35 #include "string.h"
36 #include "errno.h"
37 #include "limits.h"
38 #include "shell.h"
39 #include "show.h"
40
41 #define TEMP_PATH_MAX (PATH_MAX + SHOW_MAX_LEN)
42
VfsStrnlen(const CHAR * str,size_t maxlen)43 STATIC UINT32 VfsStrnlen(const CHAR *str, size_t maxlen)
44 {
45 const CHAR *p = NULL;
46
47 for (p = str; ((maxlen-- != 0) && (*p != '\0')); ++p) {}
48
49 return p - str;
50 }
51
52 /* abandon the redundant '/' in the path, only keep one. */
StrPath(CHAR * path)53 STATIC CHAR *StrPath(CHAR *path)
54 {
55 CHAR *dest = path;
56 CHAR *src = path;
57
58 while (*src != '\0') {
59 if (*src == '/') {
60 *dest++ = *src++;
61 while (*src == '/') {
62 src++;
63 }
64 continue;
65 }
66 *dest++ = *src++;
67 }
68 *dest = '\0';
69 return path;
70 }
71
StrRemovePathEndSlash(CHAR * dest,const CHAR * fullpath)72 STATIC VOID StrRemovePathEndSlash(CHAR *dest, const CHAR *fullpath)
73 {
74 if ((*dest == '.') && (*(dest - 1) == '/')) {
75 *dest = '\0';
76 dest--;
77 }
78 if ((dest != fullpath) && (*dest == '/')) {
79 *dest = '\0';
80 }
81 }
82
StrNormalizePath(CHAR * fullpath)83 STATIC CHAR *StrNormalizePath(CHAR *fullpath)
84 {
85 CHAR *dest = fullpath;
86 CHAR *src = fullpath;
87
88 /* 2: The position of the path character: / and the end character /0 */
89 while (*src != '\0') {
90 if (*src == '.') {
91 if (*(src + 1) == '/') {
92 src += 2; /* 2, sizeof "./" */
93 continue;
94 } else if (*(src + 1) == '.') {
95 if ((*(src + 2) == '/') || (*(src + 2) == '\0')) { /* 2, 2, offset to check */
96 src += 2; /* 2, sizeof offset */
97 } else {
98 while ((*src != '\0') && (*src != '/')) {
99 *dest++ = *src++;
100 }
101 continue;
102 }
103 } else {
104 *dest++ = *src++;
105 continue;
106 }
107 } else {
108 *dest++ = *src++;
109 continue;
110 }
111
112 if ((dest - 1) != fullpath) {
113 dest--;
114 }
115
116 while ((dest > fullpath) && (*(dest - 1) != '/')) {
117 dest--;
118 }
119
120 if (*src == '/') {
121 src++;
122 }
123 }
124
125 *dest = '\0';
126
127 /* remove '/' in the end of path if exist */
128
129 dest--;
130
131 StrRemovePathEndSlash(dest, fullpath);
132 return dest;
133 }
134
VfsNormalizePathParameCheck(const CHAR * filename,CHAR ** pathname)135 STATIC INT32 VfsNormalizePathParameCheck(const CHAR *filename, CHAR **pathname)
136 {
137 INT32 namelen;
138 CHAR *name = NULL;
139
140 if (pathname == NULL) {
141 return -EINVAL;
142 }
143
144 /* check parameters */
145
146 if (filename == NULL) {
147 *pathname = NULL;
148 return -EINVAL;
149 }
150
151 namelen = VfsStrnlen(filename, PATH_MAX);
152 if (!namelen) {
153 *pathname = NULL;
154 return -EINVAL;
155 } else if (namelen >= PATH_MAX) {
156 *pathname = NULL;
157 return -ENAMETOOLONG;
158 }
159
160 for (name = (CHAR *)filename + namelen; ((name != filename) && (*name != '/')); name--) {
161 if (strlen(name) > NAME_MAX) {
162 *pathname = NULL;
163 return -ENAMETOOLONG;
164 }
165 }
166
167 return namelen;
168 }
169
VfsNotAbsolutePath(const CHAR * directory,const CHAR * filename,CHAR ** pathname,INT32 namelen)170 STATIC CHAR *VfsNotAbsolutePath(const CHAR *directory, const CHAR *filename, CHAR **pathname, INT32 namelen)
171 {
172 INT32 ret;
173 CHAR *fullpath = NULL;
174
175 /* 2: The position of the path character: / and the end character /0 */
176
177 if ((namelen > 1) && (filename[0] == '.') && (filename[1] == '/')) {
178 filename += 2; /* 2, size of "./" */
179 }
180
181 fullpath = (CHAR *)malloc(strlen(directory) + namelen + 2); /* 2, size of "./" */
182 if (fullpath == NULL) {
183 *pathname = NULL;
184 SetErrno(ENOMEM);
185 return (CHAR *)NULL;
186 }
187
188 /* 2, size of "./", join path and file name */
189 ret = snprintf_s(fullpath, strlen(directory) + namelen + 2, strlen(directory) + namelen + 1,
190 "%s/%s", directory, filename);
191 if (ret < 0) {
192 *pathname = NULL;
193 free(fullpath);
194 SetErrno(ENAMETOOLONG);
195 return (CHAR *)NULL;
196 }
197
198 return fullpath;
199 }
200
VfsNormalizeFullpath(const CHAR * directory,const CHAR * filename,CHAR ** pathname,INT32 namelen)201 STATIC CHAR *VfsNormalizeFullpath(const CHAR *directory, const CHAR *filename, CHAR **pathname, INT32 namelen)
202 {
203 CHAR *fullpath = NULL;
204
205 if (filename[0] != '/') {
206 /* not an absolute path */
207
208 fullpath = VfsNotAbsolutePath(directory, filename, pathname, namelen);
209 if (fullpath == NULL) {
210 return (CHAR *)NULL;
211 }
212 } else {
213 /* it's an absolute path, use it directly */
214
215 fullpath = strdup(filename); /* copy string */
216 if (fullpath == NULL) {
217 *pathname = NULL;
218 SetErrno(ENOMEM);
219 return (CHAR *)NULL;
220 }
221 if (filename[1] == '/') {
222 *pathname = NULL;
223 free(fullpath);
224 SetErrno(EINVAL);
225 return (CHAR *)NULL;
226 }
227 }
228
229 return fullpath;
230 }
231
VfsNormalizePath(const CHAR * directory,const CHAR * filename,CHAR ** pathname)232 INT32 VfsNormalizePath(const CHAR *directory, const CHAR *filename, CHAR **pathname)
233 {
234 CHAR *fullpath = NULL;
235 INT32 namelen;
236
237 namelen = VfsNormalizePathParameCheck(filename, pathname);
238 if (namelen < 0) {
239 return namelen;
240 }
241
242 if ((directory == NULL) && (filename[0] != '/')) {
243 PRINT_ERR("NO_WORKING_DIR\n");
244 *pathname = NULL;
245 return -EINVAL;
246 }
247
248 /* 2, The position of the path character: / and the end character /0 */
249 if ((filename[0] != '/') && (strlen(directory) + namelen + 2 > TEMP_PATH_MAX)) {
250 return -ENAMETOOLONG;
251 }
252
253 fullpath = VfsNormalizeFullpath(directory, filename, pathname, namelen);
254 if (fullpath == NULL) {
255 return -errno;
256 }
257
258 (VOID)StrPath(fullpath);
259 (VOID)StrNormalizePath(fullpath);
260 if (strlen(fullpath) >= PATH_MAX) {
261 *pathname = NULL;
262 free(fullpath);
263 return -ENAMETOOLONG;
264 }
265
266 *pathname = fullpath;
267 return 0;
268 }
269
270