summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog12
-rw-r--r--tests/cmdAH.test14
-rw-r--r--win/tclWin32Dll.c6
-rw-r--r--win/tclWinFile.c78
-rw-r--r--win/tclWinInt.h4
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 <kennykb@acm.org>
+
+ * 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 <donal.k.fellows@man.ac.uk>
* 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,