Subject: Re: bug#7325: new test failure due to non-portability of printf formats like %05.3s

From: Jim Meyering <[email-masked]>
Date: Wed, 10 Nov 2010 10:04:52 +0100

Jim Meyering wrote:

> Paul Eggert wrote:
>
>> On 11/08/10 08:02, Eric Blake wrote:
>>> In fact, since Paul originally wrote utimecmp.c, I'm surprised that you
>>> rewrote the coreutils hash table from scratch rather than trying to
>>> reuse the code.
>>
>> I had vaguely remembered the issue, but I had forgotten where I put
>> that code.  utimecmp.c modifies the time stamp of the files, right?
>> So it might not be a good idea here.  But perhaps some of the common
>> code could be factored out.
>>
>> Getting back to the point: I don't see a problem with 'stat'
>> backward compatibility.
>> The guessed-resolution time stamps are output only if someone uses "%.X",
>> which is a format that nobody would use before the change.  So old
>> scripts shouldn't be broken by the change.
>>
>> So it sounds like the issue is mostly about new scripts.  But for
>
> Yes.
>
>> those, we can tell people not to use "%.X" if they want to do textual
>
> The semantics of this feature feel rather involved for something that
> looks like a simple default.  Some will not read the caveat.
>
>> comparison.  Advice along these lines will be needed no matter what,
>> because, even if we could determine timestamp resolution perfectly,
>> there would still be a problem with blind use of "%.X".  Suppose someone
>> did something like this:
>>
>> 	ts=$(stat -c %.Y $old)
>> 	cp -p $old $new
>> 	# Wait for $new to be modified
>> 	while [ $ts = $(stat -c %.Y $new) ]; do sleep .1; done
>>
>> This won't work as desired even if stat could deduce timestamp resolution
>> perfectly, because $old and $new could be on different file systems,
>> and $new's file system could have a coarser resolution than $old's.
>>
>> I can write a documentation patch along these lines if you like.
>
> Isn't this a good reason to attach the variable-width functionality
> to a less-likely-to-be-(ab)used syntax like "%#.X"?  Then we would put
> that format directive in the default format string, where its output
> is parsed only by humans, and scripts using the shorter %.X
> would be less error prone.

Unless I hear otherwise soon, I'll use something like
the following basis for the proposed change:
(of course, this needs additional tests and probably documentation changes)

diff --git a/src/stat.c b/src/stat.c
index ae7ce02..98b7501 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -550,18 +550,27 @@ out_epoch_sec (char *pformat, size_t prefix_len, struct stat const *statbuf,
       sec_prefix_len = dot - pformat;
       pformat[prefix_len] = '\0';

+      /* %.X   => precision defaults to 9
+         %.5X  => precision is 5
+         %#.X  => precision is determined by fstimeprec
+         %#.3X => precision is 3 (specified overrides "#")  */
+
       if (ISDIGIT (dot[1]))
         {
           long int lprec = strtol (dot + 1, NULL, 10);
           precision = (lprec <= INT_MAX ? lprec : INT_MAX);
         }
-      else
+      else if (memchr (pformat, '#', dot - pformat))
         {
           static struct fstimeprec *tab;
           if (! tab)
             tab = fstimeprec_alloc ();
           precision = fstimeprec (tab, statbuf);
         }
+      else
+        {
+          precision = 9;
+        }

       if (precision && ISDIGIT (dot[-1]))
         {