All of lore.kernel.org
 help / color / mirror / Atom feed
From: Nils Stec <nils.stec@gmail.com>
To: ELKS <linux-8086@vger.kernel.org>
Subject: Re: [PATCH] elkscmd/file_utils/cp.c: add options -b, -n, -v, -u and updated usage
Date: Wed, 01 Apr 2015 13:41:04 +0200	[thread overview]
Message-ID: <551BD950.40406@gmail.com> (raw)
In-Reply-To: <551BD737.8040602@jodybruchon.com>

[-- 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, &times);
 	}
 
+	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);
 }

  reply	other threads:[~2015-04-01 11:41 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
2015-04-01 12:35   ` Jody Bruchon

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=551BD950.40406@gmail.com \
    --to=nils.stec@gmail.com \
    --cc=linux-8086@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.