* [PATCH] elkscmd/file_utils/cp.c: add options -b, -n, -v, -u and updated usage
@ 2015-04-01 11:22 Nils Stec
2015-04-01 11:32 ` Jody Bruchon
0 siblings, 1 reply; 4+ messages in thread
From: Nils Stec @ 2015-04-01 11:22 UTC (permalink / raw)
To: ELKS
[-- Attachment #1: Type: text/plain, Size: 540 bytes --]
Here's my updated patch. I think this attempt is better than the first,
if you still find something annoying i will fix/change it.
This patch add some command line options to cp:
-b make backup if file exists
-n no clobber
-v be verbose
-u overwrite if source is newer than destintation file
I also tried to add "-i" (interactive), but i still need to figure out
how to ask for just one keypress (y/n) without pressing return...
Everything for that is prepared, in usage-text -i is commented out.
Hope you like this,
Nils
[-- Attachment #2: patch-cp-add_options_002.diff --]
[-- Type: text/x-patch, Size: 5256 bytes --]
diff --git a/elkscmd/file_utils/cp.c b/elkscmd/file_utils/cp.c
index 6e23864..b881af0 100644
--- a/elkscmd/file_utils/cp.c
+++ b/elkscmd/file_utils/cp.c
@@ -20,11 +20,25 @@
#include <grp.h>
#include <utime.h>
#include <errno.h>
+#include <stdint.h>
#define BUF_SIZE 4096
static char *buf;
+/* macros for flag setting/clearing/testing */
+#define ISFLAG(a) ((flags & a) == a)
+#define SETFLAG(a) (flags |= a)
+#define CLRFLAG(a) (flags &= ~(a))
+
+/* some flags for command-line-options */
+static uint16_t flags;
+#define OPT_NOCLOBBER 0x0001
+#define OPT_VERBOSE 0x0002
+#define OPT_INTERACTIVE 0x0004
+#define OPT_BACKUP 0x0008
+#define OPT_BACKUPMADE 0x0010
+#define OPT_UPDATE 0x0020
/*
* Build a path name from the specified directory name and file name.
@@ -67,6 +81,9 @@ int isadir(char *name)
* and modes. Returns 1 if successful, or 0 on a failure with an
* error message output. (Failure is not indicated if the attributes cannot
* be set.)
+ *
+ * Returns -1 if OPT_NOCLOBBER is set and a file is skipped if existent.
+ * This "skipped-file-indicator" is not used atm.
*/
int copyfile(char *srcname, char *destname, int setmodes)
{
@@ -78,15 +95,38 @@ int copyfile(char *srcname, char *destname, int setmodes)
struct stat statbuf1;
struct stat statbuf2;
struct utimbuf times;
+ static char backupname[PATHLEN];
+ /* source nonexistent */
if (stat(srcname, &statbuf1) < 0) {
perror(srcname);
return 0;
}
+ /* destination nonexistent */
if (stat(destname, &statbuf2) < 0) {
statbuf2.st_ino = -1;
statbuf2.st_dev = -1;
+ } else { /* destination existent */
+ if (ISFLAG(OPT_BACKUP)) {
+ strcpy(backupname, destname);
+ strcat(backupname, "~");
+ rename(destname, backupname);
+ SETFLAG(OPT_BACKUPMADE);
+ } else if (ISFLAG(OPT_UPDATE)) {
+ /* if dest is newer than source, don't overwrite it */
+ if (statbuf1.st_mtime < statbuf2.st_mtime) return -1;
+ } else if (ISFLAG(OPT_NOCLOBBER)) {
+ return -1;
+ } else if (ISFLAG(OPT_INTERACTIVE)) {
+ /* TODO fix this, getchar wants return */
+ /*
+ * fprintf(stderr, "really overwrite '%s'? (y/n) \n", destname);
+ if(getchar() != 'y') {
+ return -1;
+ }
+ */
+ }
}
if ((statbuf1.st_dev == statbuf2.st_dev) &&
@@ -143,9 +183,14 @@ int copyfile(char *srcname, char *destname, int setmodes)
(void) utime(destname, ×);
}
+ if (ISFLAG(OPT_BACKUPMADE) && ISFLAG(OPT_VERBOSE)) {
+ fprintf(stderr, "`%s' -> `%s' (backup: `%s')\n", srcname, destname, backupname);
+ CLRFLAG(OPT_BACKUPMADE);
+ }
+ else if (ISFLAG(OPT_VERBOSE))
+ fprintf(stderr, "`%s' -> `%s'\n", srcname, destname);
return 1;
-
error_exit:
close(rfd);
close(wfd);
@@ -157,37 +202,76 @@ error_exit:
int main(int argc, char **argv)
{
int dirflag;
+ int arg_cnt;
+ int opt_cnt;
+ int retval;
+ unsigned int file_count;
char *srcname;
char *destname;
char *lastarg;
if (argc < 3) goto usage;
+ /* lastarg is copy destination */
lastarg = argv[argc - 1];
dirflag = isadir(lastarg);
- if ((argc > 3) && !dirflag) {
- fprintf(stderr, "%s: not a directory\n", lastarg);
+ flags = 0;
+ opt_cnt = 0;
+
+ arg_cnt = 1; /* start at argv[1] */
+ while(arg_cnt < argc) {
+ if (!strcmp(argv[arg_cnt], "-n")) {
+ SETFLAG(OPT_NOCLOBBER);
+ } else if (!strcmp(argv[arg_cnt], "-v")) {
+ SETFLAG(OPT_VERBOSE);
+ } else if (!strcmp(argv[arg_cnt], "-i")) {
+ SETFLAG(OPT_INTERACTIVE);
+ } else if (!strcmp(argv[arg_cnt], "-u")) {
+ SETFLAG(OPT_UPDATE);
+ } else if (!strcmp(argv[arg_cnt], "-b")) {
+ SETFLAG(OPT_BACKUP);
+ } else if (!strcmp(argv[arg_cnt], "-h")) goto usage;
+ else break;
+ opt_cnt++;
+ arg_cnt++;
+ }
+ opt_cnt++;
+
+ /* if multiple files are specified, last one must be a directory */
+ if ((argc > (opt_cnt + 2)) && !dirflag) {
+ fprintf(stderr, "%s is not a directory\n", lastarg);
exit(1);
}
buf = malloc(BUF_SIZE);
- while (argc-- > 2) {
- srcname = argv[1];
+ file_count = 0;
+ while (argc-- > (opt_cnt + 1)) {
+ srcname = argv[opt_cnt+file_count];
destname = lastarg;
if (dirflag) destname = buildname(destname, srcname);
- if (!copyfile(*++argv, destname, 0)) goto error_copy;
+ retval = copyfile(srcname, destname, 0);
+ if (!retval) goto error_copy;
+ file_count++;
}
free(buf);
+
exit(0);
error_copy:
fprintf(stderr, "Failed to copy %s -> %s\n", srcname, destname);
exit(1);
usage:
- fprintf(stderr, "usage: %s source_file dest_file\n", argv[0]);
- fprintf(stderr, " %s file1 file2 ... dest_directory\n", argv[0]);
+ fprintf(stderr, "usage: %s [options] source_file dest_file\n", argv[0]);
+ fprintf(stderr, " %s [options] file1 file2 ... dest_directory\n", argv[0]);
+ fprintf(stderr, "options: -b make a backup of each exisiting destination file\n");
+ fprintf(stderr, " -b overrides -u (update)\n");
+ fprintf(stderr, " -n no overwriting, no clobber\n");
+ fprintf(stderr, " -v be verbose\n");
+/* fprintf(stderr, " -i interactive, prompt before overwrite\n");
+ fprintf(stderr, " -b, -u and -n override interactive mode\n");*/
+ fprintf(stderr, " -u copy only if source file is newer than destination file\n");
exit(1);
}
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] elkscmd/file_utils/cp.c: add options -b, -n, -v, -u and updated usage
2015-04-01 11:22 [PATCH] elkscmd/file_utils/cp.c: add options -b, -n, -v, -u and updated usage Nils Stec
@ 2015-04-01 11:32 ` Jody Bruchon
2015-04-01 11:41 ` Nils Stec
2015-04-01 12:35 ` Jody Bruchon
0 siblings, 2 replies; 4+ messages in thread
From: Jody Bruchon @ 2015-04-01 11:32 UTC (permalink / raw)
To: ELKS
On 4/1/2015 7:22 AM, Nils Stec wrote:
+ * Returns -1 if OPT_NOCLOBBER is set and a file is skipped if existent.
...
+ } else if (ISFLAG(OPT_NOCLOBBER)) {
+ return -1;
...
+ retval = copyfile(srcname, destname, 0);
+ if (!retval) goto error_copy;
This causes an error to be returned if someone asks for no clobbering.
Doing what is asked for by the user should never be an error condition
and should return success unless a true error occurred (i.e. write
errors). Here's example output when using the -n switch with GNU
coreutils 'cp' and testing for any error conditions:
$ ls -l foo bar
bar:
total 0
-rw-r--r-- 1 user user 0 Apr 1 07:31 1
-rw-r--r-- 1 user user 0 Apr 1 07:31 2
foo:
total 12
-rw-r--r-- 1 user user 4 Apr 1 07:31 1
-rw-r--r-- 1 user user 4 Apr 1 07:31 2
-rw-r--r-- 1 user user 4 Apr 1 07:31 3
$ cp -n foo/* bar/ || echo error
$ cp -n foo/* bar/ && echo success
success
$ ls -l foo bar
bar:
total 4
-rw-r--r-- 1 user user 0 Apr 1 07:31 1
-rw-r--r-- 1 user user 0 Apr 1 07:31 2
-rw-r--r-- 1 user user 4 Apr 1 07:32 3
foo:
total 12
-rw-r--r-- 1 user user 4 Apr 1 07:31 1
-rw-r--r-- 1 user user 4 Apr 1 07:31 2
-rw-r--r-- 1 user user 4 Apr 1 07:31 3
$
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH] elkscmd/file_utils/cp.c: add options -b, -n, -v, -u and updated usage
2015-04-01 11:32 ` Jody Bruchon
@ 2015-04-01 11:41 ` Nils Stec
2015-04-01 12:35 ` Jody Bruchon
1 sibling, 0 replies; 4+ messages in thread
From: Nils Stec @ 2015-04-01 11:41 UTC (permalink / raw)
To: ELKS
[-- Attachment #1: Type: text/plain, Size: 1545 bytes --]
On 04/01/2015 01:32 PM, Jody Bruchon wrote:
> On 4/1/2015 7:22 AM, Nils Stec wrote:
> + * Returns -1 if OPT_NOCLOBBER is set and a file is skipped if existent.
> ...
> + } else if (ISFLAG(OPT_NOCLOBBER)) {
> + return -1;
> ...
> + retval = copyfile(srcname, destname, 0);
> + if (!retval) goto error_copy;
>
> This causes an error to be returned if someone asks for no clobbering.
> Doing what is asked for by the user should never be an error condition
> and should return success unless a true error occurred (i.e. write
> errors). Here's example output when using the -n switch with GNU
> coreutils 'cp' and testing for any error conditions:
>
> $ ls -l foo bar
> bar:
> total 0
> -rw-r--r-- 1 user user 0 Apr 1 07:31 1
> -rw-r--r-- 1 user user 0 Apr 1 07:31 2
>
> foo:
> total 12
> -rw-r--r-- 1 user user 4 Apr 1 07:31 1
> -rw-r--r-- 1 user user 4 Apr 1 07:31 2
> -rw-r--r-- 1 user user 4 Apr 1 07:31 3
> $ cp -n foo/* bar/ || echo error
> $ cp -n foo/* bar/ && echo success
> success
> $ ls -l foo bar
> bar:
> total 4
> -rw-r--r-- 1 user user 0 Apr 1 07:31 1
> -rw-r--r-- 1 user user 0 Apr 1 07:31 2
> -rw-r--r-- 1 user user 4 Apr 1 07:32 3
>
> foo:
> total 12
> -rw-r--r-- 1 user user 4 Apr 1 07:31 1
> -rw-r--r-- 1 user user 4 Apr 1 07:31 2
> -rw-r--r-- 1 user user 4 Apr 1 07:31 3
> $
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-8086" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
[-- Attachment #2: patch-cp-add_options_004.diff --]
[-- Type: text/x-patch, Size: 4859 bytes --]
diff --git a/elkscmd/file_utils/cp.c b/elkscmd/file_utils/cp.c
index 6e23864..2e413e9 100644
--- a/elkscmd/file_utils/cp.c
+++ b/elkscmd/file_utils/cp.c
@@ -20,11 +20,25 @@
#include <grp.h>
#include <utime.h>
#include <errno.h>
+#include <stdint.h>
#define BUF_SIZE 4096
static char *buf;
+/* macros for flag setting/clearing/testing */
+#define ISFLAG(a) ((flags & a) == a)
+#define SETFLAG(a) (flags |= a)
+#define CLRFLAG(a) (flags &= ~(a))
+
+/* some flags for command-line-options */
+static uint16_t flags;
+#define OPT_NOCLOBBER 0x0001
+#define OPT_VERBOSE 0x0002
+#define OPT_INTERACTIVE 0x0004
+#define OPT_BACKUP 0x0008
+#define OPT_BACKUPMADE 0x0010
+#define OPT_UPDATE 0x0020
/*
* Build a path name from the specified directory name and file name.
@@ -78,15 +92,38 @@ int copyfile(char *srcname, char *destname, int setmodes)
struct stat statbuf1;
struct stat statbuf2;
struct utimbuf times;
+ static char backupname[PATHLEN];
+ /* source nonexistent */
if (stat(srcname, &statbuf1) < 0) {
perror(srcname);
return 0;
}
+ /* destination nonexistent */
if (stat(destname, &statbuf2) < 0) {
statbuf2.st_ino = -1;
statbuf2.st_dev = -1;
+ } else { /* destination existent */
+ if (ISFLAG(OPT_BACKUP)) {
+ strcpy(backupname, destname);
+ strcat(backupname, "~");
+ rename(destname, backupname);
+ SETFLAG(OPT_BACKUPMADE);
+ } else if (ISFLAG(OPT_UPDATE)) {
+ /* if dest is newer than source, don't overwrite it */
+ if (statbuf1.st_mtime < statbuf2.st_mtime) return 1;
+ } else if (ISFLAG(OPT_NOCLOBBER)) {
+ return 1;
+ } else if (ISFLAG(OPT_INTERACTIVE)) {
+ /* TODO fix this, getchar wants return */
+ /*
+ * fprintf(stderr, "really overwrite '%s'? (y/n) \n", destname);
+ if(getchar() != 'y') {
+ return -1;
+ }
+ */
+ }
}
if ((statbuf1.st_dev == statbuf2.st_dev) &&
@@ -143,9 +180,14 @@ int copyfile(char *srcname, char *destname, int setmodes)
(void) utime(destname, ×);
}
+ if (ISFLAG(OPT_BACKUPMADE) && ISFLAG(OPT_VERBOSE)) {
+ fprintf(stderr, "`%s' -> `%s' (backup: `%s')\n", srcname, destname, backupname);
+ CLRFLAG(OPT_BACKUPMADE);
+ }
+ else if (ISFLAG(OPT_VERBOSE))
+ fprintf(stderr, "`%s' -> `%s'\n", srcname, destname);
return 1;
-
error_exit:
close(rfd);
close(wfd);
@@ -157,37 +199,76 @@ error_exit:
int main(int argc, char **argv)
{
int dirflag;
+ int arg_cnt;
+ int opt_cnt;
+ int retval;
+ unsigned int file_count;
char *srcname;
char *destname;
char *lastarg;
if (argc < 3) goto usage;
+ /* lastarg is copy destination */
lastarg = argv[argc - 1];
dirflag = isadir(lastarg);
- if ((argc > 3) && !dirflag) {
- fprintf(stderr, "%s: not a directory\n", lastarg);
+ flags = 0;
+ opt_cnt = 0;
+
+ arg_cnt = 1; /* start at argv[1] */
+ while(arg_cnt < argc) {
+ if (!strcmp(argv[arg_cnt], "-n")) {
+ SETFLAG(OPT_NOCLOBBER);
+ } else if (!strcmp(argv[arg_cnt], "-v")) {
+ SETFLAG(OPT_VERBOSE);
+ } else if (!strcmp(argv[arg_cnt], "-i")) {
+ SETFLAG(OPT_INTERACTIVE);
+ } else if (!strcmp(argv[arg_cnt], "-u")) {
+ SETFLAG(OPT_UPDATE);
+ } else if (!strcmp(argv[arg_cnt], "-b")) {
+ SETFLAG(OPT_BACKUP);
+ } else if (!strcmp(argv[arg_cnt], "-h")) goto usage;
+ else break;
+ opt_cnt++;
+ arg_cnt++;
+ }
+ opt_cnt++;
+
+ /* if multiple files are specified, last one must be a directory */
+ if ((argc > (opt_cnt + 2)) && !dirflag) {
+ fprintf(stderr, "%s is not a directory\n", lastarg);
exit(1);
}
buf = malloc(BUF_SIZE);
- while (argc-- > 2) {
- srcname = argv[1];
+ file_count = 0;
+ while (argc-- > (opt_cnt + 1)) {
+ srcname = argv[opt_cnt+file_count];
destname = lastarg;
if (dirflag) destname = buildname(destname, srcname);
- if (!copyfile(*++argv, destname, 0)) goto error_copy;
+ retval = copyfile(srcname, destname, 0);
+ if (!retval) goto error_copy;
+ file_count++;
}
free(buf);
+
exit(0);
error_copy:
fprintf(stderr, "Failed to copy %s -> %s\n", srcname, destname);
exit(1);
usage:
- fprintf(stderr, "usage: %s source_file dest_file\n", argv[0]);
- fprintf(stderr, " %s file1 file2 ... dest_directory\n", argv[0]);
+ fprintf(stderr, "usage: %s [options] source_file dest_file\n", argv[0]);
+ fprintf(stderr, " %s [options] file1 file2 ... dest_directory\n", argv[0]);
+ fprintf(stderr, "options: -b make a backup of each exisiting destination file\n");
+ fprintf(stderr, " -b overrides -u (update)\n");
+ fprintf(stderr, " -n no overwriting, no clobber\n");
+ fprintf(stderr, " -v be verbose\n");
+/* fprintf(stderr, " -i interactive, prompt before overwrite\n");
+ fprintf(stderr, " -b, -u and -n override interactive mode\n");*/
+ fprintf(stderr, " -u copy only if source file is newer than destination file\n");
exit(1);
}
^ permalink raw reply related [flat|nested] 4+ messages in thread* Re: [PATCH] elkscmd/file_utils/cp.c: add options -b, -n, -v, -u and updated usage
2015-04-01 11:32 ` Jody Bruchon
2015-04-01 11:41 ` Nils Stec
@ 2015-04-01 12:35 ` Jody Bruchon
1 sibling, 0 replies; 4+ messages in thread
From: Jody Bruchon @ 2015-04-01 12:35 UTC (permalink / raw)
To: ELKS
On 4/1/2015 7:32 AM, Jody Bruchon wrote:
> This causes an error to be returned if someone asks for no clobbering.
I should drink more caffeine before reading code in the morning; it
seems that this statement is not correct after all. I can't seem to
apply the patch against master though.
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2015-04-01 12:35 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-04-01 11:22 [PATCH] elkscmd/file_utils/cp.c: add options -b, -n, -v, -u and updated usage Nils Stec
2015-04-01 11:32 ` Jody Bruchon
2015-04-01 11:41 ` Nils Stec
2015-04-01 12:35 ` Jody Bruchon
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox