From 9dc4d62155a906e3cb7a4d11c2332774d2071d83 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" Date: Tue, 27 Mar 2012 11:20:55 +0000 Subject: [Bug 3508771] Wrong Tcl_StatBuf used on MinGW [Bug 2015723] duplicate inodes from file stat on windows --- ChangeLog | 5 +++++ generic/tcl.h | 66 +++++++++++++++++++++++++++---------------------------- generic/tclFCmd.c | 31 ++++++++++++++------------ 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/ChangeLog b/ChangeLog index 78a565e..6f7740b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-03-27 Jan Nijtmans + + * generic/tcl.h: [Bug 3508771] Wrong Tcl_StatBuf used on MinGW + * generic/tclFCmd.c: [Bug 2015723] duplicate inodes from file stat on windows + 2012-03-24 Jan Nijtmans * generic/tclInt.decls: [Bug 3508771] load tclreg.dll in cygwin tclsh diff --git a/generic/tcl.h b/generic/tcl.h index e794032..3c6ef5e 100644 --- a/generic/tcl.h +++ b/generic/tcl.h @@ -376,17 +376,9 @@ typedef long LONG; # if defined(__WIN32__) # define TCL_WIDE_INT_TYPE __int64 # ifdef __BORLANDC__ -typedef struct stati64 Tcl_StatBuf; # define TCL_LL_MODIFIER "L" # define TCL_LL_MODIFIER_SIZE 1 # else /* __BORLANDC__ */ -# if defined(_WIN64) -typedef struct __stat64 Tcl_StatBuf; -# elif (defined(_MSC_VER) && (_MSC_VER < 1400)) || defined(_USE_32BIT_TIME_T) -typedef struct _stati64 Tcl_StatBuf; -# else -typedef struct _stat32i64 Tcl_StatBuf; -# endif /* _MSC_VER < 1400 */ # define TCL_LL_MODIFIER "I64" # define TCL_LL_MODIFIER_SIZE 3 # endif /* __BORLANDC__ */ @@ -394,11 +386,6 @@ typedef struct _stat32i64 Tcl_StatBuf; # define TCL_WIDE_INT_TYPE long long # define TCL_LL_MODIFIER "ll" # define TCL_LL_MODIFIER_SIZE 2 -# if defined(__WIN32__) -typedef struct _stat32i64 Tcl_StatBuf; -# else -typedef struct stat Tcl_StatBuf; -# endif # else /* ! __WIN32__ && ! __GNUC__ */ /* * Don't know what platform it is and configure hasn't discovered what @@ -425,7 +412,6 @@ typedef TCL_WIDE_INT_TYPE Tcl_WideInt; typedef unsigned TCL_WIDE_INT_TYPE Tcl_WideUInt; #ifdef TCL_WIDE_INT_IS_LONG -typedef struct stat Tcl_StatBuf; # define Tcl_WideAsLong(val) ((long)(val)) # define Tcl_LongAsWide(val) ((long)(val)) # define Tcl_WideAsDouble(val) ((double)((long)(val))) @@ -440,25 +426,6 @@ typedef struct stat Tcl_StatBuf; * Windows or some other strange platform. */ # ifndef TCL_LL_MODIFIER -# ifdef __CYGWIN__ -typedef struct _stat32i64 { - dev_t st_dev; - ino_t st_ino; - unsigned short st_mode; - short st_nlink; - short st_uid; - short st_gid; - dev_t st_rdev; - long long st_size; - struct {long tv_sec;} st_atim; - struct {long tv_sec;} st_mtim; - struct {long tv_sec;} st_ctim; -} Tcl_StatBuf; -# elif defined(HAVE_STRUCT_STAT64) -typedef struct stat64 Tcl_StatBuf; -# else -typedef struct stat Tcl_StatBuf; -# endif /* HAVE_STRUCT_STAT64 */ # define TCL_LL_MODIFIER "ll" # define TCL_LL_MODIFIER_SIZE 2 # endif /* !TCL_LL_MODIFIER */ @@ -467,6 +434,39 @@ typedef struct stat Tcl_StatBuf; # define Tcl_WideAsDouble(val) ((double)((Tcl_WideInt)(val))) # define Tcl_DoubleAsWide(val) ((Tcl_WideInt)((double)(val))) #endif /* TCL_WIDE_INT_IS_LONG */ + +#if defined(__WIN32__) +# ifdef __BORLANDC__ + typedef struct stati64 Tcl_StatBuf; +# elif defined(_WIN64) + typedef struct __stat64 Tcl_StatBuf; +# elif (defined(_MSC_VER) && (_MSC_VER < 1400)) || defined(_USE_32BIT_TIME_T) + typedef struct _stati64 Tcl_StatBuf; +# else + typedef struct _stat32i64 Tcl_StatBuf; +# endif /* _MSC_VER < 1400 */ +#elif defined(__CYGWIN__) + typedef struct _stat32i64 { + dev_t st_dev; + unsigned short st_ino; + unsigned short st_mode; + short st_nlink; + short st_uid; + short st_gid; + /* Here is a 2-byte gap */ + dev_t st_rdev; + /* Here is a 4-byte gap */ + long long st_size; + struct {long tv_sec;} st_atim; + struct {long tv_sec;} st_mtim; + struct {long tv_sec;} st_ctim; + /* Here is a 4-byte gap */ + } Tcl_StatBuf; +#elif defined(HAVE_STRUCT_STAT64) + typedef struct stat64 Tcl_StatBuf; +#else + typedef struct stat Tcl_StatBuf; +#endif /* diff --git a/generic/tclFCmd.c b/generic/tclFCmd.c index 6113cf7..3d6a169 100644 --- a/generic/tclFCmd.c +++ b/generic/tclFCmd.c @@ -516,20 +516,23 @@ CopyRenameOneFile(interp, source, target, copyFlag, force) goto done; } - /* - * Prevent copying or renaming a file onto itself. Under Windows, - * stat always returns 0 for st_ino. However, the Windows-specific - * code knows how to deal with copying or renaming a file on top of - * itself. It might be a good idea to write a stat that worked. - */ - - if ((sourceStatBuf.st_ino != 0) && (targetStatBuf.st_ino != 0)) { - if ((sourceStatBuf.st_ino == targetStatBuf.st_ino) && - (sourceStatBuf.st_dev == targetStatBuf.st_dev)) { - result = TCL_OK; - goto done; - } - } + /* + * Prevent copying or renaming a file onto itself. On Windows since + * 8.5 we do get an inode number, however the unsigned short field is + * insufficient to accept the Win32 API file id so it is truncated to + * 16 bits and we get collisions. See bug #2015723. + */ + +#if !defined(WIN32) && !defined(__CYGWIN__) + if ((sourceStatBuf.st_ino != 0) && (targetStatBuf.st_ino != 0)) { + if ((sourceStatBuf.st_ino == targetStatBuf.st_ino) && + (sourceStatBuf.st_dev == targetStatBuf.st_dev)) { + result = TCL_OK; + goto done; + } + } +#endif + /* * Prevent copying/renaming a file onto a directory and -- cgit v0.12