Scan the format string to build a STATX_* mask prior to calling statx. This allows us to avoid setting bits for attributes that we don't intend to display, which can mean a much lighter-weight operation on some filesystems.
* src/stat.c: only set STATX_* mask bits for things we want to print --- src/stat.c | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 79 insertions(+), 2 deletions(-) diff --git a/src/stat.c b/src/stat.c index 264e9138cdc9..2bbc75792b5a 100644 --- a/src/stat.c +++ b/src/stat.c @@ -1370,6 +1370,84 @@ print_statx (char *pformat, size_t prefix_len, unsigned int m, return fail; } +static unsigned int +fmt_to_mask(char fmt) +{ + switch(fmt) + { + case 'N': + return STATX_MODE|STATX_SIZE; + case 'd': + case 'D': + return STATX_MODE; + case 'i': + return STATX_INO; + case 'a': + case 'A': + return STATX_MODE; + case 'f': + return STATX_MODE|STATX_TYPE; + case 'F': + return STATX_TYPE; + case 'h': + return STATX_NLINK; + case 'u': + case 'U': + return STATX_UID; + case 'g': + case 'G': + return STATX_GID; + case 'm': + return STATX_MODE|STATX_INO; + case 's': + return STATX_SIZE; + case 't': + case 'T': + return STATX_MODE; + case 'b': + return STATX_BLOCKS; + case 'w': + case 'W': + return STATX_BTIME; + case 'x': + case 'X': + return STATX_ATIME; + case 'y': + case 'Y': + return STATX_MTIME; + case 'z': + case 'Z': + return STATX_CTIME; + } + return 0; +} + +static unsigned int __attribute__((const)) +format_to_mask(char const *format) +{ + unsigned int mask = 0; + char const *b; + + for (b = format; *b; b++) + { + if (*b != '%') + continue; + + size_t len = strspn (b + 1, printf_flags); + char const *fmt_char = b + len + 1; + fmt_char += strspn (fmt_char, digits); + if (*fmt_char == '.') + fmt_char += 1 + strspn (fmt_char + 1, digits); + char fmt_code = *fmt_char; + + b = fmt_char; + if (fmt_code == '\0') + break; + mask |= fmt_to_mask(fmt_code); + } + return mask; +} + /* statx the file and print what we find */ static bool ATTRIBUTE_WARN_UNUSED_RESULT do_stat (char const *filename, char const *format, char const *format2) @@ -1394,8 +1472,7 @@ do_stat (char const *filename, char const *format, char const *format2) flags = AT_SYMLINK_NOFOLLOW; } - /* FIXME: set request mask based on format */ - fd = statx(fd, pathname, flags, STATX_BASIC_STATS|STATX_BTIME, &stx); + fd = statx(fd, pathname, flags, format_to_mask(format), &stx); if (fd < 0) { if (flags & AT_EMPTY_PATH) -- 2.20.1