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 43STATIC 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. */ 53STATIC 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 72STATIC 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 83STATIC 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 135STATIC 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 170STATIC 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 201STATIC 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 232INT32 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