• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /****************************************************************************
2  * fs/vfs/fs_rename.c
3  *
4  *   Copyright (C) 2007-2009, 2014, 2017 Gregory Nutt. All rights reserved.
5  *   Author: Gregory Nutt <gnutt@nuttx.org>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name NuttX nor the names of its contributors may be
18  *    used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
28  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32  * POSSIBILITY OF SUCH DAMAGE.
33  *
34  ****************************************************************************/
35 
36 /****************************************************************************
37  * Included Files
38  ****************************************************************************/
39 
40 #include "vfs_config.h"
41 
42 #include "stdio.h"
43 #include "unistd.h"
44 #include "errno.h"
45 #include "stdlib.h"
46 #include "vnode.h"
47 #include "limits.h"
48 #include "fs/fs_operation.h"
49 #include "path_cache.h"
50 /****************************************************************************
51  * Public Functions
52  ****************************************************************************/
check_rename_target(struct Vnode * old_vnode,struct Vnode * old_parent_vnode,struct Vnode * new_vnode,struct Vnode * new_parent_vnode)53 static int check_rename_target(struct Vnode *old_vnode, struct Vnode *old_parent_vnode,
54     struct Vnode *new_vnode, struct Vnode *new_parent_vnode)
55 {
56   if (old_vnode == NULL || old_parent_vnode == NULL ||
57       new_parent_vnode == NULL || new_parent_vnode->type != VNODE_TYPE_DIR)
58     {
59       return -ENOENT;
60     }
61   if ((new_parent_vnode->originMount) && (new_parent_vnode->originMount->mountFlags & MS_RDONLY))
62     {
63       return -EROFS;
64     }
65   if (old_vnode->type != VNODE_TYPE_DIR && old_vnode->type != VNODE_TYPE_REG)
66     {
67       return -EACCES;
68     }
69   if (new_vnode != NULL && new_vnode->type != old_vnode->type)
70     {
71       if (new_vnode->type == VNODE_TYPE_DIR)
72         {
73           return -EISDIR;
74         }
75       return -ENOTDIR;
76     }
77   if (new_vnode != NULL && new_vnode->useCount != 0)
78     {
79       return -EBUSY;
80     }
81 
82   if (VfsVnodePermissionCheck(old_parent_vnode, (WRITE_OP | EXEC_OP))
83       || VfsVnodePermissionCheck(new_parent_vnode, (WRITE_OP | EXEC_OP)))
84     {
85       return -EACCES;
86     }
87 
88   if (old_parent_vnode->originMount != new_parent_vnode->originMount)
89     {
90       return -EXDEV;
91     }
92   if ((old_vnode->flag & VNODE_FLAG_MOUNT_ORIGIN)
93        || (old_vnode->flag & VNODE_FLAG_MOUNT_NEW))
94     {
95       return -EBUSY;
96     }
97   if (new_vnode != NULL && ((new_vnode->flag & VNODE_FLAG_MOUNT_ORIGIN)
98       || (new_vnode->flag & VNODE_FLAG_MOUNT_NEW)))
99     {
100       return -EBUSY;
101     }
102 
103   return OK;
104 }
105 
check_path_invalid(const char * fulloldpath,const char * fullnewpath)106 static int check_path_invalid(const char *fulloldpath, const char *fullnewpath)
107 {
108   char cwd[PATH_MAX];
109   char *pret = getcwd(cwd, PATH_MAX);
110   ssize_t len = strlen(fulloldpath);
111   if (pret != NULL)
112     {
113       if (!strcmp(fulloldpath, cwd))
114         {
115           return -EBUSY;
116         }
117     }
118 
119   if (strncmp(fulloldpath, fullnewpath, len))
120     {
121       return OK;
122     }
123 
124   if (fullnewpath[len] != '/')
125     {
126       return OK;
127     }
128 
129   return -EINVAL;
130 }
131 
do_rename(int oldfd,const char * oldpath,int newfd,const char * newpath)132 int do_rename(int oldfd, const char *oldpath, int newfd, const char *newpath)
133 {
134   struct Vnode *old_parent_vnode = NULL;
135   struct Vnode *new_parent_vnode = NULL;
136   struct Vnode *old_vnode = NULL;
137   struct Vnode *new_vnode = NULL;
138   char *fulloldpath = NULL;
139   char *fullnewpath = NULL;
140   char *oldname = NULL;
141   char *newname = NULL;
142   int ret;
143   if (!oldpath || *oldpath == '\0' || !newpath || *newpath == '\0')
144     {
145       ret = -EINVAL;
146       goto errout;
147     }
148 
149   ret = vfs_normalize_pathat(oldfd, oldpath, &fulloldpath);
150   if (ret < 0)
151     {
152       goto errout;
153     }
154 
155   ret = vfs_normalize_pathat(newfd, newpath, &fullnewpath);
156   if (ret < 0)
157     {
158       goto errout_with_oldpath;
159     }
160   oldname = strrchr(fulloldpath, '/') + 1;
161   newname = strrchr(fullnewpath, '/') + 1;
162   ret = check_path_invalid(fulloldpath, fullnewpath);
163   if (ret != OK)
164     {
165       goto errout_with_newpath;
166     }
167 
168   VnodeHold();
169   ret = VnodeLookup(fulloldpath, &old_vnode, 0);
170   if (ret < 0)
171     {
172       goto errout_with_vnode;
173     }
174   old_parent_vnode = old_vnode->parent;
175   ret = VnodeLookup(fullnewpath, &new_vnode, 0);
176   if (ret == OK)
177     {
178       new_parent_vnode = new_vnode->parent;
179     }
180   else
181     {
182       new_parent_vnode = new_vnode;
183       new_vnode = NULL;
184     }
185   ret = check_rename_target(old_vnode, old_parent_vnode, new_vnode, new_parent_vnode);
186   if (ret != OK)
187     {
188       goto errout_with_vnode;
189     }
190   if (old_vnode == new_vnode)
191     {
192       VnodeDrop();
193       free(fulloldpath);
194       free(fullnewpath);
195       return OK;
196     }
197   if (!old_vnode->vop || !old_vnode->vop->Rename)
198     {
199       ret = -ENOSYS;
200       goto errout_with_vnode;
201     }
202   new_parent_vnode->useCount++;
203   ret = old_vnode->vop->Rename(old_vnode, new_parent_vnode, oldname, newname);
204   new_parent_vnode->useCount--;
205   if (ret < 0)
206     {
207       goto errout_with_vnode;
208     }
209   VnodeFree(new_vnode);
210   VnodePathCacheFree(old_vnode);
211   old_vnode->filePath = strdup(fullnewpath);
212   PathCacheAlloc(new_parent_vnode, old_vnode, newname, strlen(newname));
213   old_vnode->parent = new_parent_vnode;
214   VnodeDrop();
215 
216   free(fulloldpath);
217   free(fullnewpath);
218 
219   return OK;
220 
221 errout_with_vnode:
222   VnodeDrop();
223 errout_with_newpath:
224   free(fullnewpath);
225 errout_with_oldpath:
226   free(fulloldpath);
227 errout:
228   set_errno(-ret);
229   return VFS_ERROR;
230 }
231 
232 
233 /****************************************************************************
234  * Name: rename
235  *
236  * Description:  Rename a file managed a mountpoint
237  *
238  ****************************************************************************/
239 
rename(const char * oldpath,const char * newpath)240 int rename(const char *oldpath, const char *newpath)
241 {
242   return do_rename(AT_FDCWD, oldpath, AT_FDCWD, newpath);
243 }
244 
245 /****************************************************************************
246  * Name: renameat
247  *
248  * Description:  Rename a file managed a mountpoint with relatively fds.
249  *
250  ****************************************************************************/
251 
renameat(int oldfd,const char * oldpath,int newdfd,const char * newpath)252 int renameat(int oldfd, const char *oldpath, int newdfd, const char *newpath)
253 {
254   return do_rename(oldfd, oldpath, newdfd, newpath);
255 }
256