mirror of
git://git.sv.gnu.org/findutils.git
synced 2026-01-30 13:18:59 +01:00
Support for sub-second timestamp resolution in -newer, -anewer and -cnewer plus the various -printf actions
This commit is contained in:
25
ChangeLog
25
ChangeLog
@@ -1,3 +1,28 @@
|
||||
2007-01-16 James Youngman <jay@gnu.org>
|
||||
|
||||
(ctime_format): format the time manually (rather than using ctime)
|
||||
in order to include the sub-second part of the time.
|
||||
(weekdays, months): new static variables used bu ctime_format.
|
||||
(format_date): append a the sub-second part of the timestamp to
|
||||
the seconds part of date/time output.
|
||||
|
||||
2007-01-15 James Youngman <jay@gnu.org>
|
||||
|
||||
* find/defs.h (time_val): define struct; use timespec to hold time
|
||||
in the 'reftime' member.
|
||||
(args): use struct timespec instead of time_t for predicates
|
||||
-newer, -anewer, -cnewer. * find/parser.c (includes): include
|
||||
stat-time.h.
|
||||
(parse_anewer, parse_cnewer, parse_newer): use struct timespec to
|
||||
hold timestamps. * find/pred.c (compare_ts): new function for
|
||||
comparing timestamps in struct timespec.
|
||||
(pred_anewer, pred_cnewer, pred_newer): use compare_ts() to
|
||||
compare timestamps (hence takinng acoung of sub-second
|
||||
granularity).
|
||||
* find/ftsfind.c: Various improvements to comments.
|
||||
(is_fts_enabled): Newline before function name to comply with GNU
|
||||
coding standard.
|
||||
|
||||
2007-01-13 James Youngman <jay@gnu.org>
|
||||
|
||||
* xargs/xargs.c (read_line): Fixed Savannah bug# 18714; VT and FF
|
||||
|
||||
12
NEWS
12
NEWS
@@ -12,6 +12,18 @@ this change will happen. We now issue a warning indicating that the
|
||||
change has already happened (in 4.3.x only, there is no plan to make
|
||||
this change in the 4.2.x series).
|
||||
|
||||
The tests -newer, -anewer and -cnewer now support sub-second
|
||||
timestamps. This support does not yet exist for the tests -mtime,
|
||||
-atime, or -ctime, nor does it exist for -amin, -cmin, or -mmin.
|
||||
|
||||
The -printf format specifiers also support sub-second timestamps:
|
||||
atime ctime mtime
|
||||
%a %c %t
|
||||
%AS %CS %TS
|
||||
%AT %CT %TT
|
||||
%A+ %C+ %T+
|
||||
%AX %CX %TX
|
||||
|
||||
|
||||
** Bug Fixes
|
||||
|
||||
|
||||
46
config.rpath
46
config.rpath
@@ -488,33 +488,54 @@ fi
|
||||
|
||||
# Check dynamic linker characteristics
|
||||
# Code taken from libtool.m4's AC_LIBTOOL_SYS_DYNAMIC_LINKER.
|
||||
# Unlike libtool.m4, here we don't care about _all_ names of the library, but
|
||||
# only about the one the linker finds when passed -lNAME. This is the last
|
||||
# element of library_names_spec in libtool.m4, or possibly two of them if the
|
||||
# linker has special search rules.
|
||||
library_names_spec= # the last element of library_names_spec in libtool.m4
|
||||
libname_spec='lib$name'
|
||||
case "$host_os" in
|
||||
aix3*)
|
||||
library_names_spec='$libname.a'
|
||||
;;
|
||||
aix4* | aix5*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
amigaos*)
|
||||
library_names_spec='$libname.a'
|
||||
;;
|
||||
beos*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
bsdi[45]*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
cygwin* | mingw* | pw32*)
|
||||
shrext=.dll
|
||||
library_names_spec='$libname.dll.a $libname.lib'
|
||||
;;
|
||||
darwin* | rhapsody*)
|
||||
shrext=.dylib
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
dgux*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
freebsd1*)
|
||||
;;
|
||||
kfreebsd*-gnu)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
freebsd* | dragonfly*)
|
||||
case "$host_os" in
|
||||
freebsd[123]*)
|
||||
library_names_spec='$libname$shrext$versuffix' ;;
|
||||
*)
|
||||
library_names_spec='$libname$shrext' ;;
|
||||
esac
|
||||
;;
|
||||
gnu*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
hpux9* | hpux10* | hpux11*)
|
||||
case $host_cpu in
|
||||
@@ -528,10 +549,13 @@ case "$host_os" in
|
||||
shrext=.sl
|
||||
;;
|
||||
esac
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
interix3*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
irix5* | irix6* | nonstopux*)
|
||||
library_names_spec='$libname$shrext'
|
||||
case "$host_os" in
|
||||
irix5* | nonstopux*)
|
||||
libsuff= shlibsuff=
|
||||
@@ -549,40 +573,56 @@ case "$host_os" in
|
||||
linux*oldld* | linux*aout* | linux*coff*)
|
||||
;;
|
||||
linux*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
knetbsd*-gnu)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
netbsd*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
newsos6)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
nto-qnx*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
openbsd*)
|
||||
library_names_spec='$libname$shrext$versuffix'
|
||||
;;
|
||||
os2*)
|
||||
libname_spec='$name'
|
||||
shrext=.dll
|
||||
library_names_spec='$libname.a'
|
||||
;;
|
||||
osf3* | osf4* | osf5*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
solaris*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
sunos4*)
|
||||
library_names_spec='$libname$shrext$versuffix'
|
||||
;;
|
||||
sysv4 | sysv4.3*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
sysv4*MP*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
uts4*)
|
||||
library_names_spec='$libname$shrext'
|
||||
;;
|
||||
esac
|
||||
|
||||
sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
|
||||
escaped_wl=`echo "X$wl" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
shlibext=`echo "$shrext" | sed -e 's,^\.,,'`
|
||||
escaped_libname_spec=`echo "X$libname_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
escaped_library_names_spec=`echo "X$library_names_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
escaped_hardcode_libdir_flag_spec=`echo "X$hardcode_libdir_flag_spec" | sed -e 's/^X//' -e "$sed_quote_subst"`
|
||||
|
||||
LC_ALL=C sed -e 's/^\([a-zA-Z0-9_]*\)=/acl_cv_\1=/' <<EOF
|
||||
@@ -596,6 +636,12 @@ libext="$libext"
|
||||
# Shared library suffix (normally "so").
|
||||
shlibext="$shlibext"
|
||||
|
||||
# Format of library name prefix.
|
||||
libname_spec="$escaped_libname_spec"
|
||||
|
||||
# Library names that the linker finds when passed -lNAME.
|
||||
library_names_spec="$escaped_library_names_spec"
|
||||
|
||||
# Flag to hardcode \$libdir into a binary during linking.
|
||||
# This must work even if \$libdir does not exist.
|
||||
hardcode_libdir_flag_spec="$escaped_hardcode_libdir_flag_spec"
|
||||
|
||||
12
find/defs.h
12
find/defs.h
@@ -64,6 +64,7 @@ extern int errno;
|
||||
#endif
|
||||
|
||||
#include "regex.h"
|
||||
#include "timespec.h"
|
||||
|
||||
#ifndef S_IFLNK
|
||||
#define lstat stat
|
||||
@@ -220,7 +221,13 @@ struct size_val
|
||||
uintmax_t size;
|
||||
};
|
||||
|
||||
struct time_val
|
||||
{
|
||||
enum comparison_type kind;
|
||||
struct timespec ts;
|
||||
};
|
||||
|
||||
|
||||
#include "buildcmd.h"
|
||||
|
||||
struct exec_val
|
||||
@@ -333,12 +340,11 @@ struct predicate
|
||||
char *str; /* fstype [i]lname [i]name [i]path */
|
||||
struct re_pattern_buffer *regex; /* regex */
|
||||
struct exec_val exec_vec; /* exec ok */
|
||||
struct long_val info; /* atime ctime gid inum links mtime
|
||||
size uid */
|
||||
struct long_val numinfo; /* gid inum links uid */
|
||||
struct size_val size; /* size */
|
||||
uid_t uid; /* user */
|
||||
gid_t gid; /* group */
|
||||
time_t time; /* newer */
|
||||
struct time_val reftime; /* newer anewer cnewer mtime atime ctime mmin amin cmin */
|
||||
struct perm_val perm; /* perm */
|
||||
struct dir_id fileid; /* samefile */
|
||||
mode_t type; /* type */
|
||||
|
||||
134
find/parser.c
134
find/parser.c
@@ -35,6 +35,7 @@
|
||||
#include "nextelem.h"
|
||||
#include "stdio-safer.h"
|
||||
#include "regextype.h"
|
||||
#include "stat-time.h"
|
||||
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
@@ -491,7 +492,6 @@ estimate_timestamp_success_rate(time_t when)
|
||||
return estimate_file_age_success_rate(num_days);
|
||||
}
|
||||
|
||||
|
||||
/* The parsers are responsible to continue scanning ARGV for
|
||||
their arguments. Each parser knows what is and isn't
|
||||
allowed for itself.
|
||||
@@ -502,28 +502,7 @@ estimate_timestamp_success_rate(time_t when)
|
||||
|
||||
The predicate structure is updated with the new information. */
|
||||
|
||||
static boolean
|
||||
parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
struct predicate *our_pred;
|
||||
uintmax_t num;
|
||||
enum comparison_type c_type;
|
||||
time_t t;
|
||||
|
||||
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
||||
return false;
|
||||
if (!get_num_days (argv[*arg_ptr], &num, &c_type))
|
||||
return false;
|
||||
t = options.cur_day_start + DAYSECS - num * 60;
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.info.kind = c_type;
|
||||
our_pred->args.info.negative = t < 0;
|
||||
our_pred->args.info.l_val = t;
|
||||
our_pred->est_success_rate = estimate_file_age_success_rate(num);
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
parse_and (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
@@ -551,7 +530,8 @@ parse_anewer (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
|
||||
error (1, errno, "%s", argv[*arg_ptr]);
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.time = stat_newer.st_mtime;
|
||||
our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
|
||||
our_pred->args.reftime.kind = COMP_GT;
|
||||
our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
@@ -573,28 +553,6 @@ parse_close (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean
|
||||
parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
struct predicate *our_pred;
|
||||
uintmax_t num;
|
||||
enum comparison_type c_type;
|
||||
time_t t;
|
||||
|
||||
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
||||
return false;
|
||||
if (!get_num_days (argv[*arg_ptr], &num, &c_type))
|
||||
return false;
|
||||
t = options.cur_day_start + DAYSECS - num * 60;
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.info.kind = c_type;
|
||||
our_pred->args.info.negative = t < 0;
|
||||
our_pred->args.info.l_val = t;
|
||||
our_pred->est_success_rate = estimate_file_age_success_rate(num);
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
}
|
||||
|
||||
static boolean
|
||||
parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
@@ -606,7 +564,8 @@ parse_cnewer (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
|
||||
error (1, errno, "%s", argv[*arg_ptr]);
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.time = stat_newer.st_mtime;
|
||||
our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
|
||||
our_pred->args.reftime.kind = COMP_GT;
|
||||
our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
@@ -849,7 +808,7 @@ static boolean
|
||||
parse_gid (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
struct predicate *p = insert_num (argv, arg_ptr, entry);
|
||||
p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
|
||||
p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -876,7 +835,7 @@ parse_group (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
}
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.gid = gid;
|
||||
our_pred->est_success_rate = (our_pred->args.info.l_val < 100) ? 0.99 : 0.2;
|
||||
our_pred->est_success_rate = (our_pred->args.numinfo.l_val < 100) ? 0.99 : 0.2;
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
}
|
||||
@@ -1059,9 +1018,9 @@ static boolean
|
||||
parse_links (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
struct predicate *p = insert_num (argv, arg_ptr, entry);
|
||||
if (p->args.info.l_val == 1)
|
||||
if (p->args.numinfo.l_val == 1)
|
||||
p->est_success_rate = 0.99;
|
||||
else if (p->args.info.l_val == 2)
|
||||
else if (p->args.numinfo.l_val == 2)
|
||||
p->est_success_rate = 0.01;
|
||||
else
|
||||
p->est_success_rate = 1e-3;
|
||||
@@ -1136,9 +1095,10 @@ parse_mindepth (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
(*arg_ptr)++;
|
||||
return parse_noop(entry, argv, arg_ptr);
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
do_parse_xmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
struct predicate *our_pred;
|
||||
uintmax_t num;
|
||||
@@ -1147,17 +1107,36 @@ parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
|
||||
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
||||
return false;
|
||||
if (!get_num_days (argv[*arg_ptr], &num, &c_type))
|
||||
/* XXX: need to capture sub-second part */
|
||||
if (!get_num_days (argv[*arg_ptr], &num, &c_type)) /* actually not a number of days... */
|
||||
return false;
|
||||
t = options.cur_day_start + DAYSECS - num * 60;
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.info.kind = c_type;
|
||||
our_pred->args.info.negative = t < 0;
|
||||
our_pred->args.info.l_val = t;
|
||||
our_pred->args.reftime.kind = c_type;
|
||||
our_pred->args.reftime.ts.tv_sec = t;
|
||||
our_pred->args.reftime.ts.tv_nsec = 0; /* XXX: need to capture this. */
|
||||
our_pred->est_success_rate = estimate_file_age_success_rate(num);
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
}
|
||||
static boolean
|
||||
parse_amin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
return do_parse_xmin(entry, argv, arg_ptr);
|
||||
}
|
||||
|
||||
static boolean
|
||||
parse_cmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
return do_parse_xmin(entry, argv, arg_ptr);
|
||||
}
|
||||
|
||||
|
||||
static boolean
|
||||
parse_mmin (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
return do_parse_xmin(entry, argv, arg_ptr);
|
||||
}
|
||||
|
||||
static boolean
|
||||
parse_name (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
@@ -1211,7 +1190,8 @@ parse_newer (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
if ((*options.xstat) (argv[*arg_ptr], &stat_newer))
|
||||
error (1, errno, "%s", argv[*arg_ptr]);
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.time = stat_newer.st_mtime;
|
||||
our_pred->args.reftime.ts = get_stat_mtime(&stat_newer);
|
||||
our_pred->args.reftime.kind = COMP_GT;
|
||||
our_pred->est_success_rate = estimate_timestamp_success_rate(stat_newer.st_mtime);
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
@@ -1850,7 +1830,7 @@ static boolean
|
||||
parse_uid (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
{
|
||||
struct predicate *p = insert_num (argv, arg_ptr, entry);
|
||||
p->est_success_rate = (p->args.info.l_val < 100) ? 0.99 : 0.2;
|
||||
p->est_success_rate = (p->args.numinfo.l_val < 100) ? 0.99 : 0.2;
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -1864,13 +1844,15 @@ parse_used (const struct parser_table* entry, char **argv, int *arg_ptr)
|
||||
|
||||
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
||||
return false;
|
||||
|
||||
/* XXX: need to capture nanoseconds part */
|
||||
if (!get_num (argv[*arg_ptr], &num_days, &c_type))
|
||||
return false;
|
||||
t = num_days * DAYSECS;
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.info.kind = c_type;
|
||||
our_pred->args.info.negative = t < 0;
|
||||
our_pred->args.info.l_val = t;
|
||||
our_pred->args.reftime.kind = c_type;
|
||||
our_pred->args.reftime.ts.tv_sec = t;
|
||||
our_pred->args.reftime.ts.tv_nsec = 0; /* XXX: capture ns part */
|
||||
our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
|
||||
(*arg_ptr)++;
|
||||
return true;
|
||||
@@ -2129,7 +2111,8 @@ insert_fprintf (FILE *fp, const struct parser_table *entry, PRED_FUNC func, char
|
||||
our_pred->args.printf_vec.quote_opts = clone_quoting_options (NULL);
|
||||
our_pred->need_type = false;
|
||||
our_pred->need_stat = false;
|
||||
|
||||
our_pred->p_cost = NeedsNothing;
|
||||
|
||||
segmentp = &our_pred->args.printf_vec.segment;
|
||||
*segmentp = NULL;
|
||||
|
||||
@@ -2628,6 +2611,7 @@ insert_exec_ok (const char *action, const struct parser_table *entry, char **arg
|
||||
|
||||
|
||||
/* Get a number of days and comparison type.
|
||||
- but beware, this is also used to collect numbers of minutes -
|
||||
STR is the ASCII representation.
|
||||
Set *NUM_DAYS to the number of days, taken as being from
|
||||
the current moment (or possibly midnight). Thus the sense of the
|
||||
@@ -2653,7 +2637,7 @@ get_num_days (char *str, uintmax_t *num_days, enum comparison_type *comp_type)
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Insert a time predicate PRED.
|
||||
/* Insert a time predicate based on the information in ENTRY.
|
||||
ARGV is a pointer to the argument array.
|
||||
ARG_PTR is a pointer to an index into the array, incremented if
|
||||
all went well.
|
||||
@@ -2675,6 +2659,8 @@ parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
|
||||
|
||||
if ((argv == NULL) || (argv[*arg_ptr] == NULL))
|
||||
return false;
|
||||
|
||||
/* XXX: capture sub-second part */
|
||||
if (!get_num_days (argv[*arg_ptr], &num_days, &c_type))
|
||||
return false;
|
||||
|
||||
@@ -2700,9 +2686,9 @@ parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
|
||||
}
|
||||
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.info.kind = c_type;
|
||||
our_pred->args.info.negative = t < 0;
|
||||
our_pred->args.info.l_val = t;
|
||||
our_pred->args.reftime.kind = c_type;
|
||||
our_pred->args.reftime.ts.tv_sec = t;
|
||||
our_pred->args.reftime.ts.tv_nsec = 0; /* XXX: capture this part */
|
||||
our_pred->est_success_rate = estimate_file_age_success_rate(num_days);
|
||||
(*arg_ptr)++;
|
||||
|
||||
@@ -2714,14 +2700,14 @@ parse_time (const struct parser_table* entry, char *argv[], int *arg_ptr)
|
||||
((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
|
||||
(c_type == COMP_GT) ? " >" :
|
||||
((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? ">=" : " ?")));
|
||||
t = our_pred->args.info.l_val;
|
||||
fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.info.l_val, ctime (&t));
|
||||
t = our_pred->args.reftime.ts.tv_sec;
|
||||
fprintf (stderr, "%ju %s", (uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
|
||||
if (c_type == COMP_EQ)
|
||||
{
|
||||
t = our_pred->args.info.l_val += DAYSECS;
|
||||
t = our_pred->args.reftime.ts.tv_sec += DAYSECS;
|
||||
fprintf (stderr, " < %ju %s",
|
||||
(uintmax_t) our_pred->args.info.l_val, ctime (&t));
|
||||
our_pred->args.info.l_val -= DAYSECS;
|
||||
(uintmax_t) our_pred->args.reftime.ts.tv_sec, ctime (&t));
|
||||
our_pred->args.reftime.ts.tv_sec -= DAYSECS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2785,8 +2771,8 @@ insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
|
||||
if (!get_num (argv[*arg_ptr], &num, &c_type))
|
||||
return NULL;
|
||||
our_pred = insert_primary (entry);
|
||||
our_pred->args.info.kind = c_type;
|
||||
our_pred->args.info.l_val = num;
|
||||
our_pred->args.numinfo.kind = c_type;
|
||||
our_pred->args.numinfo.l_val = num;
|
||||
(*arg_ptr)++;
|
||||
|
||||
if (options.debug_options & DebugExpressionTree)
|
||||
@@ -2797,7 +2783,7 @@ insert_num (char **argv, int *arg_ptr, const struct parser_table *entry)
|
||||
((c_type == COMP_LT) ? "lt" : ((c_type == COMP_EQ) ? "eq" : "?")),
|
||||
(c_type == COMP_GT) ? " >" :
|
||||
((c_type == COMP_LT) ? " <" : ((c_type == COMP_EQ) ? " =" : " ?")));
|
||||
fprintf (stderr, "%ju\n", our_pred->args.info.l_val);
|
||||
fprintf (stderr, "%ju\n", our_pred->args.numinfo.l_val);
|
||||
}
|
||||
return our_pred;
|
||||
}
|
||||
|
||||
323
find/pred.c
323
find/pred.c
@@ -29,6 +29,7 @@
|
||||
#include <sys/stat.h>
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
#include <locale.h>
|
||||
#include "xalloc.h"
|
||||
#include "dirname.h"
|
||||
#include "human.h"
|
||||
@@ -39,6 +40,7 @@
|
||||
#include "buildcmd.h"
|
||||
#include "yesno.h"
|
||||
#include "listfile.h"
|
||||
#include "stat-time.h"
|
||||
|
||||
#if ENABLE_NLS
|
||||
# include <libintl.h>
|
||||
@@ -153,8 +155,8 @@
|
||||
|
||||
static boolean match_lname PARAMS((char *pathname, struct stat *stat_buf, struct predicate *pred_ptr, boolean ignore_case));
|
||||
|
||||
static char *format_date PARAMS((time_t when, int kind));
|
||||
static char *ctime_format PARAMS((time_t when));
|
||||
static char *format_date PARAMS((struct timespec ts, int kind));
|
||||
static char *ctime_format PARAMS((struct timespec ts));
|
||||
|
||||
#ifdef DEBUG
|
||||
struct pred_assoc
|
||||
@@ -225,6 +227,32 @@ struct pred_assoc pred_table[] =
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Returns ts1 - ts2 */
|
||||
static double ts_difference(struct timespec ts1,
|
||||
struct timespec ts2)
|
||||
{
|
||||
double d = difftime(ts1.tv_sec, ts2.tv_sec)
|
||||
+ (1.0e-9 * (ts1.tv_nsec - ts2.tv_nsec));
|
||||
return d;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
compare_ts(struct timespec ts1,
|
||||
struct timespec ts2)
|
||||
{
|
||||
if ((ts1.tv_sec == ts2.tv_sec) &&
|
||||
(ts1.tv_nsec == ts2.tv_nsec))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double diff = ts_difference(ts1, ts2);
|
||||
return diff < 0.0 ? -1 : +1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Predicate processing routines.
|
||||
|
||||
PATHNAME is the full pathname of the file being checked.
|
||||
@@ -242,25 +270,22 @@ struct pred_assoc pred_table[] =
|
||||
* COMP_EQ: less than WINDOW seconds after the specified time.
|
||||
*/
|
||||
static boolean
|
||||
pred_timewindow(time_t the_time, struct predicate const *pred_ptr, int window)
|
||||
pred_timewindow(struct timespec ts, struct predicate const *pred_ptr, int window)
|
||||
{
|
||||
switch (pred_ptr->args.info.kind)
|
||||
double delta;
|
||||
|
||||
switch (pred_ptr->args.reftime.kind)
|
||||
{
|
||||
case COMP_GT:
|
||||
if (the_time > (time_t) pred_ptr->args.info.l_val)
|
||||
return true;
|
||||
break;
|
||||
return compare_ts(ts, pred_ptr->args.reftime.ts) > 0;
|
||||
|
||||
case COMP_LT:
|
||||
if (the_time < (time_t) pred_ptr->args.info.l_val)
|
||||
return true;
|
||||
break;
|
||||
return compare_ts(ts, pred_ptr->args.reftime.ts) < 0;
|
||||
|
||||
case COMP_EQ:
|
||||
if ((the_time >= (time_t) pred_ptr->args.info.l_val)
|
||||
&& (the_time < (time_t) pred_ptr->args.info.l_val + window))
|
||||
return true;
|
||||
break;
|
||||
delta = ts_difference(ts, pred_ptr->args.reftime.ts);
|
||||
return (delta >= 0.0 && delta < window);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -268,7 +293,7 @@ boolean
|
||||
pred_amin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) &pathname;
|
||||
return pred_timewindow(stat_buf->st_atime, pred_ptr, 60);
|
||||
return pred_timewindow(get_stat_atime(stat_buf), pred_ptr, 60);
|
||||
}
|
||||
|
||||
boolean
|
||||
@@ -292,17 +317,15 @@ boolean
|
||||
pred_anewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) &pathname;
|
||||
|
||||
if (stat_buf->st_atime > pred_ptr->args.time)
|
||||
return (true);
|
||||
return (false);
|
||||
assert(COMP_GT == pred_ptr->args.reftime.kind);
|
||||
return compare_ts(get_stat_atime(stat_buf), pred_ptr->args.reftime.ts) > 0;
|
||||
}
|
||||
|
||||
boolean
|
||||
pred_atime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) &pathname;
|
||||
return pred_timewindow(stat_buf->st_atime, pred_ptr, DAYSECS);
|
||||
return pred_timewindow(get_stat_atime(stat_buf), pred_ptr, DAYSECS);
|
||||
}
|
||||
|
||||
boolean
|
||||
@@ -319,7 +342,7 @@ boolean
|
||||
pred_cmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
return pred_timewindow(stat_buf->st_ctime, pred_ptr, 60);
|
||||
return pred_timewindow(get_stat_ctime(stat_buf), pred_ptr, 60);
|
||||
}
|
||||
|
||||
boolean
|
||||
@@ -327,10 +350,8 @@ pred_cnewer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
|
||||
if (stat_buf->st_ctime > pred_ptr->args.time)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
assert(COMP_GT == pred_ptr->args.reftime.kind);
|
||||
return compare_ts(get_stat_ctime(stat_buf), pred_ptr->args.reftime.ts) > 0;
|
||||
}
|
||||
|
||||
boolean
|
||||
@@ -351,7 +372,7 @@ boolean
|
||||
pred_ctime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) &pathname;
|
||||
return pred_timewindow(stat_buf->st_ctime, pred_ptr, DAYSECS);
|
||||
return pred_timewindow(get_stat_ctime(stat_buf), pred_ptr, DAYSECS);
|
||||
}
|
||||
|
||||
boolean
|
||||
@@ -595,7 +616,7 @@ do_fprintf(FILE *fp,
|
||||
{
|
||||
case 'a': /* atime in `ctime' format. */
|
||||
/* UNTRUSTED, probably unexploitable */
|
||||
fprintf (fp, segment->text, ctime_format (stat_buf->st_atime));
|
||||
fprintf (fp, segment->text, ctime_format (get_stat_atime(stat_buf)));
|
||||
break;
|
||||
case 'b': /* size in 512-byte blocks */
|
||||
/* UNTRUSTED, probably unexploitable */
|
||||
@@ -606,7 +627,7 @@ do_fprintf(FILE *fp,
|
||||
break;
|
||||
case 'c': /* ctime in `ctime' format */
|
||||
/* UNTRUSTED, probably unexploitable */
|
||||
fprintf (fp, segment->text, ctime_format (stat_buf->st_ctime));
|
||||
fprintf (fp, segment->text, ctime_format (get_stat_ctime(stat_buf)));
|
||||
break;
|
||||
case 'd': /* depth in search tree */
|
||||
/* UNTRUSTED, probably unexploitable */
|
||||
@@ -806,8 +827,9 @@ do_fprintf(FILE *fp,
|
||||
|
||||
case 't': /* mtime in `ctime' format */
|
||||
/* UNTRUSTED, probably unexploitable */
|
||||
fprintf (fp, segment->text, ctime_format (stat_buf->st_mtime));
|
||||
fprintf (fp, segment->text, ctime_format (get_stat_mtime(stat_buf)));
|
||||
break;
|
||||
|
||||
case 'u': /* user name */
|
||||
/* trusted */
|
||||
/* (well, the actual user is selected by the user on systems
|
||||
@@ -897,18 +919,18 @@ pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
if ( (KIND_FORMAT == segment->segkind) && segment->format_char[1]) /* Component of date. */
|
||||
{
|
||||
time_t t;
|
||||
|
||||
struct timespec ts;
|
||||
|
||||
switch (segment->format_char[0])
|
||||
{
|
||||
case 'A':
|
||||
t = stat_buf->st_atime;
|
||||
ts = get_stat_atime(stat_buf);
|
||||
break;
|
||||
case 'C':
|
||||
t = stat_buf->st_ctime;
|
||||
ts = get_stat_ctime(stat_buf);
|
||||
break;
|
||||
case 'T':
|
||||
t = stat_buf->st_mtime;
|
||||
ts = get_stat_mtime(stat_buf);
|
||||
break;
|
||||
default:
|
||||
assert(0);
|
||||
@@ -920,7 +942,7 @@ pred_fprintf (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
*/
|
||||
/* trusted */
|
||||
fprintf (fp, segment->text,
|
||||
format_date (t, segment->format_char[1]));
|
||||
format_date (ts, segment->format_char[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -946,18 +968,18 @@ pred_gid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
|
||||
switch (pred_ptr->args.info.kind)
|
||||
switch (pred_ptr->args.numinfo.kind)
|
||||
{
|
||||
case COMP_GT:
|
||||
if (stat_buf->st_gid > pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_gid > pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_LT:
|
||||
if (stat_buf->st_gid < pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_gid < pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_EQ:
|
||||
if (stat_buf->st_gid == pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_gid == pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
}
|
||||
@@ -1002,18 +1024,18 @@ pred_inum (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
|
||||
switch (pred_ptr->args.info.kind)
|
||||
switch (pred_ptr->args.numinfo.kind)
|
||||
{
|
||||
case COMP_GT:
|
||||
if (stat_buf->st_ino > pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_ino > pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_LT:
|
||||
if (stat_buf->st_ino < pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_ino < pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_EQ:
|
||||
if (stat_buf->st_ino == pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_ino == pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
}
|
||||
@@ -1035,18 +1057,18 @@ pred_links (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
|
||||
switch (pred_ptr->args.info.kind)
|
||||
switch (pred_ptr->args.numinfo.kind)
|
||||
{
|
||||
case COMP_GT:
|
||||
if (stat_buf->st_nlink > pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_nlink > pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_LT:
|
||||
if (stat_buf->st_nlink < pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_nlink < pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_EQ:
|
||||
if (stat_buf->st_nlink == pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_nlink == pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
}
|
||||
@@ -1093,14 +1115,14 @@ boolean
|
||||
pred_mmin (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) &pathname;
|
||||
return pred_timewindow(stat_buf->st_mtime, pred_ptr, 60);
|
||||
return pred_timewindow(get_stat_mtime(stat_buf), pred_ptr, 60);
|
||||
}
|
||||
|
||||
boolean
|
||||
pred_mtime (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
return pred_timewindow(stat_buf->st_mtime, pred_ptr, DAYSECS);
|
||||
return pred_timewindow(get_stat_mtime(stat_buf), pred_ptr, DAYSECS);
|
||||
}
|
||||
|
||||
boolean
|
||||
@@ -1135,9 +1157,8 @@ pred_newer (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
|
||||
if (stat_buf->st_mtime > pred_ptr->args.time)
|
||||
return (true);
|
||||
return (false);
|
||||
assert(COMP_GT == pred_ptr->args.reftime.kind);
|
||||
return compare_ts(get_stat_mtime(stat_buf), pred_ptr->args.reftime.ts) > 0;
|
||||
}
|
||||
|
||||
boolean
|
||||
@@ -1478,18 +1499,18 @@ boolean
|
||||
pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
(void) pathname;
|
||||
switch (pred_ptr->args.info.kind)
|
||||
switch (pred_ptr->args.numinfo.kind)
|
||||
{
|
||||
case COMP_GT:
|
||||
if (stat_buf->st_uid > pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_uid > pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_LT:
|
||||
if (stat_buf->st_uid < pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_uid < pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
case COMP_EQ:
|
||||
if (stat_buf->st_uid == pred_ptr->args.info.l_val)
|
||||
if (stat_buf->st_uid == pred_ptr->args.numinfo.l_val)
|
||||
return (true);
|
||||
break;
|
||||
}
|
||||
@@ -1499,10 +1520,20 @@ pred_uid (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
boolean
|
||||
pred_used (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr)
|
||||
{
|
||||
time_t delta;
|
||||
struct timespec delta, at, ct;
|
||||
|
||||
(void) pathname;
|
||||
delta = stat_buf->st_atime - stat_buf->st_ctime; /* Use difftime? */
|
||||
|
||||
/* XXX: 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;
|
||||
if (delta.tv_nsec < 0)
|
||||
{
|
||||
delta.tv_nsec += 1000000000;
|
||||
delta.tv_sec -= 1;
|
||||
}
|
||||
return pred_timewindow(delta, pred_ptr, DAYSECS);
|
||||
}
|
||||
|
||||
@@ -1704,52 +1735,172 @@ launch (const struct buildcmd_control *ctl,
|
||||
|
||||
|
||||
/* Return a static string formatting the time WHEN according to the
|
||||
strftime format character KIND. */
|
||||
|
||||
* strftime format character KIND.
|
||||
*
|
||||
* This function contains a number of assertions. These look like
|
||||
* runtime checks of the results of computations, which would be a
|
||||
* problem since external events should not be tested for with
|
||||
* "assert" (instead you should use "if"). However, they are not
|
||||
* really runtime checks. The assertions actually exist to verify
|
||||
* that the various buffers are correctly sized.
|
||||
*/
|
||||
static char *
|
||||
format_date (time_t when, int kind)
|
||||
format_date (struct timespec ts, int kind)
|
||||
{
|
||||
static char buf[MAX (LONGEST_HUMAN_READABLE + 2, 64)];
|
||||
/* Use an extra 10 characters for 9 digits of nanoseconds and 1 for
|
||||
* the decimal point
|
||||
*/
|
||||
enum {
|
||||
NS_BUF_LEN = 12,
|
||||
DATE_LEN_PERCENT_APLUS=21 /* length of result of %A+ (it's longer than %c)*/
|
||||
};
|
||||
static char buf[10u + MAX(DATE_LEN_PERCENT_APLUS, MAX (LONGEST_HUMAN_READABLE + 2, 64))];
|
||||
char ns_buf[NS_BUF_LEN]; /* .9999999990 */
|
||||
int charsprinted, need_ns_suffix;
|
||||
struct tm *tm;
|
||||
char fmt[6];
|
||||
|
||||
fmt[0] = '%';
|
||||
fmt[1] = kind;
|
||||
fmt[2] = '\0';
|
||||
/* human_readable() assumes we pass a buffer which is at least as
|
||||
* long as LONGEST_HUMAN_READABLE. We use an assertion here to
|
||||
* ensure that no nasty unsigned overflow happend in our calculation
|
||||
* of the size of buf. Do the assertion here rather than in the
|
||||
* code for %@ so that we find the problem quickly if it exists. If
|
||||
* you want to submit a patch to move this into the if statement, go
|
||||
* ahead, I'll apply it. But include performance timings
|
||||
* demonstrating that the performance difference is actually
|
||||
* measurable.
|
||||
*/
|
||||
assert(sizeof(buf) >= LONGEST_HUMAN_READABLE);
|
||||
|
||||
/* Format the main part of the time. */
|
||||
if (kind == '+')
|
||||
strcpy (fmt, "%F+%T");
|
||||
|
||||
if (kind != '@'
|
||||
&& (tm = localtime (&when))
|
||||
&& strftime (buf, sizeof buf, fmt, tm))
|
||||
return buf;
|
||||
{
|
||||
strcpy (fmt, "%F+%T");
|
||||
need_ns_suffix = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
uintmax_t w = when;
|
||||
char *p = human_readable (when < 0 ? -w : w, buf + 1,
|
||||
fmt[0] = '%';
|
||||
fmt[1] = kind;
|
||||
fmt[2] = '\0';
|
||||
|
||||
/* %a, %c, and %t are handled in ctime_format() */
|
||||
switch (kind)
|
||||
{
|
||||
case 'S':
|
||||
case 'T':
|
||||
case 'X':
|
||||
need_ns_suffix = 1;
|
||||
break;
|
||||
default:
|
||||
need_ns_suffix = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (need_ns_suffix)
|
||||
{
|
||||
/* Format the nanoseconds part. Leave a trailing zero to discourage people from
|
||||
* writing scripts which extract the fractional part of the timestamp by using
|
||||
* column offsets. The reason for discouraging this is that in the future, the
|
||||
* granularity may not be nanoseconds.
|
||||
*/
|
||||
charsprinted = snprintf(ns_buf, NS_BUF_LEN, ".%09ld0", (long int)ts.tv_nsec);
|
||||
assert(charsprinted < NS_BUF_LEN);
|
||||
}
|
||||
|
||||
if (kind != '@'
|
||||
&& (tm = localtime (&ts.tv_sec))
|
||||
&& strftime (buf, sizeof buf, fmt, tm))
|
||||
{
|
||||
/* For %AS, %CS, %TS, add the fractional part of the seconds information. */
|
||||
if (need_ns_suffix)
|
||||
{
|
||||
assert((sizeof buf - strlen(buf)) > strlen(ns_buf));
|
||||
strcat(buf, ns_buf);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
else
|
||||
{
|
||||
uintmax_t w = ts.tv_sec;
|
||||
size_t used, len, remaining;
|
||||
|
||||
/* XXX: note that we are negating an unsigned type which is the widest possible
|
||||
* unsigned type.
|
||||
*/
|
||||
char *p = human_readable (ts.tv_sec < 0 ? -w : w, buf + 1,
|
||||
human_ceiling, 1, 1);
|
||||
if (when < 0)
|
||||
*--p = '-';
|
||||
assert(p > buf);
|
||||
assert(p < (buf + (sizeof buf)));
|
||||
if (ts.tv_sec < 0)
|
||||
*--p = '-'; /* XXX: Ugh, relying on internal details of human_readable(). */
|
||||
|
||||
/* Add the nanoseconds part. Because we cannot enforce a particlar implementation
|
||||
* of human_readable, we cannot assume any particular value for (p-buf). So we
|
||||
* need to be careful that there is enough space remaining in the buffer.
|
||||
*/
|
||||
len = strlen(p);
|
||||
used = (p-buf) + len; /* Offset into buf of current end */
|
||||
assert(sizeof buf > used); /* Ensure we can perform subtraction safely. */
|
||||
remaining = sizeof buf - used - 1u; /* allow space for NUL */
|
||||
assert(strlen(ns_buf) < remaining);
|
||||
strcat(p, ns_buf);
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
static const char *weekdays[] =
|
||||
{
|
||||
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
|
||||
};
|
||||
static char * months[] =
|
||||
{
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
|
||||
};
|
||||
|
||||
|
||||
static char *
|
||||
ctime_format (time_t when)
|
||||
ctime_format (struct timespec ts)
|
||||
{
|
||||
char *r = ctime (&when);
|
||||
if (!r)
|
||||
const struct tm * ptm;
|
||||
#define TIME_BUF_LEN 1024u
|
||||
static char resultbuf[TIME_BUF_LEN];
|
||||
int nout;
|
||||
|
||||
ptm = localtime(&ts.tv_sec);
|
||||
if (ptm)
|
||||
{
|
||||
/* The time cannot be represented as a struct tm.
|
||||
Output it as an integer. */
|
||||
return format_date (when, '@');
|
||||
assert(ptm->tm_wday >= 0);
|
||||
assert(ptm->tm_wday < 7);
|
||||
assert(ptm->tm_mon >= 0);
|
||||
assert(ptm->tm_mon < 12);
|
||||
assert(ptm->tm_hour >= 0);
|
||||
assert(ptm->tm_hour < 24);
|
||||
assert(ptm->tm_min < 60);
|
||||
assert(ptm->tm_sec <= 61); /* allows 2 leap seconds. */
|
||||
|
||||
/* wkday mon mday hh:mm:ss.nnnnnnnnn yyyy */
|
||||
nout = snprintf(resultbuf, TIME_BUF_LEN,
|
||||
"%3s %3s %2d %02d:%02d:%02d.%010ld %04d",
|
||||
weekdays[ptm->tm_wday],
|
||||
months[ptm->tm_mon],
|
||||
ptm->tm_mday,
|
||||
ptm->tm_hour,
|
||||
ptm->tm_min,
|
||||
ptm->tm_sec,
|
||||
(long int)ts.tv_nsec,
|
||||
1900 + ptm->tm_year);
|
||||
|
||||
assert(nout < TIME_BUF_LEN);
|
||||
return resultbuf;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove the trailing newline from the ctime output,
|
||||
being careful not to assume that the output is fixed-width. */
|
||||
*strchr (r, '\n') = '\0';
|
||||
return r;
|
||||
/* The time cannot be represented as a struct tm.
|
||||
Output it as an integer. */
|
||||
return format_date (ts, '@');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ proc find_version {} {
|
||||
|
||||
# Run find and leave the output in $comp_output.
|
||||
# Called by individual test scripts.
|
||||
proc do_find_start { suffix findprogram flags passfail options {infile ""}} {
|
||||
proc do_find_start { suffix findprogram flags passfail options infile output } {
|
||||
global verbose
|
||||
global comp_output
|
||||
|
||||
@@ -112,6 +112,11 @@ proc do_find_start { suffix findprogram flags passfail options {infile ""}} {
|
||||
# set compareprog "cmp"
|
||||
set compareprog "diff -u"
|
||||
|
||||
set tmpout ""
|
||||
if { $output != "" } {
|
||||
error "The output option is not supported yet"
|
||||
}
|
||||
|
||||
set outfile "$testbase.xo"
|
||||
if {$infile != ""} then {
|
||||
set infile "[file dirname [file dirname $testbase]]/inputs/$infile"
|
||||
@@ -168,12 +173,18 @@ proc do_find_start { suffix findprogram flags passfail options {infile ""}} {
|
||||
}
|
||||
|
||||
|
||||
proc find_start { passfail options {infile ""}} {
|
||||
proc find_start { passfail options {infile ""} {output ""}} {
|
||||
global OLDFIND
|
||||
global FTSFIND
|
||||
global FINDFLAGS
|
||||
global comp_output
|
||||
|
||||
if {$infile != ""} then {
|
||||
set msg "Did not expect infile parameter to be set"
|
||||
untested $msg
|
||||
error $msg
|
||||
}
|
||||
|
||||
if {[which $FTSFIND] == 0} then {
|
||||
error "$FTSFIND, program does not exist"
|
||||
exit 1
|
||||
@@ -186,8 +197,8 @@ proc find_start { passfail options {infile ""}} {
|
||||
# Now run the test with each binary, once with each optimisation level.
|
||||
foreach optlevel {0 1 2 3} {
|
||||
set flags "$FINDFLAGS -O$optlevel"
|
||||
do_find_start old-O$optlevel $OLDFIND $flags $passfail $options $infile
|
||||
do_find_start new-O$optlevel $FTSFIND $flags $passfail $options $infile
|
||||
do_find_start old-O$optlevel $OLDFIND $flags $passfail $options $infile $output
|
||||
do_find_start new-O$optlevel $FTSFIND $flags $passfail $options $infile $output
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,7 +208,7 @@ proc find_exit {} {
|
||||
catch "exec rm -f find.out cmp.out"
|
||||
}
|
||||
|
||||
proc unsafe_path {} {
|
||||
proc path_setting_is_unsafe {} {
|
||||
global env;
|
||||
set itemlist [ split $env(PATH) : ]
|
||||
foreach item $itemlist {
|
||||
@@ -216,7 +227,7 @@ proc unsafe_path {} {
|
||||
}
|
||||
|
||||
proc safe_path [ ] {
|
||||
if { [ unsafe_path ] } {
|
||||
if { [ path_setting_is_unsafe ] } {
|
||||
warning { Cannot perform test as your $PATH environment variable includes a reference to the current directory or a directory name which is not absolute }
|
||||
untested { skipping this test because your $PATH variable is wrongly set }
|
||||
return 0
|
||||
|
||||
10
find/testsuite/find.gnu/execdir-pwd.exp
Normal file
10
find/testsuite/find.gnu/execdir-pwd.exp
Normal file
@@ -0,0 +1,10 @@
|
||||
# tests for -execdir pwd \+
|
||||
if { [ safe_path ] } {
|
||||
exec rm -rf tmp
|
||||
exec mkdir tmp
|
||||
exec touch tmp/foo
|
||||
set expected [ exec sh -c "cd tmp && /bin/pwd" ]
|
||||
verbose "Expected output for the pwd invoked by find is is $expected" 2
|
||||
find_start p {tmp -name foo -execdir /bin/pwd \; } "" $expected
|
||||
exec rm -rf tmp
|
||||
}
|
||||
@@ -58,7 +58,7 @@ getline getopt human idcache lstat malloc memcmp memset mktime \
|
||||
modechange pathmax quotearg realloc regex rpmatch savedir \
|
||||
stpcpy strdup strftime strstr strtol strtoul strtoull strtoumax \
|
||||
xalloc xalloc-die xgetcwd xstrtod xstrtol xstrtoumax yesno human filemode \
|
||||
getline stpcpy canonicalize mountlist closeout gettext stat-macros"
|
||||
getline stpcpy canonicalize mountlist closeout gettext stat-macros stat-time"
|
||||
|
||||
# We need regex to ensure that we can build on platforms like
|
||||
# Solaris which lack those functions.
|
||||
|
||||
Reference in New Issue
Block a user