diff options
author | Eugene Kliuchnikov <eustas.ru@gmail.com> | 2022-12-22 16:05:25 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-12-22 16:05:25 +0100 |
commit | 509d4419bd2e7f40ac97106324abf0b49d9fd7ff (patch) | |
tree | 3c979c90e4e9e27704e426b5fe8b288984f3503e /c/tools/brotli.c | |
parent | 81dc1c86c3cf5adc387941b5a47b5a937659c9e8 (diff) | |
download | brotli-509d4419bd2e7f40ac97106324abf0b49d9fd7ff.zip brotli-509d4419bd2e7f40ac97106324abf0b49d9fd7ff.tar.gz brotli-509d4419bd2e7f40ac97106324abf0b49d9fd7ff.tar.bz2 |
Copy ns time stat (#992)
Diffstat (limited to 'c/tools/brotli.c')
-rw-r--r-- | c/tools/brotli.c | 45 |
1 files changed, 35 insertions, 10 deletions
diff --git a/c/tools/brotli.c b/c/tools/brotli.c index 80ead72..102a87a 100644 --- a/c/tools/brotli.c +++ b/c/tools/brotli.c @@ -26,11 +26,7 @@ #include "../common/constants.h" #include "../common/version.h" -#if !defined(_WIN32) -#include <unistd.h> -#include <utime.h> -#define MAKE_BINARY(FILENO) (FILENO) -#else +#if defined(_WIN32) #include <io.h> #include <share.h> #include <sys/utime.h> @@ -72,7 +68,23 @@ static int ms_open(const char* filename, int oflag, int pmode) { _sopen_s(&result, filename, oflag | O_BINARY, _SH_DENYNO, pmode); return result; } -#endif /* WIN32 */ +#else /* !defined(_WIN32) */ +#include <unistd.h> +#include <utime.h> +#define MAKE_BINARY(FILENO) (FILENO) +#endif /* defined(_WIN32) */ + +#if defined(__APPLE__) && !defined(_POSIX_C_SOURCE) +#define HAVE_UTIMENSAT 1 +#define ATIME_NSEC(S) ((S)->st_atimespec.tv_nsec) +#define MTIME_NSEC(S) ((S)->st_mtimespec.tv_nsec) +#elif defined(_WIN32) || !defined(AT_SYMLINK_NOFOLLOW) +#define HAVE_UTIMENSAT 0 +#else +#define HAVE_UTIMENSAT 1 +#define ATIME_NSEC(S) ((S)->st_atim.tv_nsec) +#define MTIME_NSEC(S) ((S)->st_mtim.tv_nsec) +#endif typedef enum { COMMAND_COMPRESS, @@ -664,12 +676,27 @@ static int64_t FileSize(const char* path) { return retval; } +static int CopyTimeStat(const struct stat* statbuf, const char* output_path) { +#if HAVE_UTIMENSAT + struct timespec times[2]; + times[0].tv_sec = statbuf->st_atime; + times[0].tv_nsec = ATIME_NSEC(statbuf); + times[1].tv_sec = statbuf->st_mtime; + times[1].tv_nsec = MTIME_NSEC(statbuf); + return utimensat(AT_FDCWD, output_path, times, AT_SYMLINK_NOFOLLOW); +#else + struct utimbuf times; + times.actime = statbuf->st_atime; + times.modtime = statbuf->st_mtime; + return utime(output_path, ×); +#endif +} + /* Copy file times and permissions. TODO(eustas): this is a "best effort" implementation; honest cross-platform fully featured implementation is way too hacky; add more hacks by request. */ static void CopyStat(const char* input_path, const char* output_path) { struct stat statbuf; - struct utimbuf times; int res; if (input_path == 0 || output_path == 0) { return; @@ -677,9 +704,7 @@ static void CopyStat(const char* input_path, const char* output_path) { if (stat(input_path, &statbuf) != 0) { return; } - times.actime = statbuf.st_atime; - times.modtime = statbuf.st_mtime; - utime(output_path, ×); + res = CopyTimeStat(&statbuf, output_path); res = chmod(output_path, statbuf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (res != 0) { fprintf(stderr, "setting access bits failed for [%s]: %s\n", |