From: "Erich E. Hoover" Subject: [PATCH] ntdll: Fix converting large 32-bit time_t when time_t is signed. Message-Id: Date: Sat, 21 Nov 2020 22:42:43 -0700 Found this while trying to fix something else. If time_t is treated as signed (32-bit Linux) and you have a time_t value where the high bit is set then when you convert it to 64-bit you get an improperly sign-extended value. See the included test for an example (make sure you run the 32-bit tests). Best, Erich From 3ecfa6ca29bdb94d754e6638bed49edbe56923a2 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Sat, 21 Nov 2020 22:33:20 -0700 Subject: ntdll: Fix converting large 32-bit time_t when time_t is signed. Signed-off-by: Erich E. Hoover --- dlls/ntdll/tests/file.c | 12 ++++++++++++ dlls/ntdll/unix/file.c | 16 +++++++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c index 8b9ec4f624d..2507437c8c3 100644 --- a/dlls/ntdll/tests/file.c +++ b/dlls/ntdll/tests/file.c @@ -1361,6 +1361,18 @@ static void test_file_basic_information(void) ok ( res == STATUS_SUCCESS, "can't set system attribute, NtSetInformationFile returned %x\n", res ); ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status is %x\n", U(io).Status ); + memset(&fbi2, 0, sizeof(fbi2)); + fbi2.LastAccessTime.QuadPart = 0x200deadcafebeef; + U(io).Status = 0xdeadbeef; + res = pNtSetInformationFile(h, &io, &fbi2, sizeof(fbi2), FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't set system attribute, NtSetInformationFile returned %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't set system attribute, io.Status is %x\n", U(io).Status ); + res = pNtQueryInformationFile(h, &io, &fbi, sizeof(fbi), FileBasicInformation); + ok ( res == STATUS_SUCCESS, "can't get system attribute, NtQueryInformationFile returned %x\n", res ); + ok ( U(io).Status == STATUS_SUCCESS, "can't get system attribute, io.Status is %x\n", U(io).Status ); + ok ( fbi2.LastAccessTime.QuadPart == fbi.LastAccessTime.QuadPart, + "large access time set/get does not match.\n" ); + memset(&fbi2, 0, sizeof(fbi2)); res = pNtQueryInformationFile(h, &io, &fbi2, sizeof fbi2, FileBasicInformation); ok ( res == STATUS_SUCCESS, "can't get attributes, res %x\n", res); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index cf413f46e5c..4c2398c3cc0 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c @@ -1628,12 +1628,22 @@ static NTSTATUS set_file_times( int fd, const LARGE_INTEGER *mtime, const LARGE_ } +/* fix converting 32-bit time_t if the high bit set on systems where time_t is signed */ +static inline ULONGLONG get_quad_time(time_t time) +{ + if (sizeof(time_t) == sizeof(int)) + return (ULONGLONG)(ULONG)time; + else + return (ULONGLONG)time; +} + + static inline void get_file_times( const struct stat *st, LARGE_INTEGER *mtime, LARGE_INTEGER *ctime, LARGE_INTEGER *atime, LARGE_INTEGER *creation ) { - mtime->QuadPart = st->st_mtime * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970; - ctime->QuadPart = st->st_ctime * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970; - atime->QuadPart = st->st_atime * (ULONGLONG)TICKSPERSEC + TICKS_1601_TO_1970; + mtime->QuadPart = get_quad_time(st->st_mtime) * TICKSPERSEC + TICKS_1601_TO_1970; + ctime->QuadPart = get_quad_time(st->st_ctime) * TICKSPERSEC + TICKS_1601_TO_1970; + atime->QuadPart = get_quad_time(st->st_atime) * TICKSPERSEC + TICKS_1601_TO_1970; #ifdef HAVE_STRUCT_STAT_ST_MTIM mtime->QuadPart += st->st_mtim.tv_nsec / 100; #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC) -- 2.17.1