summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Blake <eblake@redhat.com>2010-09-30 16:42:13 -0600
committerEric Blake <eblake@redhat.com>2010-10-01 10:43:41 -0600
commit9069af45e691d1252c727da66aa4f3f3c7f1ea29 (patch)
tree09371cf730f26806f6a45703e3b4989afff0f439
parentabe5c1f9bc09753fd79e7a121c8ecfa917dfaddb (diff)
downloadcoreutils-9069af45e691d1252c727da66aa4f3f3c7f1ea29.tar.xz
stat: print timestamps to full resolution
* src/stat.c (epoch_time): New function. (print_stat): Use it for %[WXYZ]. * NEWS: Document this. * tests/touch/60-seconds: Adjust test to match. * tests/misc/stat-birthtime: Likewise.
-rw-r--r--NEWS5
-rw-r--r--src/stat.c39
-rwxr-xr-xtests/misc/stat-birthtime3
-rwxr-xr-xtests/touch/60-seconds2
4 files changed, 31 insertions, 18 deletions
diff --git a/NEWS b/NEWS
index 0c7cc38d1..2ce03e312 100644
--- a/NEWS
+++ b/NEWS
@@ -75,6 +75,11 @@ GNU coreutils NEWS -*- outline -*-
merely accepted and ignored, for compatibility. Starting two years
ago, with coreutils-7.0, its use evoked a warning.
+ stat now outputs the full sub-second resolution for the atime,
+ mtime, and ctime values since the Epoch, when using the %X, %Y, and
+ %Z directives of the --format option. This matches the fact that
+ %x, %y, and %z were already doing so for the human-readable variant.
+
touch's --file option is no longer recognized. Use --reference=F (-r)
instead. --file has not been documented for 15 years, and its use has
elicited a warning since coreutils-7.1.
diff --git a/src/stat.c b/src/stat.c
index e1d68a556..6b2e99b77 100644
--- a/src/stat.c
+++ b/src/stat.c
@@ -461,6 +461,26 @@ human_time (struct timespec t)
return str;
}
+static char * ATTRIBUTE_WARN_UNUSED_RESULT
+epoch_time (struct timespec t)
+{
+ static char str[INT_STRLEN_BOUND (time_t) + sizeof ".NNNNNNNNN"];
+ /* Note that time_t can technically be a floating point value, such
+ that casting to [u]intmax_t could lose a fractional value or
+ suffer from overflow. However, most porting targets have an
+ integral time_t; also, we know of no file systems that store
+ valid time values outside the bounds of intmax_t even if that
+ value were represented as a floating point. Besides, the cost of
+ converting to struct tm just to use nstrftime (str, len, "%s.%N",
+ tm, 0, t.tv_nsec) is pointless, since nstrftime would have to
+ convert back to seconds as time_t. */
+ if (TYPE_SIGNED (time_t))
+ sprintf (str, "%" PRIdMAX ".%09ld", (intmax_t) t.tv_sec, t.tv_nsec);
+ else
+ sprintf (str, "%" PRIuMAX ".%09ld", (uintmax_t) t.tv_sec, t.tv_nsec);
+ return str;
+}
+
static void
out_string (char *pformat, size_t prefix_len, char const *arg)
{
@@ -802,38 +822,27 @@ print_stat (char *pformat, size_t prefix_len, char m,
struct timespec t = get_stat_birthtime (statbuf);
if (t.tv_nsec < 0)
out_string (pformat, prefix_len, "-");
- else if (TYPE_SIGNED (time_t))
- out_int (pformat, prefix_len, t.tv_sec);
else
- out_uint (pformat, prefix_len, t.tv_sec);
+ out_string (pformat, prefix_len, epoch_time (t));
}
break;
case 'x':
out_string (pformat, prefix_len, human_time (get_stat_atime (statbuf)));
break;
case 'X':
- if (TYPE_SIGNED (time_t))
- out_int (pformat, prefix_len, statbuf->st_atime);
- else
- out_uint (pformat, prefix_len, statbuf->st_atime);
+ out_string (pformat, prefix_len, epoch_time (get_stat_atime (statbuf)));
break;
case 'y':
out_string (pformat, prefix_len, human_time (get_stat_mtime (statbuf)));
break;
case 'Y':
- if (TYPE_SIGNED (time_t))
- out_int (pformat, prefix_len, statbuf->st_mtime);
- else
- out_uint (pformat, prefix_len, statbuf->st_mtime);
+ out_string (pformat, prefix_len, epoch_time (get_stat_mtime (statbuf)));
break;
case 'z':
out_string (pformat, prefix_len, human_time (get_stat_ctime (statbuf)));
break;
case 'Z':
- if (TYPE_SIGNED (time_t))
- out_int (pformat, prefix_len, statbuf->st_ctime);
- else
- out_uint (pformat, prefix_len, statbuf->st_ctime);
+ out_string (pformat, prefix_len, epoch_time (get_stat_ctime (statbuf)));
break;
case 'C':
fail |= out_file_context (filename, pformat, prefix_len);
diff --git a/tests/misc/stat-birthtime b/tests/misc/stat-birthtime
index b54268c11..38e5d5947 100755
--- a/tests/misc/stat-birthtime
+++ b/tests/misc/stat-birthtime
@@ -28,8 +28,7 @@ ctime=$(stat --format %Z a) || fail=1
case $(stat --format %x a) in
*.000000000*) sleep 2;; # worst case file system is FAT
- *) # FIXME: sleep .1 would be sufficient if %X is fixed to show nanoseconds
- sleep 1;;
+ *) sleep .02;; # should be adequate for any system with subsecond resolution
esac
touch a || fail=1
diff --git a/tests/touch/60-seconds b/tests/touch/60-seconds
index f858a309a..f98f0c5d1 100755
--- a/tests/touch/60-seconds
+++ b/tests/touch/60-seconds
@@ -23,7 +23,7 @@ fi
. $srcdir/test-lib.sh
-echo 60 > exp || framework_failure
+echo 60.000000000 > exp || framework_failure
# Before coreutils-7.7, this would fail, complaining of