Make "patch -r rejfile" work even when there are several rejects

With a patch that includes rejects in more than one file and with the -r
option, rejects would overwrite themselves and only the rejects from
the last file would remain.  Fix this.
This commit is contained in:
Andreas Gruenbacher 2009-03-14 16:24:09 +01:00
parent 9371e1ac99
commit b80bfda68f
7 changed files with 149 additions and 12 deletions

View File

@ -1,3 +1,16 @@
2009-03-21 Andreas Gruenbacher <agruen@suse.de>
* patch.c (main): With -r, instead of moving the global reject
file into place, copy the first reject into the file, and
append all the rest. Discard rejects with -r -.
* patch.man: Document the latter.
* util.c (copy_to_fd): New function.
(copy_file): Use that.
(append_to_file): New function.
* util.h (append_to_file): Add function declaration.
* tests/global-reject-files: New test case.
* Makefile.in (TESTS): Add test case.
2009-03-20 Andreas Gruenbacher <agruen@suse.de>
* patch.c: New option --reject-format=FORMAT.

View File

@ -88,7 +88,7 @@ HDRS = argmatch.h backupfile.h common.h dirname.h \
MISC = AUTHORS COPYING ChangeLog INSTALL Makefile.in NEWS README VERSION \
aclocal.m4 config.hin configure configure.ac install-sh \
mkinstalldirs patch.man stdbool_.h timespec.h
TESTS = tests/corrupt-reject-files tests/crlf-handling \
TESTS = tests/corrupt-reject-files tests/crlf-handling tests/global-reject-files \
tests/no-newline-triggers-assert tests/preserve-c-function-names \
tests/preserve-mode-and-timestamp \
tests/reject-format tests/remember-backup-files

18
patch.c
View File

@ -124,6 +124,7 @@ main (int argc, char **argv)
struct outstate outstate;
struct stat outst;
char numbuf[LINENUM_LENGTH_BOUND + 1];
bool written_to_rejname = false;
exit_failure = 2;
program_name = argv[0];
@ -427,7 +428,7 @@ main (int argc, char **argv)
somefailed = true;
say ("%d out of %d hunk%s %s", failed, hunk, "s" + (hunk == 1),
skip_rest_of_patch ? "ignored" : "FAILED");
if (outname) {
if (outname && (! rejname || strcmp (rejname, "-") != 0)) {
char *rej = rejname;
if (!rejname) {
rej = xmalloc (strlen (outname) + 5);
@ -437,8 +438,19 @@ main (int argc, char **argv)
say (" -- saving rejects to file %s", quotearg (rej));
if (! dry_run)
{
move_file (TMPREJNAME, &TMPREJNAME_needs_removal, 0,
rej, 0666, false);
if (rejname)
{
if (! written_to_rejname)
{
copy_file (TMPREJNAME, rejname, 0, 0, 0666);
written_to_rejname = true;
}
else
append_to_file (TMPREJNAME, rejname);
}
else
move_file (TMPREJNAME, &TMPREJNAME_needs_removal, 0,
rej, 0666, false);
}
if (!rejname)
free (rej);

View File

@ -514,7 +514,7 @@ Put rejects into
.I rejectfile
instead of the default
.B \&.rej
file.
file. When \fIrejectfile\fP is \fB\-\fP, discard rejects.
.TP
\fB\-R\fP or \fB\*=reverse\fP
Assume that this patch was created with the old and new files swapped.

90
tests/global-reject-files Executable file
View File

@ -0,0 +1,90 @@
#! /bin/bash
# Copyright (C) 2009 Free Software Foundation, Inc.
#
# Copying and distribution of this file, with or without modification,
# in any medium, are permitted without royalty provided the copyright
# notice and this notice are preserved.
# More than one reject to
. $srcdir/test-lib.sh
require_cat
require_diff
use_local_patch
use_tmpdir
# ==============================================================
cat > ab.diff <<EOF
--- a
+++ a
@@ -1 +1 @@
-one
+two
--- b
+++ b
@@ -1 +1 @@
-three
+four
EOF
echo one > a
echo three > b
check 'patch -p0 < ab.diff' <<EOF
patching file a
patching file b
EOF
# ==============================================================
check 'patch -p0 -f < ab.diff || echo "Status: $?"' <<EOF
patching file a
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file a.rej
patching file b
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file b.rej
Status: 1
EOF
check 'cat a.rej' <<EOF
--- a
+++ a
@@ -1 +1 @@
-one
+two
EOF
check 'cat b.rej' <<EOF
--- b
+++ b
@@ -1 +1 @@
-three
+four
EOF
check 'patch -p0 -f -r ab.rej < ab.diff || echo "Status: $?"' <<EOF
patching file a
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file ab.rej
patching file b
Hunk #1 FAILED at 1.
1 out of 1 hunk FAILED -- saving rejects to file ab.rej
Status: 1
EOF
check 'cat ab.rej' <<EOF
--- a
+++ a
@@ -1 +1 @@
-one
+two
--- b
+++ b
@@ -1 +1 @@
-three
+four
EOF

35
util.c
View File

@ -294,19 +294,14 @@ create_file (char const *file, int open_flags, mode_t mode)
return fd;
}
/* Copy a file. */
void
copy_file (char const *from, char const *to, struct stat *tost,
int to_flags, mode_t mode)
static void
copy_to_fd (const char *from, int tofd)
{
int tofd;
int fromfd;
size_t i;
if ((fromfd = open (from, O_RDONLY | O_BINARY)) < 0)
pfatal ("Can't reopen file %s", quotearg (from));
tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode);
while ((i = read (fromfd, buf, bufsize)) != 0)
{
if (i == (size_t) -1)
@ -316,11 +311,37 @@ copy_file (char const *from, char const *to, struct stat *tost,
}
if (close (fromfd) != 0)
read_fatal ();
}
/* Copy a file. */
void
copy_file (char const *from, char const *to, struct stat *tost,
int to_flags, mode_t mode)
{
int tofd;
tofd = create_file (to, O_WRONLY | O_BINARY | to_flags, mode);
copy_to_fd (from, tofd);
if ((tost && fstat (tofd, tost) != 0)
|| close (tofd) != 0)
write_fatal ();
}
/* Append to file. */
void
append_to_file (char const *from, char const *to)
{
int tofd;
if ((tofd = open (to, O_WRONLY | O_BINARY | O_APPEND)) < 0)
pfatal ("Can't reopen file %s", quotearg (to));
copy_to_fd (from, tofd);
if (close (tofd) != 0)
write_fatal ();
}
static char const DEV_NULL[] = NULL_DEVICE;
static char const RCSSUFFIX[] = ",v";

1
util.h
View File

@ -47,6 +47,7 @@ int systemic (char const *);
char *format_linenum (char[LINENUM_LENGTH_BOUND + 1], LINENUM);
void Fseek (FILE *, file_offset, int);
void copy_file (char const *, char const *, struct stat *, int, mode_t);
void append_to_file (char const *, char const *);
void exit_with_signal (int) __attribute__ ((noreturn));
void ignore_signals (void);
void init_backup_hash_table (void);