aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cmd/zfs/zfs_main.c5
-rw-r--r--include/libzfs.h7
-rw-r--r--lib/libzfs/libzfs_diff.c10
-rw-r--r--lib/libzfs/libzfs_impl.h1
-rw-r--r--man/man8/zfs-diff.86
-rw-r--r--tests/runfiles/common.run2
-rw-r--r--tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am1
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh4
-rwxr-xr-xtests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh48
9 files changed, 74 insertions, 10 deletions
diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c
index c43951d82..d5d181768 100644
--- a/cmd/zfs/zfs_main.c
+++ b/cmd/zfs/zfs_main.c
@@ -7664,7 +7664,7 @@ zfs_do_diff(int argc, char **argv)
int c;
struct sigaction sa;
- while ((c = getopt(argc, argv, "FHt")) != -1) {
+ while ((c = getopt(argc, argv, "FHth")) != -1) {
switch (c) {
case 'F':
flags |= ZFS_DIFF_CLASSIFY;
@@ -7675,6 +7675,9 @@ zfs_do_diff(int argc, char **argv)
case 't':
flags |= ZFS_DIFF_TIMESTAMP;
break;
+ case 'h':
+ flags |= ZFS_DIFF_NO_MANGLE;
+ break;
default:
(void) fprintf(stderr,
gettext("invalid option '%c'\n"), optopt);
diff --git a/include/libzfs.h b/include/libzfs.h
index 53a778f7b..e135ae2ee 100644
--- a/include/libzfs.h
+++ b/include/libzfs.h
@@ -835,9 +835,10 @@ _LIBZFS_H int zfs_receive(libzfs_handle_t *, const char *, nvlist_t *,
recvflags_t *, int, avl_tree_t *);
typedef enum diff_flags {
- ZFS_DIFF_PARSEABLE = 0x1,
- ZFS_DIFF_TIMESTAMP = 0x2,
- ZFS_DIFF_CLASSIFY = 0x4
+ ZFS_DIFF_PARSEABLE = 1 << 0,
+ ZFS_DIFF_TIMESTAMP = 1 << 1,
+ ZFS_DIFF_CLASSIFY = 1 << 2,
+ ZFS_DIFF_NO_MANGLE = 1 << 3
} diff_flags_t;
_LIBZFS_H int zfs_show_diffs(zfs_handle_t *, int, const char *, const char *,
diff --git a/lib/libzfs/libzfs_diff.c b/lib/libzfs/libzfs_diff.c
index d46e23a2f..b721a9fd9 100644
--- a/lib/libzfs/libzfs_diff.c
+++ b/lib/libzfs/libzfs_diff.c
@@ -176,8 +176,13 @@ print_what(FILE *fp, mode_t what)
static void
print_cmn(FILE *fp, differ_info_t *di, const char *file)
{
- stream_bytes(fp, di->dsmnt);
- stream_bytes(fp, file);
+ if (!di->no_mangle) {
+ stream_bytes(fp, di->dsmnt);
+ stream_bytes(fp, file);
+ } else {
+ (void) fputs(di->dsmnt, fp);
+ (void) fputs(file, fp);
+ }
}
static void
@@ -752,6 +757,7 @@ zfs_show_diffs(zfs_handle_t *zhp, int outfd, const char *fromsnap,
di.scripted = (flags & ZFS_DIFF_PARSEABLE);
di.classify = (flags & ZFS_DIFF_CLASSIFY);
di.timestamped = (flags & ZFS_DIFF_TIMESTAMP);
+ di.no_mangle = (flags & ZFS_DIFF_NO_MANGLE);
di.outputfd = outfd;
di.datafd = pipefd[0];
diff --git a/lib/libzfs/libzfs_impl.h b/lib/libzfs/libzfs_impl.h
index b1cf4f825..33b3feed4 100644
--- a/lib/libzfs/libzfs_impl.h
+++ b/lib/libzfs/libzfs_impl.h
@@ -232,6 +232,7 @@ typedef struct differ_info {
boolean_t scripted;
boolean_t classify;
boolean_t timestamped;
+ boolean_t no_mangle;
uint64_t shares;
int zerr;
int cleanupfd;
diff --git a/man/man8/zfs-diff.8 b/man/man8/zfs-diff.8
index 49443bf47..a347f3252 100644
--- a/man/man8/zfs-diff.8
+++ b/man/man8/zfs-diff.8
@@ -39,7 +39,7 @@
.Sh SYNOPSIS
.Nm zfs
.Cm diff
-.Op Fl FHt
+.Op Fl FHth
.Ar snapshot Ar snapshot Ns | Ns Ar filesystem
.
.Sh DESCRIPTION
@@ -92,6 +92,10 @@ Give more parsable tab-separated output, without header lines and without
arrows.
.It Fl t
Display the path's inode change time as the first column of output.
+.It Fl h
+Do not
+.Sy \e0 Ns Ar ooo Ns -escape
+non-ASCII paths.
.El
.
.Sh SEE ALSO
diff --git a/tests/runfiles/common.run b/tests/runfiles/common.run
index 89cd58c2a..d5052172d 100644
--- a/tests/runfiles/common.run
+++ b/tests/runfiles/common.run
@@ -179,7 +179,7 @@ tags = ['functional', 'cli_root', 'zfs_destroy']
[tests/functional/cli_root/zfs_diff]
tests = ['zfs_diff_changes', 'zfs_diff_cliargs', 'zfs_diff_timestamp',
- 'zfs_diff_types', 'zfs_diff_encrypted']
+ 'zfs_diff_types', 'zfs_diff_encrypted', 'zfs_diff_mangle']
tags = ['functional', 'cli_root', 'zfs_diff']
[tests/functional/cli_root/zfs_get]
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am
index db90e0585..bfb01dcb8 100644
--- a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/Makefile.am
@@ -8,6 +8,7 @@ dist_pkgdata_SCRIPTS = \
zfs_diff_changes.ksh \
zfs_diff_cliargs.ksh \
zfs_diff_encrypted.ksh \
+ zfs_diff_mangle.ksh \
zfs_diff_timestamp.ksh \
zfs_diff_types.ksh
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh
index 7063bbe9c..67eb18fa4 100755
--- a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_cliargs.ksh
@@ -39,8 +39,8 @@ function cleanup
log_assert "'zfs diff' should only work with supported options."
log_onexit cleanup
-typeset goodopts=("" "-F" "-H" "-t" "-FH" "-Ft" "-Ht" "-FHt")
-typeset badopts=("-f" "-h" "-h" "-T" "-Fx" "-Ho" "-tT" "-")
+typeset goodopts=("" "-h" "-t" "-th" "-H" "-Hh" "-Ht" "-Hth" "-F" "-Fh" "-Ft" "-Fth" "-FH" "-FHh" "-FHt" "-FHth")
+typeset badopts=("-f" "-T" "-Fx" "-Ho" "-tT" "-")
DATASET="$TESTPOOL/$TESTFS"
TESTSNAP1="$DATASET@snap1"
diff --git a/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh
new file mode 100755
index 000000000..ffce9f068
--- /dev/null
+++ b/tests/zfs-tests/tests/functional/cli_root/zfs_diff/zfs_diff_mangle.ksh
@@ -0,0 +1,48 @@
+#!/bin/ksh -p
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source. A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+. $STF_SUITE/include/libtest.shlib
+
+#
+# DESCRIPTION:
+# 'zfs diff' escapes filenames as expected, 'zfs diff -h' doesn't
+#
+# STRATEGY:
+# 1. Prepare a dataset
+# 2. Create some files
+# 3. verify 'zfs diff' mangles them and 'zfs diff -h' doesn't
+#
+
+verify_runnable "both"
+
+function cleanup
+{
+ log_must zfs destroy -r "$DATASET"
+}
+
+log_assert "'zfs diff' mangles filenames, 'zfs diff -h' doesn't"
+log_onexit cleanup
+
+DATASET="$TESTPOOL/$TESTFS/fs"
+TESTSNAP1="$DATASET@snap1"
+
+# 1. Prepare a dataset
+log_must zfs create "$DATASET"
+MNTPOINT="$(get_prop mountpoint "$DATASET")"
+log_must zfs snapshot "$TESTSNAP1"
+
+printf '%c\t'"$MNTPOINT/"'%s\n' M '' + 'śmieszny żupan' + 'достопримечательности' | sort > "$MNTPOINT/śmieszny żupan"
+printf '%c\t'"$MNTPOINT/"'%s\n' M '' + '\0305\0233mieszny\0040\0305\0274upan' + '\0320\0264\0320\0276\0321\0201\0321\0202\0320\0276\0320\0277\0321\0200\0320\0270\0320\0274\0320\0265\0321\0207\0320\0260\0321\0202\0320\0265\0320\0273\0321\0214\0320\0275\0320\0276\0321\0201\0321\0202\0320\0270' | sort > "$MNTPOINT/достопримечательности"
+log_must diff -u <(zfs diff -h "$TESTSNAP1" | grep -vF '<xattrdir>' | sort) "$MNTPOINT/śmieszny żupan"
+log_must diff -u <(zfs diff "$TESTSNAP1" | grep -vF '<xattrdir>' | sort) "$MNTPOINT/достопримечательности"
+
+log_pass "'zfs diff' mangles filenames, 'zfs diff -h' doesn't"