This is safer to output to terminal with malicious file names,
with multiple lines or control characters etc.

* src/stat.c: Quote the file name in the default output format
in the default quoting style, or as selected with QUOTING_STYLE.
Reported by Michał Majchrowicz and Marcin Wyczechowski.
---
 src/stat.c             | 18 ++++++------------
 tests/stat/stat-fmt.sh |  7 +++++++
 2 files changed, 13 insertions(+), 12 deletions(-)

diff --git a/src/stat.c b/src/stat.c
index e682bc6b9..a159d1358 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -1050,6 +1050,11 @@ neg_to_zero (struct timespec ts)
 static void
 getenv_quoting_style (void)
 {
+  static bool got_quoting_style;
+  if (got_quoting_style)
+    return;
+  got_quoting_style = true;
+
   char const *q_style = getenv ("QUOTING_STYLE");
   if (q_style)
     {
@@ -1515,6 +1520,7 @@ print_stat (char *pformat, size_t prefix_len, char mod, 
char m,
       out_string (pformat, prefix_len, filename);
       break;
     case 'N':
+      getenv_quoting_style ();
       out_string (pformat, prefix_len, quoteN (filename));
       if (S_ISLNK (statbuf->st_mode))
         {
@@ -1970,18 +1976,6 @@ main (int argc, char *argv[])
 
   if (format)
     {
-      bool need_quoting_style = false;
-      for (char const *p = format; (p = strchr (p, '%'));
-           p += (p[1] == '%') + 1)
-        {
-          if (p[1] == 'N')
-            {
-              need_quoting_style = true;
-              break;
-            }
-        }
-      if (need_quoting_style)
-        getenv_quoting_style ();
       format2 = format;
     }
   else
diff --git a/tests/stat/stat-fmt.sh b/tests/stat/stat-fmt.sh
index 11cc09bc9..364516582 100755
--- a/tests/stat/stat-fmt.sh
+++ b/tests/stat/stat-fmt.sh
@@ -53,6 +53,13 @@ cat <<\EOF >exp
 EOF
 compare exp out || fail=1
 
+# ensure control characters in file names are escaped by default
+stat "$fname" | grep 'File: ' > out || fail=1
+cat <<\EOF >exp
+  File: 'a'$'\n\n''b'$'\n''c'
+EOF
+compare exp out || fail=1
+
 # Check the behavior with invalid values of QUOTING_STYLE.
 for style in '' 'abcdef'; do
   QUOTING_STYLE="$style" stat -c%%%N \' > out 2> err || fail=1
-- 
2.54.0


Reply via email to