On 2019-11-14 17:48, Martin Schulte wrote: > Hello, > > I create files t<n> (n=1,3,5,7) with ctime=now and atime=now+<n> days: > > $ uname -a > $ echo > $ find --version > $ for d in 1 3 5 7; do >> touch -a -d "$(date -d "$d day" '+%Y-%m-%d %H:%M:%S')" t$d >> done > $ echo > $ echo find: > $ find . -name 't?' -used +4 > $ echo done. > > I expect > ./t5 > ./t7 > as output from find but I get nothing: > > Linux martnix4 4.9.0-11-amd64 #1 SMP Debian 4.9.189-3+deb9u1 (2019-09-20) > x86_64 GNU/Linux > > find (GNU findutils) 4.7.0-git > Copyright (C) 2016 Free Software Foundation, Inc. > License GPLv3+: GNU GPL version 3 or later > <http://gnu.org/licenses/gpl.html>. This is free software: you are free > to change and redistribute it. There is NO WARRANTY, to the extent > permitted by law. > > Written by Eric B. Decker, James Youngman, and Kevin Dalley. > Features enabled: D_TYPE O_NOFOLLOW(enabled) LEAF_OPTIMISATION FTS > (FTS_CWDFD) CBO(level=2) > > find: > done. > > Do I misunderstand the man page? If this is a bug, it looks as if > pred_used calls pred_timewindow with a bad second argument (absolute time > iso relative to ctime). > > Best regards, > > Martin
Thank you for the bug report. First of all, I have the impression that the -used predicate may often suffer from 'noatime' or 'relatime' mounts nowadays. Re. the problem: after a quick look at the sources I see 2 problems: a) the 'timespec delta' is reversed. It seems that this bug sneaked somehow in during the introduction of sub-second timestamp resolution back in 2007. b) the function pred_used should return false if atime < ctime. Such a condition has to be added because the -used predicate shall evaluate to true: 1. with "-used -N": if atime is less than N days after ctime. 2. with "-used N": if atime is exactly N days after ctime. 3. with "-used +N": if atime is more than N days after ctime. Therefore, if atime is before ctime, then -used with any argument should evaluate to false. The attached (raw git diff) fixes both. Your test case would then look like the following: $ rm t* # remove because otherwise 'touch' would always also set the ctime. $ for d in 1 3 5 7; do \ touch -a -d "$(date -d "$d day" '+%Y-%m-%d %H:%M:%S')" t$d ; \ done $ stat -c "Name: %n Access: %x Change: %z" t? Name: t1 Access: 2019-11-18 23:04:17.000000000 +0100 Change: 2019-11-17 23:04:17.147805944 +0100 Name: t3 Access: 2019-11-20 23:04:17.000000000 +0100 Change: 2019-11-17 23:04:17.151806001 +0100 Name: t5 Access: 2019-11-22 23:04:17.000000000 +0100 Change: 2019-11-17 23:04:17.155806059 +0100 Name: t7 Access: 2019-11-24 23:04:17.000000000 +0100 Change: 2019-11-17 23:04:17.159806116 +0100 $ for f in -8 -7 -6 -5 -4 -3 -2 -1 -0 0 +0 +1 +2 +3 +4 +5 +6 +7 +8; do \ set -x ; \ find . -type f -used $f; \ { set +x; } 2>/dev/null; \ done + find . -type f -used -8 ./t7 ./t5 ./t3 ./t1 + find . -type f -used -7 ./t7 ./t5 ./t3 ./t1 + find . -type f -used -6 ./t5 ./t3 ./t1 + find . -type f -used -5 ./t5 ./t3 ./t1 + find . -type f -used -4 ./t3 ./t1 + find . -type f -used -3 ./t3 ./t1 + find . -type f -used -2 ./t1 + find . -type f -used -1 ./t1 + find . -type f -used -0 + find . -type f -used 0 + find . -type f -used +0 ./t7 ./t5 ./t3 ./t1 + find . -type f -used +1 ./t7 ./t5 ./t3 + find . -type f -used +2 ./t7 ./t5 ./t3 + find . -type f -used +3 ./t7 ./t5 + find . -type f -used +4 ./t7 ./t5 + find . -type f -used +5 ./t7 + find . -type f -used +6 ./t7 + find . -type f -used +7 + find . -type f -used +8 I'll try to come up with a proper patch - maybe including a test case - in the next few days (although a look into my calendar for this week doesn't leave much hope for this). Have a nice day, Berny
diff --git a/find/pred.c b/find/pred.c index 688103d6..9d7b0a0e 100644 --- a/find/pred.c +++ b/find/pred.c @@ -1166,8 +1166,13 @@ pred_used (const char *pathname, struct stat *stat_buf, struct predicate *pred_p /* TODO: this needs to be retested carefully (manually, if necessary) */ at = get_stat_atime (stat_buf); ct = get_stat_ctime (stat_buf); - delta.tv_sec = at.tv_sec - ct.tv_sec; - delta.tv_nsec = at.tv_nsec - ct.tv_nsec; + + /* Always evaluate to false if aime < ctime. */ + if (compare_ts (at, ct) < 0) + return false; + + delta.tv_sec = ct.tv_sec - at.tv_sec; + delta.tv_nsec = ct.tv_nsec - at.tv_nsec; if (delta.tv_nsec < 0) { delta.tv_nsec += 1000000000;