From 1ee7ecb1f08cbc400b8ea0391c107e4ff890e25f Mon Sep 17 00:00:00 2001 From: "Markus F.X.J. Oberhumer" Date: Sun, 22 Oct 2023 13:29:26 +0200 Subject: [PATCH] all: prefer using utimensat() --- CMakeLists.txt | 29 ++++++++++++++++++++++++++++- src/work.cpp | 26 +++++++++++++++++++++++--- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index abaa2610..1c1e100a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -169,6 +169,28 @@ endif() include(CheckCCompilerFlag) include(CheckIncludeFile) +include(CheckFunctionExists) +include(CheckStructHasMember) +include(CheckSymbolExists) + +if(NOT DEFINED HAVE_UNISTD_H) + check_include_file("unistd.h" HAVE_UNISTD_H) +endif() +if(NOT DEFINED HAVE_UTIMENSAT) + check_function_exists(utimensat HAVE_UTIMENSAT_FUNCTION__) + if(HAVE_UTIMENSAT_FUNCTION__) + check_symbol_exists(utimensat "sys/types.h;fcntl.h;sys/stat.h" HAVE_UTIMENSAT_SYMBOL__) + if(HAVE_UTIMENSAT_SYMBOL__) + CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtim.tv_nsec "sys/types.h;fcntl.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + if (NOT HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + CHECK_STRUCT_HAS_MEMBER("struct stat" st_mtimespec.tv_nsec "sys/types.h;fcntl.h;sys/stat.h" HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) + endif() + if (HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC OR HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) + set(HAVE_UTIMENSAT 1) + endif() + endif() + endif() +endif() if(UPX_CONFIG_DISABLE_WSTRICT) # enable all basic warnings @@ -382,7 +404,6 @@ set(t upx_vendor_zlib) upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) target_compile_definitions(${t} PRIVATE HAVE_VSNPRINTF=1) -check_include_file("unistd.h" HAVE_UNISTD_H) if(HAVE_UNISTD_H) target_compile_definitions(${t} PRIVATE HAVE_UNISTD_H=1) endif() @@ -429,6 +450,12 @@ endif() if(NOT UPX_CONFIG_DISABLE_ZSTD) target_compile_definitions(${t} PRIVATE WITH_ZSTD=1) endif() +if(HAVE_UTIMENSAT) + target_compile_definitions(${t} PRIVATE USE_UTIMENSAT=1) + if (HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) + target_compile_definitions(${t} PRIVATE HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC=1) + endif() +endif() #upx_compile_target_debug_with_O2(${t}) upx_sanitize_target(${t}) if(MSVC_FRONTEND) diff --git a/src/work.cpp b/src/work.cpp index b2db6695..a5cfda7f 100644 --- a/src/work.cpp +++ b/src/work.cpp @@ -30,13 +30,20 @@ // of class PackerBase which then does the actual work. // And see p_com.cpp for a simple executable format. +#include "headers.h" +#if USE_UTIMENSAT +#include +#include +#include +#endif #include "conf.h" #include "file.h" #include "packmast.h" #include "ui.h" #include "util/membuffer.h" -#if (ACC_OS_DOS32) && defined(__DJGPP__) +#if USE_UTIMENSAT && defined(AT_FDCWD) +#elif (ACC_OS_DOS32) && defined(__DJGPP__) #define USE_FTIME 1 #elif ((ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_CC_INTELC || ACC_CC_MSC)) #define USE__FUTIME 1 @@ -95,16 +102,29 @@ static void copy_file_contents(const char *iname, const char *oname, OpenMode om static void copy_file_attributes(const struct stat *st, const char *oname, bool preserve_mode, bool preserve_ownership, bool preserve_timestamp) noexcept { -#if USE_UTIME // copy time stamp if (preserve_timestamp) { +#if USE_UTIMENSAT && defined(AT_FDCWD) + struct timespec times[2]; + memset(×[0], 0, sizeof(times)); +#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC + times[0] = st->st_atimespec; + times[1] = st->st_mtimespec; +#else + times[0] = st->st_atim; + times[1] = st->st_mtim; +#endif + int r = utimensat(AT_FDCWD, oname, ×[0], 0); + IGNORE_ERROR(r); +#elif USE_UTIME struct utimbuf u; + memset(&u, 0, sizeof(u)); u.actime = st->st_atime; u.modtime = st->st_mtime; int r = utime(oname, &u); IGNORE_ERROR(r); - } #endif + } #if HAVE_CHOWN // copy the group ownership if (preserve_ownership) {