344 lines
8.6 KiB
C
Executable File
344 lines
8.6 KiB
C
Executable File
/*
|
|
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
|
|
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without modification,
|
|
* are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice, this list of
|
|
* conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
|
|
* of conditions and the following disclaimer in the documentation and/or other materials
|
|
* provided with the distribution.
|
|
*
|
|
* 3. Neither the name of the copyright holder nor the names of its contributors may be used
|
|
* to endorse or promote products derived from this software without specific prior written
|
|
* permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
|
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "stdio.h"
|
|
#include "stdlib.h"
|
|
#include "string.h"
|
|
#include "errno.h"
|
|
#include "limits.h"
|
|
#include "los_process_pri.h"
|
|
#include "fs/fd_table.h"
|
|
#include "fs/file.h"
|
|
|
|
#ifdef LOSCFG_SHELL
|
|
#include "shell.h"
|
|
#endif
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
extern "C" {
|
|
#endif /* __cplusplus */
|
|
#endif /* __cplusplus */
|
|
|
|
#ifdef LOSCFG_SHELL
|
|
#define TEMP_PATH_MAX (PATH_MAX + SHOW_MAX_LEN)
|
|
#else
|
|
#define TEMP_PATH_MAX PATH_MAX
|
|
#endif
|
|
|
|
static unsigned int vfs_strnlen(const char *str, size_t maxlen)
|
|
{
|
|
const char *p = NULL;
|
|
|
|
for (p = str; ((maxlen-- != 0) && (*p != '\0')); ++p) {}
|
|
|
|
return p - str;
|
|
}
|
|
|
|
/* abandon the redundant '/' in the path, only keep one. */
|
|
|
|
static char *str_path(char *path)
|
|
{
|
|
char *dest = path;
|
|
char *src = path;
|
|
|
|
while (*src != '\0') {
|
|
if (*src == '/') {
|
|
*dest++ = *src++;
|
|
while (*src == '/') {
|
|
src++;
|
|
}
|
|
continue;
|
|
}
|
|
*dest++ = *src++;
|
|
}
|
|
*dest = '\0';
|
|
return path;
|
|
}
|
|
|
|
static void str_remove_path_end_slash(char *dest, const char *fullpath)
|
|
{
|
|
if ((*dest == '.') && (*(dest - 1) == '/')) {
|
|
*dest = '\0';
|
|
dest--;
|
|
}
|
|
if ((dest != fullpath) && (*dest == '/')) {
|
|
*dest = '\0';
|
|
}
|
|
}
|
|
|
|
static char *str_normalize_path(char *fullpath)
|
|
{
|
|
char *dest = fullpath;
|
|
char *src = fullpath;
|
|
|
|
/* 2: The position of the path character: / and the end character /0 */
|
|
|
|
while (*src != '\0') {
|
|
if (*src == '.') {
|
|
if (*(src + 1) == '/') {
|
|
src += 2;
|
|
continue;
|
|
} else if (*(src + 1) == '.') {
|
|
if ((*(src + 2) == '/') || (*(src + 2) == '\0')) {
|
|
src += 2;
|
|
} else {
|
|
while ((*src != '\0') && (*src != '/')) {
|
|
*dest++ = *src++;
|
|
}
|
|
continue;
|
|
}
|
|
} else {
|
|
*dest++ = *src++;
|
|
continue;
|
|
}
|
|
} else {
|
|
*dest++ = *src++;
|
|
continue;
|
|
}
|
|
|
|
if ((dest - 1) != fullpath) {
|
|
dest--;
|
|
}
|
|
|
|
while ((dest > fullpath) && (*(dest - 1) != '/')) {
|
|
dest--;
|
|
}
|
|
|
|
if (*src == '/') {
|
|
src++;
|
|
}
|
|
}
|
|
|
|
*dest = '\0';
|
|
|
|
/* remove '/' in the end of path if exist */
|
|
|
|
dest--;
|
|
|
|
str_remove_path_end_slash(dest, fullpath);
|
|
return dest;
|
|
}
|
|
|
|
static int vfs_normalize_path_parame_check(const char *filename, char **pathname)
|
|
{
|
|
int namelen;
|
|
char *name = NULL;
|
|
|
|
if (pathname == NULL) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* check parameters */
|
|
|
|
if (filename == NULL) {
|
|
*pathname = NULL;
|
|
return -EINVAL;
|
|
}
|
|
|
|
namelen = vfs_strnlen(filename, PATH_MAX);
|
|
if (!namelen) {
|
|
*pathname = NULL;
|
|
return -EINVAL;
|
|
} else if (namelen >= PATH_MAX) {
|
|
*pathname = NULL;
|
|
return -ENAMETOOLONG;
|
|
}
|
|
|
|
for (name = (char *)filename + namelen; ((name != filename) && (*name != '/')); name--) {
|
|
if (strlen(name) > NAME_MAX) {
|
|
*pathname = NULL;
|
|
return -ENAMETOOLONG;
|
|
}
|
|
}
|
|
|
|
return namelen;
|
|
}
|
|
|
|
static char *vfs_not_absolute_path(const char *directory, const char *filename, char **pathname, int namelen)
|
|
{
|
|
int ret;
|
|
char *fullpath = NULL;
|
|
|
|
/* 2: The position of the path character: / and the end character /0 */
|
|
|
|
if ((namelen > 1) && (filename[0] == '.') && (filename[1] == '/')) {
|
|
filename += 2;
|
|
}
|
|
|
|
fullpath = (char *)malloc(strlen(directory) + namelen + 2);
|
|
if (fullpath == NULL) {
|
|
*pathname = NULL;
|
|
set_errno(ENOMEM);
|
|
return (char *)NULL;
|
|
}
|
|
|
|
/* join path and file name */
|
|
|
|
ret = snprintf_s(fullpath, strlen(directory) + namelen + 2, strlen(directory) + namelen + 1,
|
|
"%s/%s", directory, filename);
|
|
if (ret < 0) {
|
|
*pathname = NULL;
|
|
free(fullpath);
|
|
set_errno(ENAMETOOLONG);
|
|
return (char *)NULL;
|
|
}
|
|
|
|
return fullpath;
|
|
}
|
|
|
|
static char *vfs_normalize_fullpath(const char *directory, const char *filename, char **pathname, int namelen)
|
|
{
|
|
char *fullpath = NULL;
|
|
|
|
if (filename[0] != '/') {
|
|
/* not a absolute path */
|
|
|
|
fullpath = vfs_not_absolute_path(directory, filename, pathname, namelen);
|
|
if (fullpath == NULL) {
|
|
return (char *)NULL;
|
|
}
|
|
} else {
|
|
/* it's a absolute path, use it directly */
|
|
|
|
fullpath = strdup(filename); /* copy string */
|
|
|
|
if (fullpath == NULL) {
|
|
*pathname = NULL;
|
|
set_errno(ENOMEM);
|
|
return (char *)NULL;
|
|
}
|
|
if (filename[1] == '/') {
|
|
*pathname = NULL;
|
|
free(fullpath);
|
|
set_errno(EINVAL);
|
|
return (char *)NULL;
|
|
}
|
|
}
|
|
|
|
return fullpath;
|
|
}
|
|
|
|
int vfs_normalize_path(const char *directory, const char *filename, char **pathname)
|
|
{
|
|
char *fullpath = NULL;
|
|
int namelen;
|
|
#ifdef VFS_USING_WORKDIR
|
|
UINTPTR lock_flags;
|
|
LosProcessCB *curr = OsCurrProcessGet();
|
|
BOOL dir_flags = (directory == NULL) ? TRUE : FALSE;
|
|
#endif
|
|
|
|
namelen = vfs_normalize_path_parame_check(filename, pathname);
|
|
if (namelen < 0) {
|
|
return namelen;
|
|
}
|
|
|
|
#ifdef VFS_USING_WORKDIR
|
|
if (directory == NULL)
|
|
{
|
|
spin_lock_irqsave(&curr->files->workdir_lock, lock_flags);
|
|
directory = curr->files->workdir;
|
|
}
|
|
#else
|
|
if ((directory == NULL) && (filename[0] != '/')) {
|
|
PRINT_ERR("NO_WORKING_DIR\n");
|
|
*pathname = NULL;
|
|
return -EINVAL;
|
|
}
|
|
#endif
|
|
|
|
/* 2: The position of the path character: / and the end character /0 */
|
|
|
|
if ((filename[0] != '/') && (strlen(directory) + namelen + 2 > TEMP_PATH_MAX)) {
|
|
#ifdef VFS_USING_WORKDIR
|
|
if (dir_flags == TRUE)
|
|
{
|
|
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
|
|
}
|
|
#endif
|
|
return -ENAMETOOLONG;
|
|
}
|
|
|
|
fullpath = vfs_normalize_fullpath(directory, filename, pathname, namelen);
|
|
#ifdef VFS_USING_WORKDIR
|
|
if (dir_flags == TRUE)
|
|
{
|
|
spin_unlock_irqrestore(&curr->files->workdir_lock, lock_flags);
|
|
}
|
|
#endif
|
|
if (fullpath == NULL) {
|
|
return -get_errno();
|
|
}
|
|
|
|
(void)str_path(fullpath);
|
|
(void)str_normalize_path(fullpath);
|
|
if (strlen(fullpath) >= PATH_MAX) {
|
|
*pathname = NULL;
|
|
free(fullpath);
|
|
return -ENAMETOOLONG;
|
|
}
|
|
|
|
*pathname = fullpath;
|
|
return ENOERR;
|
|
}
|
|
|
|
int vfs_normalize_pathat(int dirfd, const char *filename, char **pathname)
|
|
{
|
|
/* Get path by dirfd*/
|
|
char *relativeoldpath = NULL;
|
|
char *fullpath = NULL;
|
|
int ret = 0;
|
|
|
|
ret = get_path_from_fd(dirfd, &relativeoldpath);
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
ret = vfs_normalize_path((const char *)relativeoldpath, filename, &fullpath);
|
|
if (relativeoldpath) {
|
|
free(relativeoldpath);
|
|
}
|
|
|
|
if (ret < 0) {
|
|
return ret;
|
|
}
|
|
|
|
*pathname = fullpath;
|
|
return ret;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
}
|
|
#endif /* __cplusplus */
|
|
#endif /* __cplusplus */
|