summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2017-06-10 03:02:39 -0400
committerTavian Barnes <tavianator@tavianator.com>2017-06-10 03:02:39 -0400
commita3faa73f03a4d539de4c808d1a4f3b8ebc5ce537 (patch)
treef64b21a1459e4b9774cd27a888dd66a1ec0cdce6
parenta6c25c7c74f762cb40639da0b9b98bfcf3f4c590 (diff)
downloadbfs-a3faa73f03a4d539de4c808d1a4f3b8ebc5ce537.tar.xz
printf: Fix embedded nul bytes
Fixes #26.
-rw-r--r--dstring.c4
-rw-r--r--dstring.h11
-rw-r--r--printf.c27
-rwxr-xr-xtests.sh6
-rw-r--r--tests/test_printf_nul.outbin0 -> 198 bytes
5 files changed, 37 insertions, 11 deletions
diff --git a/dstring.c b/dstring.c
index 5a6d4b3..54815d6 100644
--- a/dstring.c
+++ b/dstring.c
@@ -95,6 +95,10 @@ int dstrncat(char **dest, const char *src, size_t n) {
return dstrcat_impl(dest, src, strnlen(src, n));
}
+int dstrapp(char **str, char c) {
+ return dstrcat_impl(str, &c, 1);
+}
+
void dstrfree(char *dstr) {
if (dstr) {
free(dstrheader(dstr));
diff --git a/dstring.h b/dstring.h
index cd867ad..318bb0b 100644
--- a/dstring.h
+++ b/dstring.h
@@ -78,6 +78,17 @@ int dstrcat(char **dest, const char *src);
int dstrncat(char **dest, const char *src, size_t n);
/**
+ * Append a single character to a dynamic string.
+ *
+ * @param str
+ * The string to append to.
+ * @param c
+ * The character to append.
+ * @return 0 on success, -1 on failure.
+ */
+int dstrapp(char **str, char c);
+
+/**
* Free a dynamic string.
*
* @param dstr
diff --git a/printf.c b/printf.c
index 33753e3..888fecb 100644
--- a/printf.c
+++ b/printf.c
@@ -48,7 +48,12 @@ struct bfs_printf_directive {
/** Print some text as-is. */
static int bfs_printf_literal(FILE *file, const struct bfs_printf_directive *directive, const struct BFTW *ftwbuf) {
- return fprintf(file, "%s", directive->str);
+ size_t len = dstrlen(directive->str);
+ if (fwrite(directive->str, 1, len, file) == len) {
+ return 0;
+ } else {
+ return -1;
+ }
}
/** \c: flush */
@@ -517,8 +522,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
if (!directive) {
goto directive_error;
}
- if (dstrncat(&directive->str, &c, 1) != 0) {
- perror("dstralloc()");
+ if (dstrapp(&directive->str, c) != 0) {
+ perror("dstrapp()");
goto directive_error;
}
@@ -540,8 +545,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
cfprintf(cerr, "%{er}error: '%s': Duplicate flag '%c'.%{rs}\n", format, c);
goto directive_error;
}
- if (dstrncat(&directive->str, &c, 1) != 0) {
- perror("dstrncat()");
+ if (dstrapp(&directive->str, c) != 0) {
+ perror("dstrapp()");
goto directive_error;
}
continue;
@@ -552,8 +557,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
// Parse the field width
while (c >= '0' && c <= '9') {
- if (dstrncat(&directive->str, &c, 1) != 0) {
- perror("dstrncat()");
+ if (dstrapp(&directive->str, c) != 0) {
+ perror("dstrapp()");
goto directive_error;
}
c = *++i;
@@ -562,8 +567,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
// Parse the precision
if (c == '.') {
do {
- if (dstrncat(&directive->str, &c, 1) != 0) {
- perror("dstrncat()");
+ if (dstrapp(&directive->str, c) != 0) {
+ perror("dstrapp()");
goto directive_error;
}
c = *++i;
@@ -774,8 +779,8 @@ struct bfs_printf *parse_bfs_printf(const char *format, struct cmdline *cmdline)
}
one_char:
- if (dstrncat(&literal->str, &c, 1) != 0) {
- perror("dstrncat()");
+ if (dstrapp(&literal->str, c) != 0) {
+ perror("dstrapp()");
goto error;
}
}
diff --git a/tests.sh b/tests.sh
index a07ae8a..ef4bbfc 100755
--- a/tests.sh
+++ b/tests.sh
@@ -302,6 +302,7 @@ gnu_tests=(
test_printf_escapes
test_printf_times
test_printf_leak
+ test_printf_nul
test_quit_after_print
test_quit_before_print
test_fstype
@@ -1036,6 +1037,11 @@ function test_printf_leak() {
bfs_diff basic -maxdepth 0 -printf '%p'
}
+function test_printf_nul() {
+ # NUL byte regression test
+ bfs_diff basic -printf '%h\0%f\n'
+}
+
function test_fstype() {
fstype="$($BFS -printf '%F\n' | head -n1)"
bfs_diff basic -fstype "$fstype"
diff --git a/tests/test_printf_nul.out b/tests/test_printf_nul.out
new file mode 100644
index 0000000..3e30a4f
--- /dev/null
+++ b/tests/test_printf_nul.out
Binary files differ