提交 900bf4b3 编写于 作者: O openharmony_ci 提交者: Gitee

!45 新增link/symlink/readlink接口的系统调用及内核实现

Merge pull request !45 from JING/link
/*
* Copyright (c) 2021-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 "unistd.h"
#include "errno.h"
#include "fs/vnode.h"
int do_link(int oldfd, const char *oldpath, int newfd, const char *newpath, int flag)
{
struct Vnode *new_parent_vnode = NULL;
struct Vnode *new_vnode = NULL;
struct Vnode *old_vnode = NULL;
char *fulloldpath = NULL;
char *fullnewpath = NULL;
char *newname = NULL;
int ret;
if (!oldpath || !newpath)
{
ret = -EFAULT;
goto errout;
}
if (*oldpath == '\0' || *newpath == '\0' || flag & ~AT_SYMLINK_FOLLOW)
{
ret = -EINVAL;
goto errout;
}
ret = vfs_normalize_pathat(newfd, newpath, &fullnewpath);
if (ret < 0)
{
goto errout;
}
if (!(flag & AT_SYMLINK_FOLLOW))
{
ret = vfs_normalize_pathat(oldfd, oldpath, &fulloldpath);
if (ret < 0)
{
goto errout_with_newpath;
}
}
newname = strrchr(fullnewpath, '/') + 1;
VnodeHold();
if (flag & AT_SYMLINK_FOLLOW)
{
ret = follow_symlink(oldfd, oldpath, &old_vnode, &fulloldpath);
if (ret < 0)
{
goto errout_with_vnode;
}
}
else
{
ret = VnodeLookup(fulloldpath, &old_vnode, 0);
if (ret < 0)
{
goto errout_with_vnode;
}
}
if (old_vnode->type != VNODE_TYPE_REG && old_vnode->type != VNODE_TYPE_LNK)
{
ret = -EPERM;
goto errout_with_vnode;
}
ret = VnodeLookup(fullnewpath, &new_parent_vnode, 0);
if (ret == OK)
{
ret = -EEXIST;
goto errout_with_vnode;
}
if (old_vnode->originMount != new_parent_vnode->originMount)
{
ret = -EXDEV;
goto errout_with_vnode;
}
if (!old_vnode->vop || !old_vnode->vop->Link)
{
ret = -ENOSYS;
goto errout_with_vnode;
}
new_parent_vnode->useCount++;
ret = old_vnode->vop->Link(old_vnode, new_parent_vnode, &new_vnode, newname);
new_parent_vnode->useCount--;
if (ret < 0)
{
goto errout_with_vnode;
}
PathCacheAlloc(new_parent_vnode, new_vnode, newname, strlen(newname));
VnodeDrop();
free(fulloldpath);
free(fullnewpath);
return OK;
errout_with_vnode:
VnodeDrop();
free(fulloldpath);
errout_with_newpath:
free(fullnewpath);
errout:
set_errno(-ret);
return VFS_ERROR;
}
int link(const char *oldpath, const char *newpath)
{
return do_link(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
}
int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags)
{
return do_link(olddirfd, oldpath, newdirfd, newpath, flags);
}
\ No newline at end of file
......@@ -158,7 +158,7 @@ static int do_creat(struct Vnode *parentNode, char *fullpath, mode_t mode, struc
return OK;
}
int fp_open(char *fullpath, int oflags, mode_t mode)
int fp_open(int dirfd, const char *path, int oflags, mode_t mode)
{
int ret;
int fd;
......@@ -166,9 +166,10 @@ int fp_open(char *fullpath, int oflags, mode_t mode)
struct file *filep = NULL;
struct Vnode *vnode = NULL;
struct Vnode *parentVnode = NULL;
char *fullpath = NULL;
VnodeHold();
ret = VnodeLookup(fullpath, &vnode, 0);
ret = follow_symlink(dirfd, path, &vnode, &fullpath);
if (ret == OK)
{
/* if file exist */
......@@ -305,6 +306,10 @@ errout_with_count:
vnode->useCount--;
VnodeDrop();
errout:
if (fullpath)
{
free(fullpath);
}
set_errno(-ret);
return VFS_ERROR;
}
......@@ -313,25 +318,6 @@ int do_open(int dirfd, const char *path, int oflags, mode_t mode)
{
int ret;
int fd;
char *fullpath = NULL;
char *relativepath = NULL;
/* Get relative path by dirfd*/
ret = get_path_from_fd(dirfd, &relativepath);
if (ret < 0)
{
goto errout;
}
ret = vfs_normalize_path((const char *)relativepath, path, &fullpath);
if (relativepath)
{
free(relativepath);
}
if (ret < 0)
{
goto errout;
}
if ((oflags & (O_WRONLY | O_CREAT)) != 0)
{
......@@ -339,7 +325,7 @@ int do_open(int dirfd, const char *path, int oflags, mode_t mode)
mode &= (S_IRWXU | S_IRWXG | S_IRWXO);
}
fd = fp_open(fullpath, oflags, mode);
fd = fp_open(dirfd, path, oflags, mode);
if (fd < 0)
{
ret = -get_errno();
......@@ -349,10 +335,6 @@ int do_open(int dirfd, const char *path, int oflags, mode_t mode)
return fd;
errout:
if (fullpath)
{
free(fullpath);
}
set_errno(-ret);
return VFS_ERROR;
}
......
/*
* Copyright (c) 2021-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 "unistd.h"
#include "errno.h"
#include "fs/vnode.h"
ssize_t do_readlink(int dirfd, const char *path, char *buf, size_t bufsize)
{
struct Vnode *vnode = NULL;
char *fullpath = NULL;
ssize_t ret;
if (!path)
{
ret = -EFAULT;
goto errout;
}
if (*path == '\0')
{
ret = -EINVAL;
goto errout;
}
ret = vfs_normalize_pathat(dirfd, path, &fullpath);
if (ret < 0)
{
goto errout;
}
VnodeHold();
ret = VnodeLookup(fullpath, &vnode, 0);
if (ret < 0)
{
goto errout_with_vnode;
}
if (vnode->type != VNODE_TYPE_LNK)
{
ret = -EINVAL;
goto errout_with_vnode;
}
if (!vnode->vop || !vnode->vop->Readlink)
{
ret = -ENOSYS;
goto errout_with_vnode;
}
ret = vnode->vop->Readlink(vnode, buf, bufsize);
if (ret < 0)
{
goto errout_with_vnode;
}
VnodeDrop();
free(fullpath);
return ret;
errout_with_vnode:
VnodeDrop();
free(fullpath);
errout:
set_errno(-ret);
return VFS_ERROR;
}
ssize_t readlink(const char *pathname, char *buf, size_t bufsize)
{
return do_readlink(AT_FDCWD, pathname, buf, bufsize);
}
ssize_t readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsize)
{
return do_readlink(dirfd, pathname, buf, bufsize);
}
/*
* Copyright (c) 2021-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 "unistd.h"
#include "errno.h"
#include "fs/vnode.h"
int follow_symlink(int dirfd, const char *path, struct Vnode **vnode, char **fullpath)
{
int ret;
struct Vnode *newvnode = NULL;
char pathname[PATH_MAX] = {0};
(void)strcpy_s(pathname, PATH_MAX, path);
for (int i = 0; i < CONFIG_FS_MAX_LNK_CNT; i++)
{
if (*fullpath)
{
free(*fullpath);
*fullpath = NULL;
}
ret = vfs_normalize_pathat(dirfd, pathname, fullpath);
if (ret < 0)
{
return ret;
}
ret = VnodeLookup(*fullpath, &newvnode, 0);
if (ret != OK)
{
/* The object of fullpath is not exist. Return its parent's vnode. */
*vnode = newvnode;
return ret;
}
if (newvnode->type != VNODE_TYPE_LNK)
{
/* The object of fullpath is exist, and is not a symbol link. Return its vnode. */
*vnode = newvnode;
return ret;
}
if (newvnode->vop->Readlink == NULL)
{
ret = -ENOSYS;
return ret;
}
/* The object of fullpath is a symbol link. Read its target and find the source file successively. */
(void)memset_s(pathname, PATH_MAX, 0, PATH_MAX);
ret = newvnode->vop->Readlink(newvnode, pathname, PATH_MAX);
if (ret < 0)
{
return ret;
}
}
/* Failed to find the source file in CONFIG_FS_MAX_LNK_CNT times. */
return -ELOOP;
}
int do_symlink(const char *target, int newfd, const char *path)
{
struct Vnode *parent_vnode = NULL;
struct Vnode *new_vnode = NULL;
char *fullpath = NULL;
char *newname = NULL;
int ret;
if (!path)
{
ret = -EFAULT;
goto errout;
}
if (*path == '\0')
{
ret = -EINVAL;
goto errout;
}
if (strlen(target) >= PATH_MAX)
{
ret = -ENAMETOOLONG;
goto errout;
}
ret = vfs_normalize_pathat(newfd, path, &fullpath);
if (ret < 0)
{
goto errout;
}
newname = strrchr(fullpath, '/') + 1;
VnodeHold();
ret = VnodeLookup(fullpath, &parent_vnode, 0);
if (ret == 0)
{
ret = -EEXIST;
goto errout_with_vnode;
}
if (!parent_vnode->vop || !parent_vnode->vop->Symlink)
{
ret = -ENOSYS;
goto errout_with_vnode;
}
parent_vnode->useCount++;
ret = parent_vnode->vop->Symlink(parent_vnode, &new_vnode, (const char *)newname, (const char *)target);
parent_vnode->useCount--;
if (ret < 0)
{
goto errout_with_vnode;
}
PathCacheAlloc(parent_vnode, new_vnode, newname, strlen(newname));
VnodeDrop();
free(fullpath);
return OK;
errout_with_vnode:
VnodeDrop();
free(fullpath);
errout:
set_errno(-ret);
return VFS_ERROR;
}
int symlink(const char *target, const char *path)
{
return do_symlink(target, AT_FDCWD, path);
}
int symlinkat(const char *target, int newdirfd, const char *path)
{
return do_symlink(target, newdirfd, path);
}
......@@ -1110,6 +1110,7 @@ void weak_function files_initialize(void);
int vfs_normalize_path(const char *directory, const char *filename, char **pathname);
int vfs_normalize_pathat(int fd, const char *filename, char **pathname);
int follow_symlink(int dirfd, const char *path, struct Vnode **vnode, char **fullpath);
#ifdef __cplusplus
#if __cplusplus
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册