From 80c783d8a3c7e45827a3ea3160549a49bac5d6a0 Mon Sep 17 00:00:00 2001 From: Kevin B Kenny Date: Mon, 1 Nov 2004 16:58:35 +0000 Subject: Second part of fix for Bug 926106 --- ChangeLog | 12 +++++++++ tests/cmdAH.test | 14 +++++++++- win/tclWin32Dll.c | 6 ++--- win/tclWinFile.c | 78 +++++++++++++++++++++++++++++++++++++++---------------- win/tclWinInt.h | 4 +-- 5 files changed, 85 insertions(+), 29 deletions(-) diff --git a/ChangeLog b/ChangeLog index e23f2e6..f6a4b68 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2004-11-01 Kevin B. Kenny + + * win/tclWinFile.c (FromCTime, TclpUtime): Replaced a call to the + Posix 'utime' function with calls to Windows-API equivalents, to + avoid a bug where the VC++ versions misconvert times across a + Daylight Saving Time boundary. [Bug 926106] + * win/tclWinInt.h (TclWinProcs): + * win/tclWin32Dll.c (asciiProcs, unicodeProcs): Removed now-unused + reference to 'utime'. + * tests/cmdAH.test (cmdAH-24.12): Added test case for the + above bug. + 2004-11-01 Donal K. Fellows * generic/tclExecute.c (TclExecuteByteCode): Make INST_EQ and diff --git a/tests/cmdAH.test b/tests/cmdAH.test index 7173908..25db252 100644 --- a/tests/cmdAH.test +++ b/tests/cmdAH.test @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: cmdAH.test,v 1.49 2004/10/31 23:59:49 dgp Exp $ +# RCS: @(#) $Id: cmdAH.test,v 1.50 2004/11/01 16:58:37 kennykb Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.1 @@ -1231,6 +1231,18 @@ test cmdAH-24.11 {Tcl_FileObjCmd: mtime touch with non-ascii chars} win { removeFile touch.me rename waitForEvenSecondForFAT {} +test cmdAH-24.12 {Tcl_FileObjCmd: mtime and daylight savings} { + set name [file join [temporaryDirectory] clockchange] + + file delete -force $name + close [open $name w] + set time [clock scan "21:00:00 October 30 2004 GMT"] + file mtime $name $time + set newmtime [file mtime $name] + file delete $name + expr {$newmtime == $time ? 1 : "$newmtime != $time"} +} {1} + # owned test cmdAH-25.1 {Tcl_FileObjCmd: owned} { diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c index c4f6e5d..59746d2 100644 --- a/win/tclWin32Dll.c +++ b/win/tclWin32Dll.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWin32Dll.c,v 1.39 2004/09/01 17:41:03 hobbs Exp $ + * RCS: @(#) $Id: tclWin32Dll.c,v 1.40 2004/11/01 16:58:37 kennykb Exp $ */ #include "tclWinInt.h" @@ -136,7 +136,7 @@ static TclWinProcs asciiProcs = { */ NULL, NULL, - (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime, + /* deleted (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime, */ NULL, NULL, /* Security SDK - not available on 95,98,ME */ @@ -187,7 +187,7 @@ static TclWinProcs unicodeProcs = { */ NULL, NULL, - (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime, + /* deleted (int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime, */ NULL, NULL, /* Security SDK - will be filled in on NT,XP,2000,2003 */ diff --git a/win/tclWinFile.c b/win/tclWinFile.c index cb6ab53..ab9a601 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinFile.c,v 1.68 2004/10/30 21:36:48 kennykb Exp $ + * RCS: @(#) $Id: tclWinFile.c,v 1.69 2004/11/01 16:58:37 kennykb Exp $ */ //#define _WIN32_WINNT 0x0500 @@ -162,6 +162,8 @@ typedef enum _FINDEX_SEARCH_OPS { /* Other typedefs required by this code */ static time_t ToCTime(FILETIME fileTime); +static void FromCTime( time_t posixTime, + FILETIME* fileTime ); typedef NET_API_STATUS NET_API_FUNCTION NETUSERGETINFOPROC (LPWSTR servername, LPWSTR username, DWORD level, LPBYTE *bufptr); @@ -1998,9 +2000,8 @@ NativeStatMode(DWORD attr, int checkLinks, int isExec) */ static time_t -ToCTime( FILETIME fileTime ) /* UTC Time to convert to local time_t. */ +ToCTime( FILETIME fileTime ) /* UTC time */ { - LARGE_INTEGER convertedTime; convertedTime.LowPart = fileTime.dwLowDateTime; convertedTime.HighPart = (LONG) fileTime.dwHighDateTime; @@ -2009,6 +2010,31 @@ ToCTime( FILETIME fileTime ) /* UTC Time to convert to local time_t. */ / (Tcl_WideInt) 10000000); } + +/* + *------------------------------------------------------------------------ + * + * FromCTime -- + * + * Converts a time_t to a Windows FILETIME + * + * Results: + * Returns the count of 100-ns ticks seconds from the Windows epoch. + * + *------------------------------------------------------------------------ + */ + +static void +FromCTime( time_t posixTime, + FILETIME* fileTime ) /* UTC Time */ +{ + LARGE_INTEGER convertedTime; + convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000 + + POSIX_EPOCH_AS_FILETIME; + fileTime->dwLowDateTime = convertedTime.LowPart; + fileTime->dwHighDateTime = convertedTime.HighPart; +} + #if 0 /* *------------------------------------------------------------------------- @@ -2895,7 +2921,8 @@ TclNativeDupInternalRep(clientData) * 0 on success, -1 on error. * * Side effects: - * None. + * Sets errno to a representation of any Windows problem that's + * observed in the process. * *--------------------------------------------------------------------------- */ @@ -2904,24 +2931,29 @@ TclpUtime(pathPtr, tval) Tcl_Obj *pathPtr; /* File to modify */ struct utimbuf *tval; /* New modification date structure */ { - int res; -#ifndef __BORLANDC__ - /* - * Windows uses a slightly different structure name and, possibly, - * contents, so we have to copy the information over - */ - struct _utimbuf buf; -#else - /* - * Borland's compiler does not, but we still copy the content into a - * local variable using the 'generic' name - */ - struct utimbuf buf; -#endif - - buf.actime = tval->actime; - buf.modtime = tval->modtime; - - res = (*tclWinProcs->utimeProc)(Tcl_FSGetNativePath(pathPtr),&buf); + int res = 0; + char* path; + int pathLen; + Tcl_DString buffer; + TCHAR* winPath; + HANDLE fileHandle; + FILETIME lastAccessTime; + FILETIME lastModTime; + FromCTime( tval->actime, &lastAccessTime ); + FromCTime( tval->modtime, &lastModTime ); + path = Tcl_GetStringFromObj( pathPtr, &pathLen ); + winPath = Tcl_WinUtfToTChar( path, pathLen, &buffer ); + fileHandle = (tclWinProcs->createFileProc) + ( winPath, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL ); + if ( fileHandle == INVALID_HANDLE_VALUE + || !SetFileTime( fileHandle, NULL, &lastAccessTime, &lastModTime ) ) { + TclWinConvertError( GetLastError() ); + res = -1; + } + if ( fileHandle != INVALID_HANDLE_VALUE ) { + CloseHandle( fileHandle ); + } + Tcl_DStringFree( &buffer ); return res; } diff --git a/win/tclWinInt.h b/win/tclWinInt.h index 4f0b6be..3efc16b 100644 --- a/win/tclWinInt.h +++ b/win/tclWinInt.h @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinInt.h,v 1.26 2004/05/03 17:04:31 kennykb Exp $ + * RCS: @(#) $Id: tclWinInt.h,v 1.27 2004/11/01 16:58:38 kennykb Exp $ */ #ifndef _TCLWININT @@ -100,7 +100,7 @@ typedef struct TclWinProcs { BOOL (WINAPI *createHardLinkProc)(CONST TCHAR*, CONST TCHAR*, LPSECURITY_ATTRIBUTES); - INT (__cdecl *utimeProc)(CONST TCHAR*, struct _utimbuf *); + /* deleted INT (__cdecl *utimeProc)(CONST TCHAR*, struct _utimbuf *); */ /* These two are also NULL at start; see comment above */ HANDLE (WINAPI *findFirstFileExProc)(CONST TCHAR*, UINT, LPVOID, UINT, -- cgit v0.12