1/**************************************************************************** 2 * fs/vfs/fs_rename.c 3 * 4 * Copyright (c) 2023 Huawei Device Co., Ltd. All rights reserved. 5 * Based on NuttX originally from nuttx source (nuttx/fs/ and nuttx/drivers/) 6 * 7 * Licensed under the Apache License, Version 2.0 (the "License"); 8 * you may not use this file except in compliance with the License. 9 * You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, software 14 * distributed under the License is distributed on an "AS IS" BASIS, 15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 * See the License for the specific language governing permissions and 17 * limitations under the License. 18 * 19 ****************************************************************************/ 20 21/**************************************************************************** 22 * Included Files 23 ****************************************************************************/ 24 25#include "vfs_config.h" 26 27#include "stdio.h" 28#include "unistd.h" 29#include "errno.h" 30#include "stdlib.h" 31#include "vnode.h" 32#include "limits.h" 33#include "fs/fs_operation.h" 34#include "path_cache.h" 35/**************************************************************************** 36 * Public Functions 37 ****************************************************************************/ 38static int check_rename_target(struct Vnode *old_vnode, struct Vnode *old_parent_vnode, 39 struct Vnode *new_vnode, struct Vnode *new_parent_vnode) 40{ 41 if (old_vnode == NULL || old_parent_vnode == NULL || 42 new_parent_vnode == NULL || new_parent_vnode->type != VNODE_TYPE_DIR) 43 { 44 return -ENOENT; 45 } 46 if ((new_parent_vnode->originMount) && (new_parent_vnode->originMount->mountFlags & MS_RDONLY)) 47 { 48 return -EROFS; 49 } 50 if (old_vnode->type != VNODE_TYPE_DIR && old_vnode->type != VNODE_TYPE_REG) 51 { 52 return -EACCES; 53 } 54 if (new_vnode != NULL && new_vnode->type != old_vnode->type) 55 { 56 if (new_vnode->type == VNODE_TYPE_DIR) 57 { 58 return -EISDIR; 59 } 60 return -ENOTDIR; 61 } 62 if (new_vnode != NULL && new_vnode->useCount != 0) 63 { 64 return -EBUSY; 65 } 66 67 if (VfsVnodePermissionCheck(old_parent_vnode, (WRITE_OP | EXEC_OP)) 68 || VfsVnodePermissionCheck(new_parent_vnode, (WRITE_OP | EXEC_OP))) 69 { 70 return -EACCES; 71 } 72 73 if (old_parent_vnode->originMount != new_parent_vnode->originMount) 74 { 75 return -EXDEV; 76 } 77 if ((old_vnode->flag & VNODE_FLAG_MOUNT_ORIGIN) 78 || (old_vnode->flag & VNODE_FLAG_MOUNT_NEW)) 79 { 80 return -EBUSY; 81 } 82 if (new_vnode != NULL && ((new_vnode->flag & VNODE_FLAG_MOUNT_ORIGIN) 83 || (new_vnode->flag & VNODE_FLAG_MOUNT_NEW))) 84 { 85 return -EBUSY; 86 } 87 88 return OK; 89} 90 91static int check_path_invalid(const char *fulloldpath, const char *fullnewpath) 92{ 93 char cwd[PATH_MAX]; 94 char *pret = getcwd(cwd, PATH_MAX); 95 ssize_t len = strlen(fulloldpath); 96 if (pret != NULL) 97 { 98 if (!strcmp(fulloldpath, cwd)) 99 { 100 return -EBUSY; 101 } 102 } 103 104 if (strncmp(fulloldpath, fullnewpath, len)) 105 { 106 return OK; 107 } 108 109 if (fullnewpath[len] != '/') 110 { 111 return OK; 112 } 113 114 return -EINVAL; 115} 116 117int do_rename(int oldfd, const char *oldpath, int newfd, const char *newpath) 118{ 119 struct Vnode *old_parent_vnode = NULL; 120 struct Vnode *new_parent_vnode = NULL; 121 struct Vnode *old_vnode = NULL; 122 struct Vnode *new_vnode = NULL; 123 char *fulloldpath = NULL; 124 char *fullnewpath = NULL; 125 char *oldname = NULL; 126 char *newname = NULL; 127 int ret; 128 if (!oldpath || *oldpath == '\0' || !newpath || *newpath == '\0') 129 { 130 ret = -EINVAL; 131 goto errout; 132 } 133 134 ret = vfs_normalize_pathat(oldfd, oldpath, &fulloldpath); 135 if (ret < 0) 136 { 137 goto errout; 138 } 139 140 ret = vfs_normalize_pathat(newfd, newpath, &fullnewpath); 141 if (ret < 0) 142 { 143 goto errout_with_oldpath; 144 } 145 oldname = strrchr(fulloldpath, '/') + 1; 146 newname = strrchr(fullnewpath, '/') + 1; 147 ret = check_path_invalid(fulloldpath, fullnewpath); 148 if (ret != OK) 149 { 150 goto errout_with_newpath; 151 } 152 153 VnodeHold(); 154 ret = VnodeLookup(fulloldpath, &old_vnode, 0); 155 if (ret < 0) 156 { 157 goto errout_with_vnode; 158 } 159 old_parent_vnode = old_vnode->parent; 160 ret = VnodeLookup(fullnewpath, &new_vnode, 0); 161 if (ret == OK) 162 { 163 new_parent_vnode = new_vnode->parent; 164 } 165 else 166 { 167 new_parent_vnode = new_vnode; 168 new_vnode = NULL; 169 } 170 ret = check_rename_target(old_vnode, old_parent_vnode, new_vnode, new_parent_vnode); 171 if (ret != OK) 172 { 173 goto errout_with_vnode; 174 } 175 if (old_vnode == new_vnode) 176 { 177 VnodeDrop(); 178 free(fulloldpath); 179 free(fullnewpath); 180 return OK; 181 } 182 if (!old_vnode->vop || !old_vnode->vop->Rename) 183 { 184 ret = -ENOSYS; 185 goto errout_with_vnode; 186 } 187 new_parent_vnode->useCount++; 188 ret = old_vnode->vop->Rename(old_vnode, new_parent_vnode, oldname, newname); 189 new_parent_vnode->useCount--; 190 if (ret < 0) 191 { 192 goto errout_with_vnode; 193 } 194 VnodeFree(new_vnode); 195 VnodePathCacheFree(old_vnode); 196 old_vnode->filePath = strdup(fullnewpath); 197 PathCacheAlloc(new_parent_vnode, old_vnode, newname, strlen(newname)); 198 old_vnode->parent = new_parent_vnode; 199 VnodeDrop(); 200 201 free(fulloldpath); 202 free(fullnewpath); 203 204 return OK; 205 206errout_with_vnode: 207 VnodeDrop(); 208errout_with_newpath: 209 free(fullnewpath); 210errout_with_oldpath: 211 free(fulloldpath); 212errout: 213 set_errno(-ret); 214 return VFS_ERROR; 215} 216 217 218/**************************************************************************** 219 * Name: rename 220 * 221 * Description: Rename a file managed a mountpoint 222 * 223 ****************************************************************************/ 224 225int rename(const char *oldpath, const char *newpath) 226{ 227 return do_rename(AT_FDCWD, oldpath, AT_FDCWD, newpath); 228} 229 230/**************************************************************************** 231 * Name: renameat 232 * 233 * Description: Rename a file managed a mountpoint with relatively fds. 234 * 235 ****************************************************************************/ 236 237int renameat(int oldfd, const char *oldpath, int newdfd, const char *newpath) 238{ 239 return do_rename(oldfd, oldpath, newdfd, newpath); 240} 241