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 52static 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 63static 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 82static 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 93static 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 146static 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 181static 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 213static 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 244int 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 305int 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