This is an automated email from the ASF dual-hosted git repository.

xiaoxiang781216 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git

commit b1bfa70b24d707355f97b0f0cb4429c7a6d22e83
Author: zhengyu16 <[email protected]>
AuthorDate: Wed Sep 24 16:06:57 2025 +0800

    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 <[email protected]>
---
 fs/vfs/fs_rename.c | 91 +++++++++++++++++++++---------------------------------
 1 file changed, 36 insertions(+), 55 deletions(-)

diff --git a/fs/vfs/fs_rename.c b/fs/vfs/fs_rename.c
index 183fb6e5ae6..38ed865cabd 100644
--- a/fs/vfs/fs_rename.c
+++ b/fs/vfs/fs_rename.c
@@ -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);
-      if (ret >= 0)
+      ret = oldinode->u.i_mops->stat(oldinode, oldrelpath, &oldbuf);
+      if (ret < 0)
         {
-          /* Is the directory entry a directory? */
+          goto errout_with_newinode;
+        }
 
-#ifdef CONFIG_FS_NOTIFY
-          newisdir = S_ISDIR(buf.st_mode);
-          if (newisdir)
-#else
-          if (S_ISDIR(buf.st_mode))
-#endif
-            {
-              FAR char *subdirname;
+      oldisdir = S_ISDIR(oldbuf.st_mode);
 
-              /* 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.
-               */
+      ret = oldinode->u.i_mops->stat(oldinode, newrelpath, &newbuf);
+      if (ret >= 0)
+        {
+          newisdir = S_ISDIR(newbuf.st_mode);
 
-              subdirname = basename((FAR char *)oldrelpath);
+          /* Is the new path a directory? */
 
-              /* Special case the root directory */
+          if (newisdir)
+            {
+              /* It is an error to rename a file to a directory */
 
-              if (*newrelpath == '\0')
+              if (!oldisdir)
                 {
-                  newrelpath = subdirname;
+                  ret = -EISDIR;
+                  goto errout_with_newinode;
                 }
-              else
+
+              /* Remove the newrelpath which already exists.
+               * rmdir will handle the error cases.
+               */
+
+              if (oldinode->u.i_mops->rmdir)
                 {
-                  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

Reply via email to