1/* 2 * Copyright (c) 2021-2021 Huawei Device Co., Ltd. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, 5 * are permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used 15 * to endorse or promote products derived from this software without specific prior written 16 * permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "unistd.h" 32#include "errno.h" 33#include "vnode.h" 34#include "path_cache.h" 35 36int do_link(int oldfd, const char *oldpath, int newfd, const char *newpath, int flag) 37{ 38 struct Vnode *new_parent_vnode = NULL; 39 struct Vnode *new_vnode = NULL; 40 struct Vnode *old_vnode = NULL; 41 struct Mount *mount = NULL; 42 char *fulloldpath = NULL; 43 char *fullnewpath = NULL; 44 char *newname = NULL; 45 int ret; 46 47 if (!oldpath || !newpath) 48 { 49 ret = -EFAULT; 50 goto errout; 51 } 52 53 if (*oldpath == '\0' || *newpath == '\0' || flag & ~AT_SYMLINK_FOLLOW) 54 { 55 ret = -EINVAL; 56 goto errout; 57 } 58 59 ret = vfs_normalize_pathat(newfd, newpath, &fullnewpath); 60 if (ret < 0) 61 { 62 goto errout; 63 } 64 65 if (!(flag & AT_SYMLINK_FOLLOW)) 66 { 67 ret = vfs_normalize_pathat(oldfd, oldpath, &fulloldpath); 68 if (ret < 0) 69 { 70 goto errout_with_newpath; 71 } 72 } 73 74 newname = strrchr(fullnewpath, '/') + 1; 75 76 VnodeHold(); 77 78 if (flag & AT_SYMLINK_FOLLOW) 79 { 80 ret = follow_symlink(oldfd, oldpath, &old_vnode, &fulloldpath); 81 if (ret < 0) 82 { 83 goto errout_with_vnode; 84 } 85 } 86 else 87 { 88 ret = VnodeLookup(fulloldpath, &old_vnode, 0); 89 if (ret < 0) 90 { 91 goto errout_with_vnode; 92 } 93 } 94 95 mount = old_vnode->originMount; 96 if ((mount != NULL) && (mount->mountFlags & MS_RDONLY)) 97 { 98 ret = -EROFS; 99 goto errout_with_vnode; 100 } 101 102 if (old_vnode->type != VNODE_TYPE_REG && old_vnode->type != VNODE_TYPE_LNK) 103 { 104 ret = -EPERM; 105 goto errout_with_vnode; 106 } 107 108 ret = VnodeLookup(fullnewpath, &new_parent_vnode, 0); 109 if (ret == OK) 110 { 111 ret = -EEXIST; 112 goto errout_with_vnode; 113 } 114 115 if (old_vnode->originMount != new_parent_vnode->originMount) 116 { 117 ret = -EXDEV; 118 goto errout_with_vnode; 119 } 120 121 if (!old_vnode->vop || !old_vnode->vop->Link) 122 { 123 ret = -ENOSYS; 124 goto errout_with_vnode; 125 } 126 new_parent_vnode->useCount++; 127 ret = old_vnode->vop->Link(old_vnode, new_parent_vnode, &new_vnode, newname); 128 new_parent_vnode->useCount--; 129 if (ret < 0) 130 { 131 goto errout_with_vnode; 132 } 133 PathCacheAlloc(new_parent_vnode, new_vnode, newname, strlen(newname)); 134 VnodeDrop(); 135 136 free(fulloldpath); 137 free(fullnewpath); 138 139 return OK; 140 141errout_with_vnode: 142 VnodeDrop(); 143 free(fulloldpath); 144errout_with_newpath: 145 free(fullnewpath); 146errout: 147 set_errno(-ret); 148 return VFS_ERROR; 149} 150 151int link(const char *oldpath, const char *newpath) 152{ 153 return do_link(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0); 154} 155 156int linkat(int olddirfd, const char *oldpath, int newdirfd, const char *newpath, int flags) 157{ 158 return do_link(olddirfd, oldpath, newdirfd, newpath, flags); 159} 160