1 /****************************************************************************
2 * fs/vfs/fs_rename.c
3 *
4 * Licensed to the Apache Software Foundation (ASF) under one or more
5 * contributor license agreements. See the NOTICE file distributed with
6 * this work for additional information regarding copyright ownership. The
7 * ASF licenses this file to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance with the
9 * License. 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, WITHOUT
15 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16 * License for the specific language governing permissions and limitations
17 * 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 ****************************************************************************/
check_rename_target(struct Vnode * old_vnode,struct Vnode * old_parent_vnode,struct Vnode * new_vnode,struct Vnode * new_parent_vnode)38 static 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
check_path_invalid(const char * fulloldpath,const char * fullnewpath)91 static 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
do_rename(int oldfd,const char * oldpath,int newfd,const char * newpath)117 int 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
206 errout_with_vnode:
207 VnodeDrop();
208 errout_with_newpath:
209 free(fullnewpath);
210 errout_with_oldpath:
211 free(fulloldpath);
212 errout:
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
rename(const char * oldpath,const char * newpath)225 int 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
renameat(int oldfd,const char * oldpath,int newdfd,const char * newpath)237 int renameat(int oldfd, const char *oldpath, int newdfd, const char *newpath)
238 {
239 return do_rename(oldfd, oldpath, newdfd, newpath);
240 }
241