From 2a7e55b1fc91ccb11d39d45d088ed4ac4c2ed012 Mon Sep 17 00:00:00 2001
From: patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>
Date: Mon, 21 May 2007 21:04:03 +0000
Subject: [PATCH] Add FAT rename()

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@249 42af7a65-404d-4744-a932-0658087f49c3
---
 ChangeLog                   |   2 +-
 Documentation/NuttX.html    |   4 +-
 examples/mount/mount_main.c |  79 ++++++++++++++++++++++++-
 fs/fs_fat32.c               | 112 ++++++++++++++++++++++++++++++++++--
 4 files changed, 185 insertions(+), 12 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index eaf9de1285..1579ded46a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -142,6 +142,6 @@
 
 	* Added unlink(), mkdir(), rmdir(), and rename()
 	* Fixed several serious FAT errors with oflags handling (&& instead of &)
-	* Added FAT support for unlink(), mkdir() and rmdir()
+	* Added FAT support for unlink(), mkdir(), rmdir(), and rename
 	* Started m68322
 
diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html
index e16071e1ad..50ba2f76a8 100644
--- a/Documentation/NuttX.html
+++ b/Documentation/NuttX.html
@@ -8,7 +8,7 @@
   <tr align="center" bgcolor="#e4e4e4">
     <td>
       <h1><big><font color="#3c34ec"><i>NuttX RTOS</i></font></big></h1>
-      <p>Last Updated: May 19, 2007</p>
+      <p>Last Updated: May 21, 2007</p>
     </td>
   </tr>
 </table>
@@ -573,7 +573,7 @@ Other memory:
 
 	* Added unlink(), mkdir(), rmdir(), and rename()
 	* Fixed several serious FAT errors with oflags handling (&& instead of &)
-	* Added FAT support for unlink(), mkdir() and rmdir()
+	* Added FAT support for unlink(), mkdir(), rmdir(), and rename()
 	* Started m68322
 </pre></ul>
 
diff --git a/examples/mount/mount_main.c b/examples/mount/mount_main.c
index ef12c4bb57..0656951d7d 100644
--- a/examples/mount/mount_main.c
+++ b/examples/mount/mount_main.c
@@ -65,10 +65,13 @@ static const char g_target[]         = "/mnt/fs";
 static const char g_filesystemtype[] = "vfat";
 
 static const char g_testdir1[]       = "/mnt/fs/TestDir";
-static const char g_testdir2[]       = "/mnt/fs/NewDir";
+static const char g_testdir2[]       = "/mnt/fs/NewDir1";
+static const char g_testdir3[]       = "/mnt/fs/NewDir2";
+static const char g_testdir4[]       = "/mnt/fs/NewDir3";
 static const char g_testfile1[]      = "/mnt/fs/TestDir/TestFile.txt";
-static const char g_testfile2[]      = "/mnt/fs/TestDir/WritTest.txt";
-static const char g_testfile3[]      = "/mnt/fs/NewDir/WritTest.txt";
+static const char g_testfile2[]      = "/mnt/fs/TestDir/WrTest1.txt";
+static const char g_testfile3[]      = "/mnt/fs/NewDir1/WrTest2.txt";
+static const char g_testfile4[]      = "/mnt/fs/NewDir3/Renamed.txt";
 static const char g_testmsg[]        = "This is a write test";
 
 static int        g_nerrors          = 0;
@@ -315,6 +318,52 @@ static void succeed_unlink(const char *path)
     }
 }
 
+/****************************************************************************
+ * Name: fail_rename
+ ****************************************************************************/
+
+static void fail_rename(const char *oldpath, const char *newpath, int expectederror)
+{
+  int ret;
+
+  /* Try rename() against a file or directory.  It should fail with expectederror */
+
+  printf("fail_rename: Try rename(%s->%s)\n", oldpath, newpath);
+
+  ret = rename(oldpath, newpath);
+  if (ret == 0)
+    {
+      printf("fail_rename: ERROR rename(%s->%s) succeeded\n",
+             oldpath, newpath);
+      g_nerrors++;
+    }
+  else if (*get_errno_ptr() != expectederror)
+    {
+      printf("fail_rename: ERROR rename(%s->%s) failed with errno=%d (expected %d)\n",
+             oldpath, newpath, *get_errno_ptr(), expectederror);
+      g_nerrors++;
+    }
+}
+
+/****************************************************************************
+ * Name: succeed_rename
+ ****************************************************************************/
+
+static void succeed_rename(const char *oldpath, const char *newpath)
+{
+  int ret;
+
+  printf("succeed_rename: Try rename(%s->%s)\n", oldpath, newpath);
+
+  ret = rename(oldpath, newpath);
+  if (ret != 0)
+    {
+      printf("succeed_rename: ERROR rename(%s->%s) failed with errno=%d\n",
+             oldpath, newpath, *get_errno_ptr());
+      g_nerrors++;
+    }
+}
+
 /****************************************************************************
  * Public Functions
  ****************************************************************************/
@@ -413,6 +462,30 @@ int user_start(int argc, char *argv[])
 
       read_test_file(g_testfile3);
 
+      /* Use mkdir() to create test dir3.  It should succeed */
+
+      succeed_mkdir(g_testdir3);
+
+      /* Try rename() on the root directory. Should fail with EXDEV*/
+
+      fail_rename(g_target, g_testdir4, EXDEV);
+
+      /* Try rename() to an existing directory.  Should fail with EEXIST */
+
+      fail_rename(g_testdir2, g_testdir3, EEXIST);
+
+      /* Try rename() to a non-existing directory.  Should succeed */
+
+      succeed_rename(g_testdir3, g_testdir4);
+
+      /* Try rename() of file.  Should work. */
+
+      succeed_rename(g_testfile3, g_testfile4);
+
+      /* Make sure that we can still read the renamed file */
+
+      read_test_file(g_testfile4);
+
       /* Unmount the file system */
 
       printf("user_start: Try unmount(%s)\n", g_target);
diff --git a/fs/fs_fat32.c b/fs/fs_fat32.c
index 1307520b28..3f29741098 100644
--- a/fs/fs_fat32.c
+++ b/fs/fs_fat32.c
@@ -90,8 +90,8 @@ static int     fat_unlink(struct inode *mountpt, const char *relpath);
 static int     fat_mkdir(struct inode *mountpt, const char *relpath,
                          mode_t mode);
 static int     fat_rmdir(struct inode *mountpt, const char *relpath);
-static int     fat_rename(struct inode *mountpt, const char *old_relpath,
-                          const char *new_relpath);
+static int     fat_rename(struct inode *mountpt, const char *oldrelpath,
+                          const char *newrelpath);
 
 /****************************************************************************
  * Private Variables
@@ -1615,10 +1615,15 @@ int fat_rmdir(struct inode *mountpt, const char *relpath)
  *
  ****************************************************************************/
 
-int fat_rename(struct inode *mountpt, const char *old_relpath,
-               const char *new_relpath)
+int fat_rename(struct inode *mountpt, const char *oldrelpath,
+               const char *newrelpath)
 {
   struct fat_mountpt_s *fs;
+  struct fat_dirinfo_s  dirinfo;
+  size_t                oldsector;
+  ubyte                *olddirentry;
+  ubyte                *newdirentry;
+  ubyte                 dirstate[32-11];
   int                   ret;
 
   /* Sanity checks */
@@ -1638,8 +1643,103 @@ int fat_rename(struct inode *mountpt, const char *old_relpath,
       goto errout_with_semaphore;
     }
 
-#warning "fat_rename is not implemented"
-  ret = -ENOSYS;
+  /* Find the directory entry for the oldrelpath */
+
+  ret = fat_finddirentry(fs, &dirinfo, oldrelpath);
+  if (ret != OK)
+    {
+      /* Some error occurred -- probably -ENOENT */
+
+      goto errout_with_semaphore;
+    }
+
+  /* Save the information that will need to recover the
+   * directory sector and directory entry offset to the
+   * old directory.
+   */
+
+  olddirentry = dirinfo.fd_entry;
+
+  /* One more check:  Make sure that the oldrelpath does
+   * not refer to the root directory.  We can't rename the
+   * root directory.
+   */
+
+  if (!olddirentry)
+    {
+      ret = -EXDEV;
+      goto errout_with_semaphore;
+    }
+
+  oldsector   = fs->fs_currentsector;
+  memcpy(dirstate, &olddirentry[DIR_ATTRIBUTES], 32-11);
+
+  /* No find the directory where we should create the newpath object */
+
+  ret = fat_finddirentry(fs, &dirinfo, newrelpath);
+  if (ret == OK)
+    {
+      /* It is an error if the object at newrelpath already exists */
+
+      ret = -EEXIST;
+      goto errout_with_semaphore;
+    }
+
+  /* What we expect is -ENOENT mean that the full directory path was
+   * followed but that the object does not exists in the terminal directory.
+   */
+
+  if (ret != -ENOENT)
+    {
+      goto errout_with_semaphore;
+    }
+
+  /* Reserve a directory entry */
+
+  ret = fat_allocatedirentry(fs, &dirinfo);
+  if (ret != OK)
+    {
+      goto errout_with_semaphore;
+    }
+
+  /* Create the new directory entry */
+
+  newdirentry = dirinfo.fd_entry;
+
+  memcpy(&newdirentry[DIR_ATTRIBUTES], dirstate, 32-11);
+  memcpy(&newdirentry[DIR_NAME], dirinfo.fd_name, 8+3);
+#ifdef CONFIG_FLAT_LCNAMES
+  DIR_PUTNTRES(newdirentry, dirinfo.fd_ntflags);
+#else
+  DIR_PUTNTRES(newdirentry, 0);
+#endif
+  fs->fs_dirty = TRUE;
+
+  /* Now flush the new directory entry to disk and read the sector
+   * containing the old directory entry.
+   */
+
+  ret = fat_fscacheread(fs, oldsector);
+  if (ret < 0)
+    {
+      goto errout_with_semaphore;
+    }
+
+  /* Remove the old entry */
+
+  olddirentry[DIR_NAME] = DIR0_EMPTY;
+  fs->fs_dirty = TRUE;
+
+  /* Write the old entry to disk and update FSINFO if necessary */
+
+  ret = fat_updatefsinfo(fs);
+  if (ret < 0)
+    {
+      goto errout_with_semaphore;
+    }
+
+  fat_semgive(fs);
+  return OK;
 
  errout_with_semaphore:
   fat_semgive(fs);
-- 
GitLab