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;