summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruen@suse.de>2010-04-29 14:19:13 +0200
committerAndreas Gruenbacher <agruen@suse.de>2010-05-02 11:44:03 +0200
commitb68294e3e1177bcf98d6d23f90ef3e6b5576af2a (patch)
tree2f6fcca8d1579115dd4467689f66f7563511a7c4
parentf9db7450fa2788377c4567b5d0565b0ddfc1015c (diff)
downloadpatch-b68294e3e1177bcf98d6d23f90ef3e6b5576af2a.tar.gz
git diffs: Support file mode changes
* src/patch.c (main): When a git diff includes a file mode change, change to the new mode. * src/util.c (set_file_attributes): Add a mode parameter. * tests/file-modes: New test case. * tests/Makefile.am (TESTS): Add test case.
-rw-r--r--ChangeLog6
-rw-r--r--src/patch.c13
-rw-r--r--src/util.c10
-rw-r--r--src/util.h2
-rw-r--r--tests/Makefile.am1
-rw-r--r--tests/file-modes84
6 files changed, 107 insertions, 9 deletions
diff --git a/ChangeLog b/ChangeLog
index 05fa61e..9b4f7a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2009-04-29 Andreas Gruenbacher <agruen@suse.de>
+ * src/patch.c (main): When a git diff includes a file mode change,
+ change to the new mode.
+ * src/util.c (set_file_attributes): Add a mode parameter.
+ * tests/file-modes: New test case.
+ * tests/Makefile.am (TESTS): Add test case.
+
* src/patch.c (main): Support git symlink diffs.
* tests/symlinks: Add git symlink diff test cases.
diff --git a/src/patch.c b/src/patch.c
index 741ad79..07913bb 100644
--- a/src/patch.c
+++ b/src/patch.c
@@ -406,12 +406,17 @@ main (int argc, char **argv)
if (! dry_run)
{
+ mode_t old_mode = pch_mode (reverse);
+ mode_t new_mode = pch_mode (! reverse);
+ bool set_mode = new_mode && old_mode != new_mode;
+
/* Avoid replacing files when nothing has changed. */
- if (failed < hunk || diff_type == ED_DIFF)
+ if (failed < hunk || diff_type == ED_DIFF || set_mode)
{
enum file_attributes attr = FA_IDS | FA_MODE;
struct timespec new_time = pch_timestamp (! reverse);
- mode_t mode = file_type | (instat.st_mode & S_IRWXUGO);
+ mode_t mode = file_type |
+ ((new_mode ? new_mode : instat.st_mode) & S_IRWXUGO);
move_file (TMPOUTNAME, &TMPOUTNAME_needs_removal, &outst,
outname, mode, backup);
@@ -437,9 +442,9 @@ main (int argc, char **argv)
}
if (! inerrno)
- set_file_attributes (outname, attr, &instat, &new_time);
+ set_file_attributes (outname, attr, &instat, mode, &new_time);
}
- else
+ else if (backup)
create_backup (outname, 0, 0, true);
}
}
diff --git a/src/util.c b/src/util.c
index 70edbb3..c21828b 100644
--- a/src/util.c
+++ b/src/util.c
@@ -124,7 +124,7 @@ contains_slash (const char *s)
void
set_file_attributes (char const *to, enum file_attributes attr,
- struct stat *st, struct timespec *new_time)
+ struct stat *st, mode_t mode, struct timespec *new_time)
{
if (attr & FA_TIMES)
{
@@ -171,10 +171,12 @@ set_file_attributes (char const *to, enum file_attributes attr,
}
if (attr & FA_MODE)
{
+ if (! mode)
+ mode = st->st_mode;
#ifdef HAVE_LCHMOD
- if (lchmod (to, st->st_mode))
+ if (lchmod (to, mode))
#else
- if (! S_ISLNK (st->st_mode) && chmod (to, st->st_mode) != 0)
+ if (! S_ISLNK (mode) && chmod (to, mode) != 0)
#endif
pfatal ("Failed to set the permissions of %s %s",
S_ISLNK (st->st_mode) ? "symbolic link" : "file",
@@ -188,7 +190,7 @@ create_backup_copy (char const *from, char const *to, struct stat *st,
bool to_dir_known_to_exist)
{
copy_file (from, to, 0, 0, st->st_mode, to_dir_known_to_exist);
- set_file_attributes (to, FA_TIMES | FA_IDS | FA_MODE, st, NULL);
+ set_file_attributes (to, FA_TIMES | FA_IDS | FA_MODE, st, 0, NULL);
}
void
diff --git a/src/util.h b/src/util.h
index a48399a..609aa26 100644
--- a/src/util.h
+++ b/src/util.h
@@ -71,7 +71,7 @@ enum file_attributes {
};
void set_file_attributes (char const *, enum file_attributes, struct stat *,
- struct timespec *);
+ mode_t, struct timespec *);
static inline char const *
skip_spaces (char const *str)
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 3df2e74..af30156 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -23,6 +23,7 @@ TESTS = \
create-delete \
crlf-handling \
dash-o-append \
+ file-modes \
filename-choice \
git-binary-diff \
global-reject-files \
diff --git a/tests/file-modes b/tests/file-modes
new file mode 100644
index 0000000..9da184a
--- /dev/null
+++ b/tests/file-modes
@@ -0,0 +1,84 @@
+# Copyright (C) 2010 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.
+
+# Test if git diffs can change file modes
+
+. $srcdir/test-lib.sh
+
+require_cat
+require_diff
+use_local_patch
+use_tmpdir
+
+# ==============================================================
+
+cat > f.diff <<EOF
+diff --git a/f b/f
+old mode 100644
+new mode 100600
+--- a/f
++++ a/f
+@@ -1 +1 @@
+-old
++new
+
+diff --git a/g b/g
+old mode 100644
+new mode 100600
+--- a/g
++++ a/g
+@@ -1 +1 @@
+-old
++new
+
+EOF
+
+echo old > f
+echo old > g
+chmod 644 f g
+
+check 'patch -p1 < f.diff' <<EOF
+patching file f
+patching file g
+EOF
+
+check 'ls -l f g | sed "s,\(..........\).*,\1,"' <<EOF
+-rw-------
+-rw-------
+EOF
+
+check 'patch -p1 -R < f.diff' <<EOF
+patching file f
+patching file g
+EOF
+
+check 'ls -l f g | sed "s,\(..........\).*,\1,"' <<EOF
+-rw-r--r--
+-rw-r--r--
+EOF
+
+cat > g.diff <<EOF
+diff --git a/f b/f
+old mode 100644
+new mode 100600
+
+diff --git a/g b/g
+old mode 100644
+new mode 100600
+
+EOF
+
+chmod 600 f
+chmod 644 g
+check 'patch -p1 < g.diff || echo "Status: $?"' <<EOF
+patching file f
+patching file g
+EOF
+
+check 'ls -l f g | sed "s,\(..........\).*,\1,"' <<EOF
+-rw-------
+-rw-------
+EOF