You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2024/02/26 06:00:04 UTC

(nuttx-apps) 01/02: cp:support -r recursive copies

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

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

commit e8470f7d0e8fa1b10d3434c50d768f26c4d8379d
Author: chenrun1 <ch...@xiaomi.com>
AuthorDate: Tue Jan 16 20:42:08 2024 +0800

    cp:support -r recursive copies
    
    The cp command supports recursive copying. Use "cp -r" to copy a folder.
    
    Signed-off-by: chenrun1 <ch...@xiaomi.com>
---
 nshlib/nsh_command.c |   2 +-
 nshlib/nsh_fscmds.c  | 403 ++++++++++++++++++++++++++++++++-------------------
 2 files changed, 254 insertions(+), 151 deletions(-)

diff --git a/nshlib/nsh_command.c b/nshlib/nsh_command.c
index 24d3e828d..70cd6ca8d 100644
--- a/nshlib/nsh_command.c
+++ b/nshlib/nsh_command.c
@@ -169,7 +169,7 @@ static const struct cmdmap_s g_cmdmap[] =
 #endif
 
 #ifndef CONFIG_NSH_DISABLE_CP
-  CMD_MAP("cp",       cmd_cp,       3, 3, "<source-path> <dest-path>"),
+  CMD_MAP("cp",       cmd_cp,       3, 4, "[-r] <source-path> <dest-path>"),
 #endif
 
 #ifndef CONFIG_NSH_DISABLE_CMP
diff --git a/nshlib/nsh_fscmds.c b/nshlib/nsh_fscmds.c
index 04636a7ed..3d45a288b 100644
--- a/nshlib/nsh_fscmds.c
+++ b/nshlib/nsh_fscmds.c
@@ -96,6 +96,235 @@
  * Private Functions
  ****************************************************************************/
 
+/****************************************************************************
+ * Name: cp_handler
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_CP
+static int cp_handler(FAR struct nsh_vtbl_s *vtbl, FAR const char *srcpath,
+                      FAR const char *destpath)
+{
+  struct stat buf;
+  FAR char *allocpath = NULL;
+  int oflags = O_WRONLY | O_CREAT | O_TRUNC;
+  int rdfd;
+  int wrfd;
+  int ret = ERROR;
+
+  rdfd = open(srcpath, O_RDONLY);
+  if (rdfd < 0)
+    {
+      nsh_error(vtbl, g_fmtcmdfailed, "cp", "open_rdfd", NSH_ERRNO);
+      return ret;
+    }
+
+  /* Check if the destination is a directory */
+
+  if (stat(destpath, &buf) == 0)
+    {
+      /* Something exists here... is it a directory? */
+
+      if (S_ISDIR(buf.st_mode))
+        {
+          /* Yes, it is a directory.
+           * Remove any trailing '/' characters from the path
+           */
+
+          nsh_trimdir((FAR char *)destpath);
+
+          /* Construct the full path to the new file */
+
+          allocpath = nsh_getdirpath(vtbl, destpath,
+                      basename((FAR char *)srcpath));
+          if (!allocpath)
+            {
+              nsh_error(vtbl, g_fmtcmdoutofmemory, "cp");
+              goto errout_with_rdfd;
+            }
+
+          /* Open then dest for writing */
+
+          destpath = allocpath;
+        }
+      else if (!S_ISREG(buf.st_mode))
+        {
+          /* Maybe it is a driver? */
+
+          oflags = O_WRONLY;
+        }
+    }
+
+  wrfd = open(destpath, oflags, 0666);
+  if (wrfd < 0)
+    {
+      nsh_error(vtbl, g_fmtcmdfailed, "cp", "open_wrfd", NSH_ERRNO);
+      goto errout_with_allocpath;
+    }
+
+  for (; ; )
+    {
+      int nbytesread;
+      int nbyteswritten;
+      FAR char *iobuffer = vtbl->iobuffer;
+
+      nbytesread = read(rdfd, iobuffer, IOBUFFERSIZE);
+      if (nbytesread == 0)
+        {
+          /* End of file */
+
+          ret = OK;
+          goto errout_with_wrfd;
+        }
+      else if (nbytesread < 0)
+        {
+          /* EINTR is not an error (but will still stop the copy) */
+
+          if (errno == EINTR)
+            {
+              nsh_error(vtbl, g_fmtsignalrecvd, "cp");
+            }
+          else
+            {
+              /* Read error */
+
+              nsh_error(vtbl, g_fmtcmdfailed, "cp", "read",
+                        NSH_ERRNO);
+            }
+
+          goto errout_with_wrfd;
+        }
+
+      do
+        {
+          nbyteswritten = write(wrfd, iobuffer, nbytesread);
+          if (nbyteswritten >= 0)
+            {
+              nbytesread -= nbyteswritten;
+              iobuffer += nbyteswritten;
+            }
+          else
+            {
+              /* EINTR is not an error (but will still stop the copy) */
+
+              if (errno == EINTR)
+                {
+                  nsh_error(vtbl, g_fmtsignalrecvd, "cp");
+                }
+              else
+                {
+                  /* Read error */
+
+                  nsh_error(vtbl, g_fmtcmdfailed, "cp", "write",
+                            NSH_ERRNO);
+                }
+
+              goto errout_with_wrfd;
+            }
+        }
+      while (nbytesread > 0);
+    }
+
+errout_with_wrfd:
+  close(wrfd);
+
+errout_with_allocpath:
+  free(allocpath);
+
+errout_with_rdfd:
+  close(rdfd);
+
+  return ret;
+}
+#endif
+
+/****************************************************************************
+ * Name: cp_recursive
+ ****************************************************************************/
+
+#ifndef CONFIG_NSH_DISABLE_CP
+static int cp_recursive(FAR struct nsh_vtbl_s *vtbl, FAR const char *srcpath,
+                        FAR const char *destpath)
+{
+  FAR struct dirent *entry;
+  FAR char *allocdestpath;
+  FAR char *allocsrcpath;
+  struct stat buf;
+  int ret = OK;
+  DIR *dp;
+
+  dp = opendir(srcpath);
+  if (dp == NULL)
+    {
+      nsh_error(vtbl, g_fmtcmdfailed, "cp", "opendir", NSH_ERRNO);
+      return ERROR;
+    }
+
+  while ((entry = readdir(dp)) != NULL && ret == OK)
+    {
+      if (strcmp(entry->d_name, ".") == 0 ||
+          strcmp(entry->d_name, "..") == 0)
+        {
+          continue;
+        }
+
+      allocsrcpath = nsh_getdirpath(vtbl, srcpath, entry->d_name);
+      if (allocsrcpath == NULL)
+        {
+          ret = ERROR;
+          continue;
+        }
+
+      ret = stat(allocsrcpath, &buf);
+      if (ret != OK)
+        {
+          nsh_error(vtbl, g_fmtcmdfailed, "cp", "stat", NSH_ERRNO);
+          goto errout_with_allocsrcpath;
+        }
+
+      allocdestpath = nsh_getdirpath(vtbl, destpath, entry->d_name);
+      if (allocdestpath == NULL)
+        {
+          ret = ERROR;
+          goto errout_with_allocsrcpath;
+        }
+
+      if (S_ISDIR(buf.st_mode))
+        {
+          ret = mkdir(allocdestpath, S_IRWXU | S_IRWXG | S_IROTH |
+                      S_IXOTH);
+          if (ret != OK)
+            {
+              nsh_error(vtbl, g_fmtcmdfailed, "cp", "mkdir", NSH_ERRNO);
+              goto errout_with_allocdestpath;
+            }
+
+          ret = cp_recursive(vtbl, allocsrcpath, allocdestpath);
+          if (ret != OK)
+            {
+              goto errout_with_allocdestpath;
+            }
+        }
+      else
+        {
+          ret = cp_handler(vtbl, allocsrcpath, allocdestpath);
+          if (ret != OK)
+            {
+              goto errout_with_allocdestpath;
+            }
+        }
+
+errout_with_allocdestpath:
+      free(allocdestpath);
+
+errout_with_allocsrcpath:
+      free(allocsrcpath);
+    }
+
+  closedir(dp);
+  return ret;
+}
+#endif
+
 /****************************************************************************
  * Name: ls_specialdir
  ****************************************************************************/
@@ -618,79 +847,38 @@ int cmd_dmesg(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
 #ifndef CONFIG_NSH_DISABLE_CP
 int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
 {
-  UNUSED(argc);
-
-  struct stat buf;
   FAR char *srcpath  = NULL;
   FAR char *destpath = NULL;
-  FAR char *allocpath = NULL;
-  int oflags = O_WRONLY | O_CREAT | O_TRUNC;
-  int rdfd;
-  int wrfd;
+  bool recursive = false;
   int ret = ERROR;
+  int option;
 
-  /* Get the full path to the source file */
+  /* Get the cp flags */
 
-  srcpath = nsh_getfullpath(vtbl, argv[1]);
-  if (srcpath == NULL)
+  while ((option = getopt(argc, argv, "r")) != ERROR)
     {
-      nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
-      goto errout;
+      switch (option)
+        {
+          case 'r':
+            recursive = true;
+            break;
+        }
     }
 
-  /* Open the source file for reading */
+  /* Get the full path to the source file */
 
-  rdfd = open(srcpath, O_RDONLY);
-  if (rdfd < 0)
+  srcpath = nsh_getfullpath(vtbl, argv[optind]);
+  if (srcpath == NULL)
     {
-      nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
-      goto errout_with_srcpath;
+      nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
+      goto errout;
     }
 
-  /* Get the full path to the destination file or directory */
-
-  destpath = nsh_getfullpath(vtbl, argv[2]);
+  destpath = nsh_getfullpath(vtbl, argv[optind + 1]);
   if (destpath == NULL)
     {
       nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
-      goto errout_with_rdfd;
-    }
-
-  /* Check if the destination is a directory */
-
-  ret = stat(destpath, &buf);
-  if (ret == 0)
-    {
-      /* Something exists here... is it a directory? */
-
-      if (S_ISDIR(buf.st_mode))
-        {
-          /* Yes, it is a directory.
-           * Remove any trailing '/' characters from the path
-           */
-
-          nsh_trimdir(destpath);
-
-          /* Construct the full path to the new file */
-
-          allocpath = nsh_getdirpath(vtbl, destpath, basename(argv[1]));
-          if (!allocpath)
-            {
-              nsh_error(vtbl, g_fmtcmdoutofmemory, argv[0]);
-              goto errout_with_destpath;
-            }
-
-          /* Open then dest for writing */
-
-          nsh_freefullpath(destpath);
-          destpath = allocpath;
-        }
-      else if (!S_ISREG(buf.st_mode))
-        {
-          /* Maybe it is a driver? */
-
-          oflags = O_WRONLY;
-        }
+      goto errout_with_srcpath;
     }
 
   /* Check if the destination does not match the source */
@@ -698,110 +886,25 @@ int cmd_cp(FAR struct nsh_vtbl_s *vtbl, int argc, FAR char **argv)
   if (strcmp(destpath, srcpath) == 0)
     {
       nsh_error(vtbl, g_fmtsyntax, argv[0]);
-      goto errout_with_allocpath;
+      goto errout_with_destpath;
     }
 
   /* Now open the destination */
 
-  wrfd = open(destpath, oflags, 0666);
-  if (wrfd < 0)
-    {
-      nsh_error(vtbl, g_fmtcmdfailed, argv[0], "open", NSH_ERRNO);
-      goto errout_with_allocpath;
-    }
-
-  /* Now copy the file */
-
-  for (; ; )
+  if (recursive)
     {
-      int nbytesread;
-      int nbyteswritten;
-      FAR char *iobuffer = vtbl->iobuffer;
-
-      do
-        {
-          nbytesread = read(rdfd, iobuffer, IOBUFFERSIZE);
-          if (nbytesread == 0)
-            {
-              /* End of file */
-
-              ret = OK;
-              goto errout_with_wrfd;
-            }
-          else if (nbytesread < 0)
-            {
-              /* EINTR is not an error (but will still stop the copy) */
-
-              if (errno == EINTR)
-                {
-                  nsh_error(vtbl, g_fmtsignalrecvd, argv[0]);
-                }
-              else
-                {
-                  /* Read error */
-
-                  nsh_error(vtbl, g_fmtcmdfailed, argv[0], "read",
-                            NSH_ERRNO);
-                }
-
-              goto errout_with_wrfd;
-            }
-        }
-      while (nbytesread <= 0);
-
-      do
-        {
-          nbyteswritten = write(wrfd, iobuffer, nbytesread);
-          if (nbyteswritten >= 0)
-            {
-              nbytesread -= nbyteswritten;
-              iobuffer += nbyteswritten;
-            }
-          else
-            {
-              /* EINTR is not an error (but will still stop the copy) */
-
-              if (errno == EINTR)
-                {
-                  nsh_error(vtbl, g_fmtsignalrecvd, argv[0]);
-                }
-              else
-                {
-                  /* Read error */
-
-                  nsh_error(vtbl, g_fmtcmdfailed, argv[0], "write",
-                            NSH_ERRNO);
-                }
-
-              goto errout_with_wrfd;
-            }
-        }
-      while (nbytesread > 0);
+      ret = cp_recursive(vtbl, srcpath, destpath);
     }
-
-errout_with_wrfd:
-  close(wrfd);
-
-errout_with_allocpath:
-  if (allocpath)
+  else
     {
-      free(allocpath);
+      ret = cp_handler(vtbl, srcpath, destpath);
     }
 
 errout_with_destpath:
-  if (destpath && !allocpath)
-    {
-      nsh_freefullpath(destpath);
-    }
-
-errout_with_rdfd:
-  close(rdfd);
+  nsh_freefullpath(destpath);
 
 errout_with_srcpath:
-  if (srcpath)
-    {
-      nsh_freefullpath(srcpath);
-    }
+  nsh_freefullpath(srcpath);
 
 errout:
   return ret;