diff options
author | Steve Bennett <steveb@workware.net.au> | 2016-08-27 14:09:31 +1000 |
---|---|---|
committer | Steve Bennett <steveb@workware.net.au> | 2018-09-21 12:57:41 +1000 |
commit | fd07366b2c527527425dce94d1c337168ea86638 (patch) | |
tree | 4e5de3da314e9d70cacfcc818327c5b193d40133 | |
parent | 022f90263261694bbcb98373ad7e5a282ab74453 (diff) | |
download | jimtcl-fd07366b2c527527425dce94d1c337168ea86638.zip jimtcl-fd07366b2c527527425dce94d1c337168ea86638.tar.gz jimtcl-fd07366b2c527527425dce94d1c337168ea86638.tar.bz2 |
file: Add microsecond resolution for mtime: mtimeus
Note that actual support is dependent upon the underlying operating
system and filesystem.
Signed-off-by: Steve Bennett <steveb@workware.net.au>
-rw-r--r-- | auto.def | 5 | ||||
-rw-r--r-- | jim-file.c | 75 | ||||
-rw-r--r-- | jim_tcl.txt | 14 |
3 files changed, 78 insertions, 16 deletions
@@ -130,6 +130,11 @@ if {[cc-check-functions sysinfo]} { } } +cc-with {-includes {sys/types.h sys/stat.h}} { + cc-check-members "struct stat.st_mtimespec" + cc-check-members "struct stat.st_mtim" +} + cc-with {-includes fcntl.h} { cc-check-types "struct flock" } @@ -77,6 +77,13 @@ #define ISWINDOWS 0 #endif +/* extract nanosecond resolution mtime from struct stat */ +#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC) + #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000) +#elif defined(HAVE_STRUCT_STAT_ST_MTIM) + #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000) +#endif + /* *---------------------------------------------------------------------- * @@ -169,6 +176,9 @@ static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat AppendStatElement(interp, listObj, "atime", sb->st_atime); AppendStatElement(interp, listObj, "mtime", sb->st_mtime); AppendStatElement(interp, listObj, "ctime", sb->st_ctime); +#ifdef STAT_MTIME_US + AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb)); +#endif Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1)); Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1)); @@ -610,37 +620,65 @@ static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_OK; } +/** + * Set file atime/mtime to the given time in microseconds since the epoch. + */ +static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us) +{ +#ifdef HAVE_UTIMES + struct timeval times[2]; + + times[1].tv_sec = times[0].tv_sec = us / 1000000; + times[1].tv_usec = times[0].tv_usec = us % 1000000; + + if (utimes(filename, times) != 0) { + Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno)); + return JIM_ERR; + } + return JIM_OK; +#else + Jim_SetResultString(interp, "Not implemented", -1); + return JIM_ERR; +#endif +} + static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct stat sb; if (argc == 2) { -#ifdef HAVE_UTIMES - jim_wide newtime; - struct timeval times[2]; - - if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) { + jim_wide secs; + if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) { return JIM_ERR; } + return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000); + } + if (file_stat(interp, argv[0], &sb) != JIM_OK) { + return JIM_ERR; + } + Jim_SetResultInt(interp, sb.st_mtime); + return JIM_OK; +} - times[1].tv_sec = times[0].tv_sec = newtime; - times[1].tv_usec = times[0].tv_usec = 0; +#ifdef STAT_MTIME_US +static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + struct stat sb; - if (utimes(Jim_String(argv[0]), times) != 0) { - Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno)); + if (argc == 2) { + jim_wide us; + if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) { return JIM_ERR; } -#else - Jim_SetResultString(interp, "Not implemented", -1); - return JIM_ERR; -#endif + return JimSetFileTimes(interp, Jim_String(argv[0]), us); } if (file_stat(interp, argv[0], &sb) != JIM_OK) { return JIM_ERR; } - Jim_SetResultInt(interp, sb.st_mtime); + Jim_SetResultInt(interp, STAT_MTIME_US(sb)); return JIM_OK; } +#endif static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -765,6 +803,15 @@ static const jim_subcmd_type file_command_table[] = { 2, /* Description: Get or set last modification time */ }, +#ifdef STAT_MTIME_US + { "mtimeus", + "name ?time?", + file_cmd_mtimeus, + 1, + 2, + /* Description: Get or set last modification time in microseconds */ + }, +#endif { "copy", "?-force? source dest", file_cmd_copy, diff --git a/jim_tcl.txt b/jim_tcl.txt index efe13c5..64642a9 100644 --- a/jim_tcl.txt +++ b/jim_tcl.txt @@ -3,7 +3,7 @@ Jim Tcl(n) NAME ---- -Jim Tcl v0.78 - reference manual for the Jim Tcl scripting language +Jim Tcl v0.78+ - reference manual for the Jim Tcl scripting language SYNOPSIS -------- @@ -52,6 +52,10 @@ Some notable differences with Tcl 8.5/8.6 are: RECENT CHANGES -------------- +Changes since 0.78 +~~~~~~~~~~~~~~~~~~ +1. Add `file mtimeus` for high resolution file timestamps + Changes between 0.77 and 0.78 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Add serial/tty support with `aio tty` @@ -2373,6 +2377,12 @@ abbreviation for +'option'+ is acceptable. The valid options are: error is generated. If +'time'+ is given, sets the modification time of the file to the given value. ++*file mtimeus* 'name ?time_us?'+:: + As for `file mtime` except the time value is in microseconds + since the epoch (see also `clock microseconds`). + Note that some platforms and some filesystems don't support high + resolution timestamps for files. + +*file normalize* 'name'+:: Return the normalized path of +'name'+. See 'realpath(3)'. @@ -2410,7 +2420,7 @@ abbreviation for +'option'+ is acceptable. The valid options are: Invoke the 'stat' kernel call on +'name'+, and return the result as a dictionary with the following keys: 'atime', 'ctime', 'dev', 'gid', 'ino', 'mode', 'mtime', - 'nlink', 'size', 'type', 'uid'. + 'nlink', 'size', 'type', 'uid', 'mtimeus' (if supported - see `file mtimeus`) Each element except 'type' is a decimal string with the value of the corresponding field from the 'stat' return structure; see the manual entry for 'stat' for details on the meanings of the values. |