• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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