Hi,

I was having trouble with our patch.

It didn't warn about previously applied hunks, like:
$ dmesg | tail | tee mess > mess.orig
$ echo new line >> mess
$ diff -u mess.orig mess > xxx
$ #NOT mv mess.orig mess
$ patch -i xxx

There is -N to allow to skip them (complaining loud).

And we didn't have --dry-run.
I've picked the short-option -z for --dry-run out of the blue to
facilitate !getopt_long usage of patch.

A few points though:
- The size increase is absolutely intolerable.
  (rephrase hunk handling)
- for --dry-run we should just not write anything to dst_stream
  and get rid of any temporary file in due course.

I currently don't have more time for patch, so it would be great if
somebody steps up and either applies it as a fix in it's current state
or look a bit into it before committing it.

thanks,
diff --git a/editors/patch.c b/editors/patch.c
index 4a97151..226096a 100644
--- a/editors/patch.c
+++ b/editors/patch.c
@@ -75,16 +75,27 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
 	int ret = 0;
 	char plus = '+';
 	unsigned opt;
+#if ENABLE_LONG_OPTS
+static const char patch_longopts[] ALIGN1 =
+	"strip\0" Required_argument "p"
+	"input\0" Required_argument "i"
+	"reverse\0" No_argument "R"
+	"forward\0" No_argument "N"
+	"dry-run\0" No_argument "z"
+	;
+#endif
 	enum {
 		OPT_R = (1 << 2),
 		OPT_N = (1 << 3),
+		OPT_dry_run = (1 << 4),
 	};
 
 	xfunc_error_retval = 2;
 	{
 		const char *p = "-1";
 		const char *i = "-"; /* compat */
-		opt = getopt32(argv, "p:i:RN", &p, &i);
+		IF_LONG_OPTS(applet_long_options = patch_longopts;)
+		opt = getopt32(argv, "p:i:RNz", &p, &i);
 		if (opt & OPT_R)
 			plus = '-';
 		patch_level = xatoi(p); /* can be negative! */
@@ -97,7 +108,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
 		FILE *dst_stream;
 		//char *old_filename;
 		char *new_filename;
-		char *backup_filename;
+		char *backup_filename = NULL;
 		unsigned src_cur_line = 1;
 		unsigned dst_cur_line = 0;
 		unsigned dst_beg_line;
@@ -131,15 +142,20 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
 				bb_make_directory(new_filename, -1, FILEUTILS_RECUR);
 				*slash = '/';
 			}
-			backup_filename = NULL;
 			src_stream = NULL;
 			saved_stat.st_mode = 0644;
-		} else {
+		} else if (!(opt & OPT_dry_run)) {
 			backup_filename = xasprintf("%s.orig", new_filename);
 			xrename(new_filename, backup_filename);
 			src_stream = xfopen_for_read(backup_filename);
-		}
-		dst_stream = xfopen_for_write(new_filename);
+		} else
+			src_stream = xfopen_for_read(new_filename);
+		if (opt & OPT_dry_run) {
+			backup_filename = xasprintf("/tmp/.%s", basename(new_filename));//FIXME: tidy up
+			copy_file(new_filename, backup_filename, 0);
+			dst_stream = xfopen_for_write(backup_filename);
+		} else
+			dst_stream = xfopen_for_write(new_filename);
 		fchmod(fileno(dst_stream), saved_stat.st_mode);
 
 		printf("patching file %s\n", new_filename);
@@ -152,6 +168,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
 			unsigned hunk_offset_start;
 			unsigned src_last_line = 1;
 			unsigned dst_last_line = 1;
+			char *src_line = NULL;
 
 			if ((sscanf(patch_line, "@@ -%d,%d +%d,%d", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3)
 			 && (sscanf(patch_line, "@@ -%d +%d,%d", &src_beg_line, &dst_beg_line, &dst_last_line) < 2)
@@ -187,39 +204,44 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
 			while (1) {
 				free(patch_line);
 				patch_line = xmalloc_fgets(patch_file);
-				if (patch_line == NULL)
-					break; /* EOF */
-				if ((*patch_line != '-') && (*patch_line != '+')
-				 && (*patch_line != ' ')
-				) {
-					break; /* End of hunk */
-				}
-				if (*patch_line != plus) { /* '-' or ' ' */
-					char *src_line = NULL;
-					if (src_cur_line == src_last_line)
-						break;
-					if (src_stream) {
-						src_line = xmalloc_fgets(src_stream);
-						if (src_line) {
+				if (patch_line == NULL || (*patch_line != '+'
+					&& *patch_line != '-' && *patch_line != ' '))
+					break; /* EOF or End of hunk */
+				if (src_stream && !src_line) {
+					src_line = xmalloc_fgets(src_stream);
+					if (src_line) {
+						src_cur_line++;
+						if (*patch_line != plus) {
 							int diff = strcmp(src_line, patch_line + 1);
-							src_cur_line++;
 							free(src_line);
 							if (diff)
 								src_line = NULL;
 						}
 					}
-					/* Do not patch an already patched hunk with -N */
-					if (src_line == 0 && (opt & OPT_N)) {
+				}
+				if (*patch_line != plus && !src_line) {
+					bb_error_msg("hunk #%u FAILED at %u",
+								 hunk_count, hunk_offset_start);
+ bad_hunk:
+					bad_hunk_count++;
+					break;
+				}
+				if (src_cur_line > src_last_line) {
+					static char msg[] =
+						"Reversed (or previously applied) "
+							 "hunk #%u at %u detected! Skipping.";
+					if (opt & OPT_N) {
+						bb_error_msg(msg, hunk_count, hunk_offset_start);
 						continue;
 					}
-					if (!src_line) {
-						bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start);
-						bad_hunk_count++;
-						break;
-					}
-					if (*patch_line != ' ') { /* '-' */
+					msg[57] = '\0';
+					bb_error_msg(msg, hunk_count, hunk_offset_start);
+					goto bad_hunk;
+				}
+				if (*patch_line != plus) {
+					src_line = NULL;
+					if (*patch_line != ' ') /* '-' */
 						continue;
-					}
 				}
 				if (dst_cur_line == dst_last_line)
 					break;
@@ -244,7 +266,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv)
 			if (backup_filename) {
 				unlink(backup_filename);
 			}
-			if ((dst_cur_line == 0) || (dst_beg_line == 0)) {
+			if (!(opt & OPT_dry_run)
+				&& ((dst_cur_line == 0) || (dst_beg_line == 0))) {
 				/* The new patched file is empty, remove it */
 				xunlink(new_filename);
 				// /* old_filename and new_filename may be the same file */
diff --git a/include/usage.h b/include/usage.h
index 8316c43..05cbb50 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -3240,12 +3240,22 @@
 	)
 
 #define patch_trivial_usage \
-       "[-p NUM] [-i DIFF] [-R] [-N]"
+       "[OPTION]... [ORIGFILE [PATCHFILE]]"
 #define patch_full_usage "\n\n" \
+	IF_LONG_OPTS( \
+       "	-p,--strip NUM	Strip NUM leading components from file names" \
+     "\n	-i,--input DIFF	Read DIFF instead of stdin" \
+     "\n	-R,--reverse	Reverse patch" \
+     "\n	-N,--forward	Ignore already applied patches" \
+     "\n	-z,--dry-run	Don't actually change files" \
+	) \
+	IF_NOT_LONG_OPTS( \
        "	-p NUM	Strip NUM leading components from file names" \
      "\n	-i DIFF	Read DIFF instead of stdin" \
      "\n	-R	Reverse patch" \
      "\n	-N	Ignore already applied patches" \
+     "\n	-z	Dry run, don't actually change files" \
+	)
 
 #define patch_example_usage \
        "$ patch -p1 < example.diff\n" \
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to