mirror of
https://github.com/upx/upx
synced 2025-09-28 19:06:07 +08:00
src: prefer using SetFileTime() on Windows
This commit is contained in:
parent
27f155374a
commit
37d393cbc8
|
@ -37,7 +37,7 @@
|
|||
#pragma warning(disable : 4201 4214 4514)
|
||||
#endif
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
/* avoid warnings in some versions of <windows.h> */
|
||||
/* avoid warnings in some older versions of <windows.h> */
|
||||
#pragma warning(disable : 5105)
|
||||
#endif
|
||||
|
||||
|
|
102
src/work.cpp
102
src/work.cpp
|
@ -36,6 +36,9 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#include "util/windows_lean.h" // _get_osfhandle, GetFileTime, SetFileTime
|
||||
#endif
|
||||
#include "conf.h"
|
||||
#include "file.h"
|
||||
#include "packmast.h"
|
||||
|
@ -43,6 +46,8 @@
|
|||
#include "util/membuffer.h"
|
||||
|
||||
#if USE_UTIMENSAT && defined(AT_FDCWD)
|
||||
#elif (defined(_WIN32) || defined(__CYGWIN__)) && 1
|
||||
#define USE_SETFILETIME 1
|
||||
#elif (ACC_OS_DOS32) && defined(__DJGPP__)
|
||||
#define USE_FTIME 1
|
||||
#elif ((ACC_OS_WIN32 || ACC_OS_WIN64) && (ACC_CC_INTELC || ACC_CC_MSC))
|
||||
|
@ -62,6 +67,18 @@
|
|||
// util
|
||||
**************************************************************************/
|
||||
|
||||
namespace {
|
||||
|
||||
struct XStat {
|
||||
struct stat st;
|
||||
#if USE_SETFILETIME
|
||||
FILETIME ft_atime;
|
||||
FILETIME ft_mtime;
|
||||
#elif USE_FTIME
|
||||
struct ftime ft_ftime;
|
||||
#endif
|
||||
};
|
||||
|
||||
// ignore errors in some cases and silence __attribute__((__warn_unused_result__))
|
||||
#define IGNORE_ERROR(var) ACC_UNUSED(var)
|
||||
|
||||
|
@ -79,7 +96,29 @@ static constexpr int get_open_flags(OpenMode om) noexcept {
|
|||
return O_RDONLY | O_BINARY; // will cause an error if file does not exist
|
||||
}
|
||||
|
||||
static void copy_file_contents(const char *iname, const char *oname, OpenMode om) may_throw {
|
||||
// set file time of an open file
|
||||
static void set_fd_timestamp(int fd, const XStat *xst) noexcept {
|
||||
#if USE_SETFILETIME
|
||||
BOOL r = SetFileTime((HANDLE) _get_osfhandle(fd), nullptr, &xst->ft_atime, &xst->ft_mtime);
|
||||
IGNORE_ERROR(r);
|
||||
#elif USE_FTIME
|
||||
auto ft_ftime = xst->ft_ftime; // djgpp2 libc bug: not const, so use a copy
|
||||
int r = setftime(fd, &ft_ftime);
|
||||
IGNORE_ERROR(r);
|
||||
#elif USE__FUTIME
|
||||
struct _utimbuf u = {};
|
||||
u.actime = xst->st.st_atime;
|
||||
u.modtime = xst->st.st_mtime;
|
||||
int r = _futime(fd, &u);
|
||||
IGNORE_ERROR(r);
|
||||
#endif
|
||||
// maybe unused
|
||||
UNUSED(fd);
|
||||
UNUSED(xst);
|
||||
}
|
||||
|
||||
static void copy_file_contents(const char *iname, const char *oname, OpenMode om,
|
||||
const XStat *oname_timestamp) may_throw {
|
||||
InputFile fi;
|
||||
fi.sopen(iname, get_open_flags(RO_MUST_EXIST), SH_DENYWR);
|
||||
fi.seek(0, SEEK_SET);
|
||||
|
@ -96,17 +135,19 @@ static void copy_file_contents(const char *iname, const char *oname, OpenMode om
|
|||
break;
|
||||
fo.write(buf, bytes);
|
||||
}
|
||||
if (oname_timestamp != nullptr)
|
||||
set_fd_timestamp(fo.getFd(), oname_timestamp);
|
||||
fi.closex();
|
||||
fo.closex();
|
||||
}
|
||||
|
||||
static void copy_file_attributes(const struct stat *st, const char *oname, bool preserve_mode,
|
||||
static void copy_file_attributes(const XStat *xst, const char *oname, bool preserve_mode,
|
||||
bool preserve_ownership, bool preserve_timestamp) noexcept {
|
||||
const struct stat *const st = &xst->st;
|
||||
// copy time stamp
|
||||
if (preserve_timestamp) {
|
||||
#if USE_UTIMENSAT && defined(AT_FDCWD)
|
||||
struct timespec times[2];
|
||||
memset(×[0], 0, sizeof(times));
|
||||
struct timespec times[2] = {};
|
||||
#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
|
||||
// macOS
|
||||
times[0] = st->st_atimespec;
|
||||
|
@ -119,8 +160,7 @@ static void copy_file_attributes(const struct stat *st, const char *oname, bool
|
|||
int r = utimensat(AT_FDCWD, oname, ×[0], 0);
|
||||
IGNORE_ERROR(r);
|
||||
#elif USE_UTIME
|
||||
struct utimbuf u;
|
||||
mem_clear(&u);
|
||||
struct utimbuf u = {};
|
||||
u.actime = st->st_atime;
|
||||
u.modtime = st->st_mtime;
|
||||
int r = utime(oname, &u);
|
||||
|
@ -149,6 +189,7 @@ static void copy_file_attributes(const struct stat *st, const char *oname, bool
|
|||
}
|
||||
#endif
|
||||
// maybe unused
|
||||
UNUSED(xst);
|
||||
UNUSED(st);
|
||||
UNUSED(oname);
|
||||
UNUSED(preserve_mode);
|
||||
|
@ -156,6 +197,8 @@ static void copy_file_attributes(const struct stat *st, const char *oname, bool
|
|||
UNUSED(preserve_timestamp);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/*************************************************************************
|
||||
// process one file
|
||||
**************************************************************************/
|
||||
|
@ -164,8 +207,8 @@ void do_one_file(const char *const iname, char *const oname) may_throw {
|
|||
oname[0] = 0; // make empty
|
||||
|
||||
// check iname stat
|
||||
struct stat st;
|
||||
mem_clear(&st);
|
||||
XStat xst = {};
|
||||
struct stat &st = xst.st;
|
||||
#if HAVE_LSTAT
|
||||
int rr = lstat(iname, &st);
|
||||
#else
|
||||
|
@ -212,14 +255,16 @@ void do_one_file(const char *const iname, char *const oname) may_throw {
|
|||
InputFile fi;
|
||||
fi.sopen(iname, get_open_flags(RO_MUST_EXIST), SH_DENYWR);
|
||||
|
||||
#if USE_FTIME
|
||||
struct ftime fi_ftime;
|
||||
mem_clear(&fi_ftime);
|
||||
if (opt->preserve_timestamp) {
|
||||
if (getftime(fi.getFd(), &fi_ftime) != 0)
|
||||
#if USE_SETFILETIME
|
||||
if (GetFileTime((HANDLE) _get_osfhandle(fi.getFd()), nullptr, &xst.ft_atime,
|
||||
&xst.ft_mtime) == 0)
|
||||
throwIOException("cannot determine file timestamp");
|
||||
#elif USE_FTIME
|
||||
if (getftime(fi.getFd(), &xst.ft_ftime) != 0)
|
||||
throwIOException("cannot determine file timestamp");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// open output file
|
||||
// NOTE: only use "preserve_link" if you really need it, e.g. it can fail
|
||||
|
@ -248,8 +293,7 @@ void do_one_file(const char *const iname, char *const oname) may_throw {
|
|||
if (opt->output_name && preserve_link) {
|
||||
flags = get_open_flags(WO_CREATE_OR_TRUNCATE);
|
||||
#if HAVE_LSTAT
|
||||
struct stat ost;
|
||||
mem_clear(&ost);
|
||||
struct stat ost = {};
|
||||
int r = lstat(tname, &ost);
|
||||
if (r == 0 && S_ISREG(ost.st_mode)) {
|
||||
preserve_link = ost.st_nlink >= 2;
|
||||
|
@ -298,18 +342,8 @@ void do_one_file(const char *const iname, char *const oname) may_throw {
|
|||
throwInternalError("invalid command");
|
||||
|
||||
// copy time stamp
|
||||
if (oname[0] && opt->preserve_timestamp && fo.isOpen()) {
|
||||
#if USE_FTIME
|
||||
int r = setftime(fo.getFd(), &fi_ftime);
|
||||
IGNORE_ERROR(r);
|
||||
#elif USE__FUTIME
|
||||
struct _utimbuf u;
|
||||
u.actime = st.st_atime;
|
||||
u.modtime = st.st_mtime;
|
||||
int r = _futime(fo.getFd(), &u);
|
||||
IGNORE_ERROR(r);
|
||||
#endif
|
||||
}
|
||||
if (oname[0] && opt->preserve_timestamp && fo.isOpen())
|
||||
set_fd_timestamp(fo.getFd(), &xst);
|
||||
|
||||
// close files
|
||||
fi.closex();
|
||||
|
@ -323,9 +357,10 @@ void do_one_file(const char *const iname, char *const oname) may_throw {
|
|||
if (!makebakname(bakname, sizeof(bakname), iname))
|
||||
throwIOException("could not create a backup file name");
|
||||
if (preserve_link) {
|
||||
copy_file_contents(iname, bakname, WO_MUST_CREATE);
|
||||
copy_file_attributes(&st, bakname, true, true, true);
|
||||
copy_file_contents(oname, iname, WO_MUST_EXIST_TRUNCATE);
|
||||
copy_file_contents(iname, bakname, WO_MUST_CREATE, &xst);
|
||||
copy_file_attributes(&xst, bakname, true, true, true);
|
||||
const XStat *xstamp = opt->preserve_timestamp ? &xst : nullptr;
|
||||
copy_file_contents(oname, iname, WO_MUST_EXIST_TRUNCATE, xstamp);
|
||||
FileBase::unlink(oname);
|
||||
copy_timestamp_only = true;
|
||||
} else {
|
||||
|
@ -333,7 +368,8 @@ void do_one_file(const char *const iname, char *const oname) may_throw {
|
|||
FileBase::rename(oname, iname);
|
||||
}
|
||||
} else if (preserve_link) {
|
||||
copy_file_contents(oname, iname, WO_MUST_EXIST_TRUNCATE);
|
||||
const XStat *xstamp = opt->preserve_timestamp ? &xst : nullptr;
|
||||
copy_file_contents(oname, iname, WO_MUST_EXIST_TRUNCATE, xstamp);
|
||||
FileBase::unlink(oname);
|
||||
copy_timestamp_only = true;
|
||||
} else {
|
||||
|
@ -348,9 +384,9 @@ void do_one_file(const char *const iname, char *const oname) may_throw {
|
|||
oname[0] = 0; // done with oname
|
||||
const char *name = opt->output_name ? opt->output_name : iname;
|
||||
if (copy_timestamp_only)
|
||||
copy_file_attributes(&st, name, false, false, opt->preserve_timestamp);
|
||||
copy_file_attributes(&xst, name, false, false, opt->preserve_timestamp);
|
||||
else
|
||||
copy_file_attributes(&st, name, opt->preserve_mode, opt->preserve_ownership,
|
||||
copy_file_attributes(&xst, name, opt->preserve_mode, opt->preserve_ownership,
|
||||
opt->preserve_timestamp);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user