getdents, getdents64: quote filenames

* dirent.c (print_old_dirent): Fix quoting.
(sys_getdents): Print d_name using print_quoted_string.
(sys_getdents64): Likewise.
* tests/getdents.test: Test it.
* tests/getdents.awk: Update.
diff --git a/dirent.c b/dirent.c
index cbebdb7..d30e0d2 100644
--- a/dirent.c
+++ b/dirent.c
@@ -1,6 +1,8 @@
 #include "defs.h"
 #include <dirent.h>
 
+#define D_NAME_LEN_MAX 256
+
 struct kernel_dirent {
 	unsigned long   d_ino;
 	unsigned long   d_off;
@@ -28,12 +30,12 @@
 		return;
 	}
 
-	tprintf("{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=\"",
+	tprintf("{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
 		(unsigned long) d.d_ino, (unsigned long) d.d_off, d.d_reclen);
-	if (d.d_reclen > 256)
-		d.d_reclen = 256;
+	if (d.d_reclen > D_NAME_LEN_MAX)
+		d.d_reclen = D_NAME_LEN_MAX;
 	printpathn(tcp, addr + offsetof(old_dirent_t, d_name), d.d_reclen);
-	tprints("\"}");
+	tprints("}");
 }
 
 int
@@ -103,11 +105,18 @@
 				  i + d->d_reclen - 1 >= len;
 			int d_name_len = oob ? len - i : d->d_reclen;
 			d_name_len -= offsetof(struct kernel_dirent, d_name) + 1;
+			if (d_name_len > D_NAME_LEN_MAX)
+				d_name_len = D_NAME_LEN_MAX;
 
-			tprintf("%s{d_ino=%lu, d_off=%lu, ",
-				i ? " " : "", d->d_ino, d->d_off);
-			tprintf("d_reclen=%u, d_name=\"%.*s\", d_type=",
-				d->d_reclen, d_name_len, d->d_name);
+			tprintf("%s{d_ino=%lu, d_off=%lu, d_reclen=%u, d_name=",
+				i ? " " : "", d->d_ino, d->d_off, d->d_reclen);
+
+			if (print_quoted_string(d->d_name, d_name_len,
+					        QUOTE_0_TERMINATED) > 0) {
+				tprints("...");
+			}
+
+			tprints(", d_type=");
 			if (oob)
 				tprints("?");
 			else
@@ -182,6 +191,8 @@
 			} else {
 				d_name_len = len - i - d_name_offset;
 			}
+			if (d_name_len > D_NAME_LEN_MAX)
+				d_name_len = D_NAME_LEN_MAX;
 
 			tprintf("%s{d_ino=%" PRIu64 ", d_off=%" PRId64
 				", d_reclen=%u, d_type=",
@@ -190,8 +201,14 @@
 				d->d_off,
 				d->d_reclen);
 			printxval(direnttypes, d->d_type, "DT_???");
-			tprintf(", d_name=\"%.*s\"}",
-				d_name_len, d->d_name);
+
+			tprints(", d_name=");
+			if (print_quoted_string(d->d_name, d_name_len,
+					        QUOTE_0_TERMINATED) > 0) {
+				tprints("...");
+			}
+
+			tprints("}");
 		}
 		if (d->d_reclen < d_name_offset) {
 			tprints("/* d_reclen < offsetof(struct dirent64, d_name) */");
diff --git a/tests/getdents.awk b/tests/getdents.awk
index 686d578..904c5c0 100644
--- a/tests/getdents.awk
+++ b/tests/getdents.awk
@@ -8,17 +8,25 @@
   d_ino = "d_ino=" i
   d_off = "d_off=" i
   d_reclen = "d_reclen=" len
-  d_name1 = "d_name=\"\\.\""
-  d_name2 = "d_name=\"\\.\\.\""
-  d_type = "d_type=DT_DIR"
+  d_name_1 = "d_name=\"\\.\""
+  d_name_2 = "d_name=\"\\.\\.\""
+  d_name_3 = "d_name=\"(A\\\\n){127}Z\""
+  d_type_dir = "d_type=DT_DIR"
+  d_type_reg = "d_type=DT_REG"
 
-  d1_1 = "\\{" d_ino ", " d_off ", " d_reclen ", " d_name1 ", " d_type "\\}"
-  d1_2 = "\\{" d_ino ", " d_off ", " d_reclen ", " d_name2 ", " d_type "\\}"
-  d2_1 = "\\{" d_ino ", " d_off ", " d_reclen ", " d_type ", " d_name1 "\\}"
-  d2_2 = "\\{" d_ino ", " d_off ", " d_reclen ", " d_type ", " d_name2 "\\}"
+  dirent_1   = "\\{" d_ino ", " d_off ", " d_reclen ", " d_name_1 ", " d_type_dir "\\}"
+  dirent_2   = "\\{" d_ino ", " d_off ", " d_reclen ", " d_name_2 ", " d_type_dir "\\}"
+  dirent_3   = "\\{" d_ino ", " d_off ", " d_reclen ", " d_name_3 ", " d_type_reg "\\}"
 
-  getdents   =   "^getdents\\(" i ", \\{(" d1_1 " " d1_2 "|" d1_2 " " d1_1 ")\\}, " len "\\) += " len "$"
-  getdents64 = "^getdents64\\(" i ", \\{(" d2_1 " " d2_2 "|" d2_2 " " d2_1 ")\\}, " len "\\) += " len "$"
+  dirent64_1 = "\\{" d_ino ", " d_off ", " d_reclen ", " d_type_dir ", " d_name_1 "\\}"
+  dirent64_2 = "\\{" d_ino ", " d_off ", " d_reclen ", " d_type_dir ", " d_name_2 "\\}"
+  dirent64_3 = "\\{" d_ino ", " d_off ", " d_reclen ", " d_type_reg ", " d_name_3 "\\}"
+
+  dents   = "\\{(" dirent_1   " " dirent_2   "|" dirent_2   " " dirent_1   ") " dirent_3   "\\}"
+  dents64 = "\\{(" dirent64_1 " " dirent64_2 "|" dirent64_2 " " dirent64_1 ") " dirent64_3 "\\}"
+
+  getdents   =   "^getdents\\(" i ", " dents   ", " len "\\) += " len "$"
+  getdents64 = "^getdents64\\(" i ", " dents64 ", " len "\\) += " len "$"
 }
 
 NR == 1 {if (match($0, getdents) || match($0, getdents64)) next}
diff --git a/tests/getdents.test b/tests/getdents.test
index 5f86ac1..e6f8fee 100755
--- a/tests/getdents.test
+++ b/tests/getdents.test
@@ -5,25 +5,36 @@
 . "${srcdir=.}/init.sh"
 
 check_prog awk
-check_prog grep
 check_prog ls
 check_prog mkdir
-check_prog rmdir
+check_prog rm
+check_prog seq
+check_prog touch
 
-mkdir emptydir ||
-	framework_skip_ 'failed to create an empty directory'
+dir="$LOG.dir"
+mkdir -- "$dir" ||
+	framework_skip_ 'failed to create a directory'
 
-ls emptydir ||
-	{ rmdir emptydir; framework_skip_ 'failed to list an empty directory'; }
+touch -- "$dir/$(for i in $(seq 1 127); do echo A; done; echo Z)" ||
+	framework_skip_ 'failed to create a file'
+
+ls -- "$dir" > /dev/null || {
+	rm -rf -- "$dir"
+	framework_skip_ 'failed to list a directory'
+}
 
 args='-vegetdents,getdents64'
-$STRACE $args -o $LOG ls emptydir
+$STRACE -o "$LOG" $args ls -- "$dir" > /dev/null
 rc=$?
-rmdir emptydir
-[ $rc -eq 0 ] ||
-	{ cat $LOG; fail_ "strace $args failed"; }
+rm -rf -- "$dir"
+[ $rc -eq 0 ] || {
+	cat "$LOG"
+	fail_ "strace $args failed"
+}
 
-awk -f "$srcdir"/getdents.awk $LOG ||
-	{ cat $LOG; fail_ "strace $args failed to trace getdents/getdents64 properly"; }
+awk -f "$srcdir"/getdents.awk "$LOG" || {
+	cat "$LOG"
+	fail_ "strace $args failed to trace getdents/getdents64 properly"
+}
 
 exit 0