mirror of
https://github.com/apache/nuttx.git
synced 2026-09-04 16:13:00 +00:00
fs/vfs/rename: rename a directory to an empty directory
resolve rename{7}:
On a call to rename(old, new), when the old argument points to the pathname of a directory, if the directory named by the new argument exists and is empty it shall be removed and old renamed to new.
resolve rename{23}:
EEXIST or ENOTEMPTY in errno and a return value of -1 on a call to rename(old, new) when the link named by new is a directory containing
entries other than dot and dot-dot. The named files are not changed.
Signed-off-by: zhengyu16 <zhengyu16@xiaomi.com>
This commit is contained in:
parent
52dac57f76
commit
b1bfa70b24
1 changed files with 36 additions and 55 deletions
|
|
@ -294,10 +294,8 @@ static int mountptrename(FAR const char *oldpath, FAR struct inode *oldinode,
|
|||
FAR struct inode *newinode;
|
||||
FAR const char *newrelpath;
|
||||
FAR char *subdir = NULL;
|
||||
#ifdef CONFIG_FS_NOTIFY
|
||||
bool newisdir = false;
|
||||
bool oldisdir = false;
|
||||
#endif
|
||||
int ret;
|
||||
|
||||
DEBUGASSERT(oldinode->u.i_mops);
|
||||
|
|
@ -314,7 +312,7 @@ static int mountptrename(FAR const char *oldpath, FAR struct inode *oldinode,
|
|||
}
|
||||
|
||||
/* Get an inode for the new relpath -- it should lie on the same
|
||||
* mountpoint. Path search on oldinode was already enforced by rename().
|
||||
* mountpoint
|
||||
*/
|
||||
|
||||
SETUP_SEARCH(&newdesc, newpath, true);
|
||||
|
|
@ -356,73 +354,68 @@ static int mountptrename(FAR const char *oldpath, FAR struct inode *oldinode,
|
|||
* If the directory entry at the newrelpath is a regular file, then that
|
||||
* file should be removed first.
|
||||
*
|
||||
* If the directory entry at the target is a directory, then the source
|
||||
* file should be moved "under" the directory, i.e., if newrelpath is a
|
||||
* directory, then rename(b,a) should use move the oldrelpath should be
|
||||
* moved as if rename(b,a/basename(b)) had been called.
|
||||
* If the directory entry at the newrelpath is an empty directory, then it
|
||||
* can be removed without issue.
|
||||
*
|
||||
* If the directory entry at the newrelpath is a non-empty directory,
|
||||
* then the rename should fail with the error ENOTEMPTY.
|
||||
*/
|
||||
|
||||
if (oldinode->u.i_mops->stat != NULL)
|
||||
{
|
||||
struct stat buf;
|
||||
struct stat oldbuf;
|
||||
struct stat newbuf;
|
||||
|
||||
ret = oldinode->u.i_mops->stat(oldinode, newrelpath, &buf);
|
||||
ret = oldinode->u.i_mops->stat(oldinode, oldrelpath, &oldbuf);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_newinode;
|
||||
}
|
||||
|
||||
oldisdir = S_ISDIR(oldbuf.st_mode);
|
||||
|
||||
ret = oldinode->u.i_mops->stat(oldinode, newrelpath, &newbuf);
|
||||
if (ret >= 0)
|
||||
{
|
||||
/* Is the directory entry a directory? */
|
||||
newisdir = S_ISDIR(newbuf.st_mode);
|
||||
|
||||
/* Is the new path a directory? */
|
||||
|
||||
#ifdef CONFIG_FS_NOTIFY
|
||||
newisdir = S_ISDIR(buf.st_mode);
|
||||
if (newisdir)
|
||||
#else
|
||||
if (S_ISDIR(buf.st_mode))
|
||||
#endif
|
||||
{
|
||||
FAR char *subdirname;
|
||||
/* It is an error to rename a file to a directory */
|
||||
|
||||
/* Yes.. In this case, the target of the rename must be a
|
||||
* subdirectory of newinode, not the newinode itself. For
|
||||
* example: mv b a/ must move b to a/b.
|
||||
if (!oldisdir)
|
||||
{
|
||||
ret = -EISDIR;
|
||||
goto errout_with_newinode;
|
||||
}
|
||||
|
||||
/* Remove the newrelpath which already exists.
|
||||
* rmdir will handle the error cases.
|
||||
*/
|
||||
|
||||
subdirname = basename((FAR char *)oldrelpath);
|
||||
|
||||
/* Special case the root directory */
|
||||
|
||||
if (*newrelpath == '\0')
|
||||
if (oldinode->u.i_mops->rmdir)
|
||||
{
|
||||
newrelpath = subdirname;
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = fs_heap_asprintf(&subdir, "%s/%s", newrelpath,
|
||||
subdirname);
|
||||
ret = oldinode->u.i_mops->rmdir(oldinode, newrelpath);
|
||||
if (ret < 0)
|
||||
{
|
||||
subdir = NULL;
|
||||
ret = -ENOMEM;
|
||||
goto errout_with_newinode;
|
||||
}
|
||||
|
||||
newrelpath = subdir;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No.. newrelpath must refer to a regular file. Make sure
|
||||
* that the file at the oldrelpath actually exists before
|
||||
* performing any further actions with newrelpath
|
||||
*/
|
||||
/* No.. newrelpath must refer to a regular file. */
|
||||
|
||||
ret = oldinode->u.i_mops->stat(oldinode, oldrelpath, &buf);
|
||||
if (ret < 0)
|
||||
if (oldisdir)
|
||||
{
|
||||
/* It is an error to rename a directory to a file */
|
||||
|
||||
ret = -ENOTDIR;
|
||||
goto errout_with_newinode;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_FS_NOTIFY
|
||||
oldisdir = S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
if (oldinode->u.i_mops->unlink)
|
||||
{
|
||||
/* Attempt to remove the file before doing the rename.
|
||||
|
|
@ -439,18 +432,6 @@ static int mountptrename(FAR const char *oldpath, FAR struct inode *oldinode,
|
|||
}
|
||||
}
|
||||
}
|
||||
#ifdef CONFIG_FS_NOTIFY
|
||||
else
|
||||
{
|
||||
ret = oldinode->u.i_mops->stat(oldinode, oldrelpath, &buf);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto errout_with_newinode;
|
||||
}
|
||||
|
||||
oldisdir = S_ISDIR(buf.st_mode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Perform the rename operation using the relative paths at the common
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue