10d163575Sopenharmony_ci/* 20d163575Sopenharmony_ci * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. 30d163575Sopenharmony_ci * Copyright (c) 2020-2022 Huawei Device Co., Ltd. All rights reserved. 40d163575Sopenharmony_ci * 50d163575Sopenharmony_ci * Redistribution and use in source and binary forms, with or without modification, 60d163575Sopenharmony_ci * are permitted provided that the following conditions are met: 70d163575Sopenharmony_ci * 80d163575Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright notice, this list of 90d163575Sopenharmony_ci * conditions and the following disclaimer. 100d163575Sopenharmony_ci * 110d163575Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright notice, this list 120d163575Sopenharmony_ci * of conditions and the following disclaimer in the documentation and/or other materials 130d163575Sopenharmony_ci * provided with the distribution. 140d163575Sopenharmony_ci * 150d163575Sopenharmony_ci * 3. Neither the name of the copyright holder nor the names of its contributors may be used 160d163575Sopenharmony_ci * to endorse or promote products derived from this software without specific prior written 170d163575Sopenharmony_ci * permission. 180d163575Sopenharmony_ci * 190d163575Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 200d163575Sopenharmony_ci * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 210d163575Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 220d163575Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 230d163575Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 240d163575Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 250d163575Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 260d163575Sopenharmony_ci * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 270d163575Sopenharmony_ci * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 280d163575Sopenharmony_ci * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 290d163575Sopenharmony_ci * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 300d163575Sopenharmony_ci */ 310d163575Sopenharmony_ci 320d163575Sopenharmony_ci#include "stdio.h" 330d163575Sopenharmony_ci#include "stdlib.h" 340d163575Sopenharmony_ci#include "string.h" 350d163575Sopenharmony_ci#include "errno.h" 360d163575Sopenharmony_ci#include "limits.h" 370d163575Sopenharmony_ci#include "los_process_pri.h" 380d163575Sopenharmony_ci#include "fs/fd_table.h" 390d163575Sopenharmony_ci#include "fs/file.h" 400d163575Sopenharmony_ci 410d163575Sopenharmony_ci#ifdef LOSCFG_SHELL 420d163575Sopenharmony_ci#include "shell.h" 430d163575Sopenharmony_ci#endif 440d163575Sopenharmony_ci 450d163575Sopenharmony_ci 460d163575Sopenharmony_ci#ifdef LOSCFG_SHELL 470d163575Sopenharmony_ci#define TEMP_PATH_MAX (PATH_MAX + SHOW_MAX_LEN) 480d163575Sopenharmony_ci#else 490d163575Sopenharmony_ci#define TEMP_PATH_MAX PATH_MAX 500d163575Sopenharmony_ci#endif 510d163575Sopenharmony_ci 520d163575Sopenharmony_cistatic unsigned int vfs_strnlen(const char *str, size_t maxlen) 530d163575Sopenharmony_ci{ 540d163575Sopenharmony_ci const char *p = NULL; 550d163575Sopenharmony_ci 560d163575Sopenharmony_ci for (p = str; ((maxlen-- != 0) && (*p != '\0')); ++p) {} 570d163575Sopenharmony_ci 580d163575Sopenharmony_ci return p - str; 590d163575Sopenharmony_ci} 600d163575Sopenharmony_ci 610d163575Sopenharmony_ci/* abandon the redundant '/' in the path, only keep one. */ 620d163575Sopenharmony_ci 630d163575Sopenharmony_cistatic char *str_path(char *path) 640d163575Sopenharmony_ci{ 650d163575Sopenharmony_ci char *dest = path; 660d163575Sopenharmony_ci char *src = path; 670d163575Sopenharmony_ci 680d163575Sopenharmony_ci while (*src != '\0') { 690d163575Sopenharmony_ci if (*src == '/') { 700d163575Sopenharmony_ci *dest++ = *src++; 710d163575Sopenharmony_ci while (*src == '/') { 720d163575Sopenharmony_ci src++; 730d163575Sopenharmony_ci } 740d163575Sopenharmony_ci continue; 750d163575Sopenharmony_ci } 760d163575Sopenharmony_ci *dest++ = *src++; 770d163575Sopenharmony_ci } 780d163575Sopenharmony_ci *dest = '\0'; 790d163575Sopenharmony_ci return path; 800d163575Sopenharmony_ci} 810d163575Sopenharmony_ci 820d163575Sopenharmony_cistatic void str_remove_path_end_slash(char *dest, const char *fullpath) 830d163575Sopenharmony_ci{ 840d163575Sopenharmony_ci if ((*dest == '.') && (*(dest - 1) == '/')) { 850d163575Sopenharmony_ci *dest = '\0'; 860d163575Sopenharmony_ci dest--; 870d163575Sopenharmony_ci } 880d163575Sopenharmony_ci if ((dest != fullpath) && (*dest == '/')) { 890d163575Sopenharmony_ci *dest = '\0'; 900d163575Sopenharmony_ci } 910d163575Sopenharmony_ci} 920d163575Sopenharmony_ci 930d163575Sopenharmony_cistatic char *str_normalize_path(char *fullpath) 940d163575Sopenharmony_ci{ 950d163575Sopenharmony_ci char *dest = fullpath; 960d163575Sopenharmony_ci char *src = fullpath; 970d163575Sopenharmony_ci 980d163575Sopenharmony_ci /* 2: The position of the path character: / and the end character /0 */ 990d163575Sopenharmony_ci 1000d163575Sopenharmony_ci while (*src != '\0') { 1010d163575Sopenharmony_ci if (*src == '.') { 1020d163575Sopenharmony_ci if (*(src + 1) == '/') { 1030d163575Sopenharmony_ci src += 2; 1040d163575Sopenharmony_ci continue; 1050d163575Sopenharmony_ci } else if (*(src + 1) == '.') { 1060d163575Sopenharmony_ci if ((*(src + 2) == '/') || (*(src + 2) == '\0')) { 1070d163575Sopenharmony_ci src += 2; 1080d163575Sopenharmony_ci } else { 1090d163575Sopenharmony_ci while ((*src != '\0') && (*src != '/')) { 1100d163575Sopenharmony_ci *dest++ = *src++; 1110d163575Sopenharmony_ci } 1120d163575Sopenharmony_ci continue; 1130d163575Sopenharmony_ci } 1140d163575Sopenharmony_ci } else { 1150d163575Sopenharmony_ci *dest++ = *src++; 1160d163575Sopenharmony_ci continue; 1170d163575Sopenharmony_ci } 1180d163575Sopenharmony_ci } else { 1190d163575Sopenharmony_ci *dest++ = *src++; 1200d163575Sopenharmony_ci continue; 1210d163575Sopenharmony_ci } 1220d163575Sopenharmony_ci 1230d163575Sopenharmony_ci if ((dest - 1) != fullpath) { 1240d163575Sopenharmony_ci dest--; 1250d163575Sopenharmony_ci } 1260d163575Sopenharmony_ci 1270d163575Sopenharmony_ci while ((dest > fullpath) && (*(dest - 1) != '/')) { 1280d163575Sopenharmony_ci dest--; 1290d163575Sopenharmony_ci } 1300d163575Sopenharmony_ci 1310d163575Sopenharmony_ci if (*src == '/') { 1320d163575Sopenharmony_ci src++; 1330d163575Sopenharmony_ci } 1340d163575Sopenharmony_ci } 1350d163575Sopenharmony_ci 1360d163575Sopenharmony_ci *dest = '\0'; 1370d163575Sopenharmony_ci 1380d163575Sopenharmony_ci /* remove '/' in the end of path if exist */ 1390d163575Sopenharmony_ci 1400d163575Sopenharmony_ci dest--; 1410d163575Sopenharmony_ci 1420d163575Sopenharmony_ci str_remove_path_end_slash(dest, fullpath); 1430d163575Sopenharmony_ci return dest; 1440d163575Sopenharmony_ci} 1450d163575Sopenharmony_ci 1460d163575Sopenharmony_cistatic int vfs_normalize_path_parame_check(const char *filename, char **pathname) 1470d163575Sopenharmony_ci{ 1480d163575Sopenharmony_ci int namelen; 1490d163575Sopenharmony_ci char *name = NULL; 1500d163575Sopenharmony_ci 1510d163575Sopenharmony_ci if (pathname == NULL) { 1520d163575Sopenharmony_ci return -EINVAL; 1530d163575Sopenharmony_ci } 1540d163575Sopenharmony_ci 1550d163575Sopenharmony_ci /* check parameters */ 1560d163575Sopenharmony_ci 1570d163575Sopenharmony_ci if (filename == NULL) { 1580d163575Sopenharmony_ci *pathname = NULL; 1590d163575Sopenharmony_ci return -EINVAL; 1600d163575Sopenharmony_ci } 1610d163575Sopenharmony_ci 1620d163575Sopenharmony_ci namelen = vfs_strnlen(filename, PATH_MAX); 1630d163575Sopenharmony_ci if (!namelen) { 1640d163575Sopenharmony_ci *pathname = NULL; 1650d163575Sopenharmony_ci return -EINVAL; 1660d163575Sopenharmony_ci } else if (namelen >= PATH_MAX) { 1670d163575Sopenharmony_ci *pathname = NULL; 1680d163575Sopenharmony_ci return -ENAMETOOLONG; 1690d163575Sopenharmony_ci } 1700d163575Sopenharmony_ci 1710d163575Sopenharmony_ci for (name = (char *)filename + namelen; ((name != filename) && (*name != '/')); name--) { 1720d163575Sopenharmony_ci if (strlen(name) > NAME_MAX) { 1730d163575Sopenharmony_ci *pathname = NULL; 1740d163575Sopenharmony_ci return -ENAMETOOLONG; 1750d163575Sopenharmony_ci } 1760d163575Sopenharmony_ci } 1770d163575Sopenharmony_ci 1780d163575Sopenharmony_ci return namelen; 1790d163575Sopenharmony_ci} 1800d163575Sopenharmony_ci 1810d163575Sopenharmony_cistatic char *vfs_not_absolute_path(const char *directory, const char *filename, char **pathname, int namelen) 1820d163575Sopenharmony_ci{ 1830d163575Sopenharmony_ci int ret; 1840d163575Sopenharmony_ci char *fullpath = NULL; 1850d163575Sopenharmony_ci 1860d163575Sopenharmony_ci /* 2: The position of the path character: / and the end character /0 */ 1870d163575Sopenharmony_ci 1880d163575Sopenharmony_ci if ((namelen > 1) && (filename[0] == '.') && (filename[1] == '/')) { 1890d163575Sopenharmony_ci filename += 2; 1900d163575Sopenharmony_ci } 1910d163575Sopenharmony_ci 1920d163575Sopenharmony_ci fullpath = (char *)malloc(strlen(directory) + namelen + 2); 1930d163575Sopenharmony_ci if (fullpath == NULL) { 1940d163575Sopenharmony_ci *pathname = NULL; 1950d163575Sopenharmony_ci set_errno(ENOMEM); 1960d163575Sopenharmony_ci return (char *)NULL; 1970d163575Sopenharmony_ci } 1980d163575Sopenharmony_ci 1990d163575Sopenharmony_ci /* join path and file name */ 2000d163575Sopenharmony_ci 2010d163575Sopenharmony_ci ret = snprintf_s(fullpath, strlen(directory) + namelen + 2, strlen(directory) + namelen + 1, 2020d163575Sopenharmony_ci "%s/%s", directory, filename); 2030d163575Sopenharmony_ci if (ret < 0) { 2040d163575Sopenharmony_ci *pathname = NULL; 2050d163575Sopenharmony_ci free(fullpath); 2060d163575Sopenharmony_ci set_errno(ENAMETOOLONG); 2070d163575Sopenharmony_ci return (char *)NULL; 2080d163575Sopenharmony_ci } 2090d163575Sopenharmony_ci 2100d163575Sopenharmony_ci return fullpath; 2110d163575Sopenharmony_ci} 2120d163575Sopenharmony_ci 2130d163575Sopenharmony_cistatic char *vfs_normalize_fullpath(const char *directory, const char *filename, char **pathname, int namelen) 2140d163575Sopenharmony_ci{ 2150d163575Sopenharmony_ci char *fullpath = NULL; 2160d163575Sopenharmony_ci 2170d163575Sopenharmony_ci if (filename[0] != '/') { 2180d163575Sopenharmony_ci /* not a absolute path */ 2190d163575Sopenharmony_ci 2200d163575Sopenharmony_ci fullpath = vfs_not_absolute_path(directory, filename, pathname, namelen); 2210d163575Sopenharmony_ci if (fullpath == NULL) { 2220d163575Sopenharmony_ci return (char *)NULL; 2230d163575Sopenharmony_ci } 2240d163575Sopenharmony_ci } else { 2250d163575Sopenharmony_ci /* it's a absolute path, use it directly */ 2260d163575Sopenharmony_ci 2270d163575Sopenharmony_ci fullpath = strdup(filename); /* copy string */ 2280d163575Sopenharmony_ci if (fullpath == NULL) { 2290d163575Sopenharmony_ci *pathname = NULL; 2300d163575Sopenharmony_ci set_errno(ENOMEM); 2310d163575Sopenharmony_ci return (char *)NULL; 2320d163575Sopenharmony_ci } 2330d163575Sopenharmony_ci if (filename[1] == '/') { 2340d163575Sopenharmony_ci *pathname = NULL; 2350d163575Sopenharmony_ci free(fullpath); 2360d163575Sopenharmony_ci set_errno(EINVAL); 2370d163575Sopenharmony_ci return (char *)NULL; 2380d163575Sopenharmony_ci } 2390d163575Sopenharmony_ci } 2400d163575Sopenharmony_ci 2410d163575Sopenharmony_ci return fullpath; 2420d163575Sopenharmony_ci} 2430d163575Sopenharmony_ci 2440d163575Sopenharmony_ciint vfs_normalize_path(const char *directory, const char *filename, char **pathname) 2450d163575Sopenharmony_ci{ 2460d163575Sopenharmony_ci char *fullpath = NULL; 2470d163575Sopenharmony_ci int namelen; 2480d163575Sopenharmony_ci#ifdef VFS_USING_WORKDIR 2490d163575Sopenharmony_ci UINTPTR lock_flags; 2500d163575Sopenharmony_ci LosProcessCB *curr = OsCurrProcessGet(); 2510d163575Sopenharmony_ci BOOL dir_flags = (directory == NULL) ? TRUE : FALSE; 2520d163575Sopenharmony_ci#endif 2530d163575Sopenharmony_ci 2540d163575Sopenharmony_ci namelen = vfs_normalize_path_parame_check(filename, pathname); 2550d163575Sopenharmony_ci if (namelen < 0) { 2560d163575Sopenharmony_ci return namelen; 2570d163575Sopenharmony_ci } 2580d163575Sopenharmony_ci 2590d163575Sopenharmony_ci#ifdef VFS_USING_WORKDIR 2600d163575Sopenharmony_ci if (directory == NULL) { 2610d163575Sopenharmony_ci spin_lock_irqsave(&curr->files->workdir_lock, lock_flags); 2620d163575Sopenharmony_ci directory = curr->files->workdir; 2630d163575Sopenharmony_ci } 2640d163575Sopenharmony_ci#else 2650d163575Sopenharmony_ci if ((directory == NULL) && (filename[0] != '/')) { 2660d163575Sopenharmony_ci PRINT_ERR("NO_WORKING_DIR\n"); 2670d163575Sopenharmony_ci *pathname = NULL; 2680d163575Sopenharmony_ci return -EINVAL; 2690d163575Sopenharmony_ci } 2700d163575Sopenharmony_ci#endif 2710d163575Sopenharmony_ci 2720d163575Sopenharmony_ci /* 2: The position of the path character: / and the end character /0 */ 2730d163575Sopenharmony_ci 2740d163575Sopenharmony_ci if ((filename[0] != '/') && (strlen(directory) + namelen + 2 > TEMP_PATH_MAX)) { 2750d163575Sopenharmony_ci#ifdef VFS_USING_WORKDIR 2760d163575Sopenharmony_ci if (dir_flags == TRUE) { 2770d163575Sopenharmony_ci spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags); 2780d163575Sopenharmony_ci } 2790d163575Sopenharmony_ci#endif 2800d163575Sopenharmony_ci return -ENAMETOOLONG; 2810d163575Sopenharmony_ci } 2820d163575Sopenharmony_ci 2830d163575Sopenharmony_ci fullpath = vfs_normalize_fullpath(directory, filename, pathname, namelen); 2840d163575Sopenharmony_ci#ifdef VFS_USING_WORKDIR 2850d163575Sopenharmony_ci if (dir_flags == TRUE) { 2860d163575Sopenharmony_ci spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags); 2870d163575Sopenharmony_ci } 2880d163575Sopenharmony_ci#endif 2890d163575Sopenharmony_ci if (fullpath == NULL) { 2900d163575Sopenharmony_ci return -get_errno(); 2910d163575Sopenharmony_ci } 2920d163575Sopenharmony_ci 2930d163575Sopenharmony_ci (void)str_path(fullpath); 2940d163575Sopenharmony_ci (void)str_normalize_path(fullpath); 2950d163575Sopenharmony_ci if (strlen(fullpath) >= PATH_MAX) { 2960d163575Sopenharmony_ci *pathname = NULL; 2970d163575Sopenharmony_ci free(fullpath); 2980d163575Sopenharmony_ci return -ENAMETOOLONG; 2990d163575Sopenharmony_ci } 3000d163575Sopenharmony_ci 3010d163575Sopenharmony_ci *pathname = fullpath; 3020d163575Sopenharmony_ci return ENOERR; 3030d163575Sopenharmony_ci} 3040d163575Sopenharmony_ci 3050d163575Sopenharmony_ciint vfs_normalize_pathat(int dirfd, const char *filename, char **pathname) 3060d163575Sopenharmony_ci{ 3070d163575Sopenharmony_ci /* Get path by dirfd */ 3080d163575Sopenharmony_ci char *relativeoldpath = NULL; 3090d163575Sopenharmony_ci char *fullpath = NULL; 3100d163575Sopenharmony_ci int ret = 0; 3110d163575Sopenharmony_ci 3120d163575Sopenharmony_ci ret = get_path_from_fd(dirfd, &relativeoldpath); 3130d163575Sopenharmony_ci if (ret < 0) { 3140d163575Sopenharmony_ci return ret; 3150d163575Sopenharmony_ci } 3160d163575Sopenharmony_ci 3170d163575Sopenharmony_ci ret = vfs_normalize_path((const char *)relativeoldpath, filename, &fullpath); 3180d163575Sopenharmony_ci if (relativeoldpath) { 3190d163575Sopenharmony_ci free(relativeoldpath); 3200d163575Sopenharmony_ci } 3210d163575Sopenharmony_ci 3220d163575Sopenharmony_ci if (ret < 0) { 3230d163575Sopenharmony_ci return ret; 3240d163575Sopenharmony_ci } 3250d163575Sopenharmony_ci 3260d163575Sopenharmony_ci *pathname = fullpath; 3270d163575Sopenharmony_ci return ret; 3280d163575Sopenharmony_ci} 3290d163575Sopenharmony_ci 330