diff options
Diffstat (limited to 'win/tclWinFile.c')
| -rw-r--r-- | win/tclWinFile.c | 1880 | 
1 files changed, 786 insertions, 1094 deletions
| diff --git a/win/tclWinFile.c b/win/tclWinFile.c index 2a8a2a5..5761eeb 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -10,26 +10,21 @@   *   * 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.90 2006/10/13 12:57:21 coldstore Exp $   */ -/* #define _WIN32_WINNT	0x0500 */ -  #include "tclWinInt.h"  #include "tclFileSystem.h"  #include <winioctl.h> -#include <sys/stat.h>  #include <shlobj.h> -#include <lmaccess.h>		/* For TclpGetUserHome(). */ +#include <lm.h>		/* For TclpGetUserHome(). */  /*   * The number of 100-ns intervals between the Windows system epoch (1601-01-01   * on the proleptic Gregorian calendar) and the Posix epoch (1970-01-01).   */ -#define POSIX_EPOCH_AS_FILETIME		((Tcl_WideInt)116444736 \ -                                         * (Tcl_WideInt) 1000000000) +#define POSIX_EPOCH_AS_FILETIME	\ +	((Tcl_WideInt) 116444736 * (Tcl_WideInt) 1000000000)  /*   * Declarations for 'link' related information. This information should come @@ -90,7 +85,7 @@      CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS)  #endif  #ifndef INVALID_FILE_ATTRIBUTES -#define INVALID_FILE_ATTRIBUTES ((DWORD)-1) +#define INVALID_FILE_ATTRIBUTES		((DWORD)-1)  #endif  /* @@ -123,6 +118,7 @@ typedef struct _REPARSE_DATA_BUFFER {  	    WORD SubstituteNameLength;  	    WORD PrintNameOffset;  	    WORD PrintNameLength; +	    ULONG Flags;  	    WCHAR PathBuffer[1];  	} SymbolicLinkReparseBuffer;  	struct { @@ -141,31 +137,9 @@ typedef struct _REPARSE_DATA_BUFFER {  typedef struct {      REPARSE_DATA_BUFFER dummy; -    WCHAR dummyBuf[MAX_PATH*3]; +    WCHAR dummyBuf[MAX_PATH * 3];  } DUMMY_REPARSE_BUFFER; -#if defined(_MSC_VER) && (_MSC_VER <= 1100) -#undef	HAVE_NO_FINDEX_ENUMS -#define HAVE_NO_FINDEX_ENUMS -#elif !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0400) -#undef	HAVE_NO_FINDEX_ENUMS -#define HAVE_NO_FINDEX_ENUMS -#endif - -#ifdef HAVE_NO_FINDEX_ENUMS -/* These two aren't in VC++ 5.2 headers */ -typedef enum _FINDEX_INFO_LEVELS { -    FindExInfoStandard, -    FindExInfoMaxInfoLevel -} FINDEX_INFO_LEVELS; -typedef enum _FINDEX_SEARCH_OPS { -    FindExSearchNameMatch, -    FindExSearchLimitToDirectories, -    FindExSearchLimitToDevices, -    FindExSearchMaxSearchOp -} FINDEX_SEARCH_OPS; -#endif /* HAVE_NO_FINDEX_ENUMS */ -  /*   * Other typedefs required by this code.   */ @@ -173,38 +147,32 @@ typedef enum _FINDEX_SEARCH_OPS {  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); - -typedef NET_API_STATUS NET_API_FUNCTION NETAPIBUFFERFREEPROC(LPVOID Buffer); - -typedef NET_API_STATUS NET_API_FUNCTION NETGETDCNAMEPROC( -	LPWSTR servername, LPWSTR domainname, LPBYTE *bufptr); -  /*   * Declarations for local functions defined in this file:   */ -static int		NativeAccess(CONST TCHAR *path, int mode); -static int		NativeDev(CONST TCHAR *path); -static int		NativeStat(CONST TCHAR *path, Tcl_StatBuf *statPtr, +static int		NativeAccess(const TCHAR *path, int mode); +static int		NativeDev(const TCHAR *path); +static int		NativeStat(const TCHAR *path, Tcl_StatBuf *statPtr,  			    int checkLinks); -static unsigned short	NativeStatMode(DWORD attr, int checkLinks, int isExec); -static int		NativeIsExec(CONST TCHAR *path); -static int		NativeReadReparse(CONST TCHAR *LinkDirectory, -			    REPARSE_DATA_BUFFER* buffer); -static int		NativeWriteReparse(CONST TCHAR *LinkDirectory, -			    REPARSE_DATA_BUFFER* buffer); +static unsigned short	NativeStatMode(DWORD attr, int checkLinks, +			    int isExec); +static int		NativeIsExec(const TCHAR *path); +static int		NativeReadReparse(const TCHAR *LinkDirectory, +			    REPARSE_DATA_BUFFER *buffer, DWORD desiredAccess); +static int		NativeWriteReparse(const TCHAR *LinkDirectory, +			    REPARSE_DATA_BUFFER *buffer);  static int		NativeMatchType(int isDrive, DWORD attr, -			    CONST TCHAR *nativeName, Tcl_GlobTypeData *types); -static int		WinIsDrive(CONST char *name, int nameLen); -static int		WinIsReserved(CONST char *path); -static Tcl_Obj *	WinReadLink(CONST TCHAR *LinkSource); -static Tcl_Obj *	WinReadLinkDirectory(CONST TCHAR *LinkDirectory); -static int		WinLink(CONST TCHAR *LinkSource, -			    CONST TCHAR *LinkTarget, int linkAction); -static int		WinSymLinkDirectory(CONST TCHAR *LinkDirectory, -			    CONST TCHAR *LinkTarget); +			    const TCHAR *nativeName, Tcl_GlobTypeData *types); +static int		WinIsDrive(const char *name, int nameLen); +static int		WinIsReserved(const char *path); +static Tcl_Obj *	WinReadLink(const TCHAR *LinkSource); +static Tcl_Obj *	WinReadLinkDirectory(const TCHAR *LinkDirectory); +static int		WinLink(const TCHAR *LinkSource, +			    const TCHAR *LinkTarget, int linkAction); +static int		WinSymLinkDirectory(const TCHAR *LinkDirectory, +			    const TCHAR *LinkTarget); +MODULE_SCOPE void	tclWinDebugPanic(const char *format, ...);  /*   *-------------------------------------------------------------------- @@ -218,20 +186,20 @@ static int		WinSymLinkDirectory(CONST TCHAR *LinkDirectory,  static int  WinLink( -    CONST TCHAR *linkSourcePath, -    CONST TCHAR *linkTargetPath, +    const TCHAR *linkSourcePath, +    const TCHAR *linkTargetPath,      int linkAction)  { -    WCHAR tempFileName[MAX_PATH]; +    TCHAR tempFileName[MAX_PATH];      TCHAR *tempFilePart; -    int attr; +    DWORD attr;      /*       * Get the full path referenced by the target.       */ -    if (!(*tclWinProcs->getFullPathNameProc)(linkTargetPath, MAX_PATH, -	    tempFileName, &tempFilePart)) { +    if (!GetFullPathName(linkTargetPath, MAX_PATH, tempFileName, +	    &tempFilePart)) {  	/*  	 * Invalid file.  	 */ @@ -244,8 +212,8 @@ WinLink(       * Make sure source file doesn't exist.       */ -    attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath); -    if (attr != 0xffffffff) { +    attr = GetFileAttributes(linkSourcePath); +    if (attr != INVALID_FILE_ATTRIBUTES) {  	Tcl_SetErrno(EEXIST);  	return -1;      } @@ -254,8 +222,8 @@ WinLink(       * Get the full path referenced by the source file/directory.       */ -    if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH, -	    tempFileName, &tempFilePart)) { +    if (!GetFullPathName(linkSourcePath, MAX_PATH, tempFileName, +	    &tempFilePart)) {  	/*  	 * Invalid file.  	 */ @@ -268,45 +236,43 @@ WinLink(       * Check the target.       */ -    attr = (*tclWinProcs->getFileAttributesProc)(linkTargetPath); -    if (attr == 0xffffffff) { +    attr = GetFileAttributes(linkTargetPath); +    if (attr == INVALID_FILE_ATTRIBUTES) {  	/*  	 * The target doesn't exist.  	 */  	TclWinConvertError(GetLastError()); -	return -1; -      } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {  	/*  	 * It is a file.  	 */ -	if (tclWinProcs->createHardLinkProc == NULL) { -	    Tcl_SetErrno(ENOTDIR); -	    return -1; -	} -  	if (linkAction & TCL_CREATE_HARD_LINK) { -	    if (!(*tclWinProcs->createHardLinkProc)(linkSourcePath, -		    linkTargetPath, NULL)) { -		TclWinConvertError(GetLastError()); -		return -1; +	    if (CreateHardLink(linkSourcePath, linkTargetPath, NULL)) { +		/* +		 * Success! +		 */ + +		return 0;  	    } -	    return 0; +	    TclWinConvertError(GetLastError());  	} else if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {  	    /*  	     * Can't symlink files.  	     */  	    Tcl_SetErrno(ENOTDIR); -	    return -1;  	} else {  	    Tcl_SetErrno(ENODEV); -	    return -1;  	}      } else { +	/* +	 * We've got a directory. Now check whether what we're trying to do is +	 * reasonable. +	 */ +  	if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {  	    return WinSymLinkDirectory(linkSourcePath, linkTargetPath); @@ -316,12 +282,11 @@ WinLink(  	     */  	    Tcl_SetErrno(EISDIR); -	    return -1;  	} else {  	    Tcl_SetErrno(ENODEV); -	    return -1;  	}      } +    return -1;  }  /* @@ -334,20 +299,20 @@ WinLink(   *--------------------------------------------------------------------   */ -static Tcl_Obj* +static Tcl_Obj *  WinReadLink( -    CONST TCHAR *linkSourcePath) +    const TCHAR *linkSourcePath)  { -    WCHAR tempFileName[MAX_PATH]; +    TCHAR tempFileName[MAX_PATH];      TCHAR *tempFilePart; -    int attr; +    DWORD attr;      /*       * Get the full path referenced by the target.       */ -    if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH, -	    tempFileName, &tempFilePart)) { +    if (!GetFullPathName(linkSourcePath, MAX_PATH, tempFileName, +	    &tempFilePart)) {  	/*  	 * Invalid file.  	 */ @@ -360,8 +325,8 @@ WinReadLink(       * Make sure source file does exist.       */ -    attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath); -    if (attr == 0xffffffff) { +    attr = GetFileAttributes(linkSourcePath); +    if (attr == INVALID_FILE_ATTRIBUTES) {  	/*  	 * The source doesn't exist.  	 */ @@ -376,9 +341,9 @@ WinReadLink(  	Tcl_SetErrno(ENOTDIR);  	return NULL; -    } else { -	return WinReadLinkDirectory(linkSourcePath);      } + +    return WinReadLinkDirectory(linkSourcePath);  }  /* @@ -400,11 +365,11 @@ WinReadLink(  static int  WinSymLinkDirectory( -    CONST TCHAR *linkDirPath, -    CONST TCHAR *linkTargetPath) +    const TCHAR *linkDirPath, +    const TCHAR *linkTargetPath)  {      DUMMY_REPARSE_BUFFER dummy; -    REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; +    REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;      int len;      WCHAR nativeTarget[MAX_PATH];      WCHAR *loop; @@ -413,8 +378,8 @@ WinSymLinkDirectory(       * Make the native target name.       */ -    memcpy((void *) nativeTarget, (void *) L"\\??\\", 4*sizeof(WCHAR)); -    memcpy((void *) (nativeTarget + 4), (void *) linkTargetPath, +    memcpy(nativeTarget, L"\\??\\", 4 * sizeof(WCHAR)); +    memcpy(nativeTarget + 4, linkTargetPath,  	   sizeof(WCHAR) * (1+wcslen((WCHAR *) linkTargetPath)));      len = wcslen(nativeTarget); @@ -439,18 +404,18 @@ WinSymLinkDirectory(      memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER));      reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; -    reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = +    reparseBuffer->MountPointReparseBuffer.SubstituteNameLength =  	    wcslen(nativeTarget) * sizeof(WCHAR);      reparseBuffer->Reserved = 0; -    reparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = 0; -    reparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = -	    reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength +    reparseBuffer->MountPointReparseBuffer.PrintNameLength = 0; +    reparseBuffer->MountPointReparseBuffer.PrintNameOffset = +	    reparseBuffer->MountPointReparseBuffer.SubstituteNameLength  	    + sizeof(WCHAR); -    memcpy(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, nativeTarget, +    memcpy(reparseBuffer->MountPointReparseBuffer.PathBuffer, nativeTarget,  	    sizeof(WCHAR) -	    + reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength); +	    + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength);      reparseBuffer->ReparseDataLength = -	    reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + 12; +	    reparseBuffer->MountPointReparseBuffer.SubstituteNameLength+12;      return NativeWriteReparse(linkDirPath, reparseBuffer);  } @@ -472,13 +437,13 @@ WinSymLinkDirectory(  int  TclWinSymLinkCopyDirectory( -    CONST TCHAR *linkOrigPath,	/* Existing junction - reparse point */ -    CONST TCHAR *linkCopyPath)	/* Will become a duplicate junction */ +    const TCHAR *linkOrigPath,	/* Existing junction - reparse point */ +    const TCHAR *linkCopyPath)	/* Will become a duplicate junction */  {      DUMMY_REPARSE_BUFFER dummy;      REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy; -    if (NativeReadReparse(linkOrigPath, reparseBuffer)) { +    if (NativeReadReparse(linkOrigPath, reparseBuffer, GENERIC_READ)) {  	return -1;      }      return NativeWriteReparse(linkCopyPath, reparseBuffer); @@ -503,7 +468,7 @@ TclWinSymLinkCopyDirectory(  int  TclWinSymLinkDelete( -    CONST TCHAR *linkOrigPath, +    const TCHAR *linkOrigPath,      int linkOnly)  {      /* @@ -517,9 +482,8 @@ TclWinSymLinkDelete(      memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER));      reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; -    hFile = (*tclWinProcs->createFileProc)(linkOrigPath, GENERIC_WRITE, 0, -	    NULL, OPEN_EXISTING, -	    FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); +    hFile = CreateFile(linkOrigPath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, +	    FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);      if (hFile != INVALID_HANDLE_VALUE) {  	if (!DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, reparseBuffer, @@ -533,7 +497,7 @@ TclWinSymLinkDelete(  	} else {  	    CloseHandle(hFile);  	    if (!linkOnly) { -		(*tclWinProcs->removeDirectoryProc)(linkOrigPath); +		RemoveDirectory(linkOrigPath);  	    }  	    return 0;  	} @@ -562,23 +526,22 @@ TclWinSymLinkDelete(   *--------------------------------------------------------------------   */ -static Tcl_Obj* +static Tcl_Obj *  WinReadLinkDirectory( -    CONST TCHAR *linkDirPath) +    const TCHAR *linkDirPath)  { -    int attr; +    int attr, len, offset;      DUMMY_REPARSE_BUFFER dummy; -    REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; +    REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;      Tcl_Obj *retVal;      Tcl_DString ds; -    CONST char *copy; -    int len, offset; +    const char *copy; -    attr = (*tclWinProcs->getFileAttributesProc)(linkDirPath); +    attr = GetFileAttributes(linkDirPath);      if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {  	goto invalidError;      } -    if (NativeReadReparse(linkDirPath, reparseBuffer)) { +    if (NativeReadReparse(linkDirPath, reparseBuffer, 0)) {  	return NULL;      } @@ -599,12 +562,13 @@ WinReadLinkDirectory(  	 */  	offset = 0; -	if (reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer[0] == L'\\') { +#ifdef UNICODE +	if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') {  	    /*  	     * Check whether this is a mounted volume.  	     */ -	    if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, +	    if (wcsncmp(reparseBuffer->MountPointReparseBuffer.PathBuffer,  		    L"\\??\\Volume{",11) == 0) {  		char drive; @@ -613,7 +577,7 @@ WinReadLinkDirectory(  		 * to fix here. It doesn't seem very well documented.  		 */ -		reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer[1] = L'\\'; +		reparseBuffer->MountPointReparseBuffer.PathBuffer[1]=L'\\';  		/*  		 * Check if a corresponding drive letter exists, and use that @@ -621,7 +585,7 @@ WinReadLinkDirectory(  		 */  		drive = TclWinDriveLetterForVolMountPoint( -			reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer); +			reparseBuffer->MountPointReparseBuffer.PathBuffer);  		if (drive != -1) {  		    char driveSpec[3] = {  			'\0', ':', '\0' @@ -644,14 +608,14 @@ WinReadLinkDirectory(  		 */  		goto invalidError; -	    } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer +	    } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer  		    .PathBuffer, L"\\\\?\\",4) == 0) {  		/*  		 * Strip off the prefix.  		 */  		offset = 4; -	    } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer +	    } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer  		    .PathBuffer, L"\\??\\",4) == 0) {  		/*  		 * Strip off the prefix. @@ -660,10 +624,11 @@ WinReadLinkDirectory(  		offset = 4;  	    }  	} +#endif /* UNICODE */ -	Tcl_WinTCharToUtf((CONST char*) -		reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, -		(int) reparseBuffer->SymbolicLinkReparseBuffer +	Tcl_WinTCharToUtf((const TCHAR *) +		reparseBuffer->MountPointReparseBuffer.PathBuffer, +		(int) reparseBuffer->MountPointReparseBuffer  		.SubstituteNameLength, &ds);  	copy = Tcl_DStringValue(&ds)+offset; @@ -696,15 +661,15 @@ WinReadLinkDirectory(  static int  NativeReadReparse( -    CONST TCHAR *linkDirPath,	/* The junction to read */ -    REPARSE_DATA_BUFFER *buffer)/* Pointer to buffer. Cannot be NULL */ +    const TCHAR *linkDirPath,	/* The junction to read */ +    REPARSE_DATA_BUFFER *buffer,/* Pointer to buffer. Cannot be NULL */ +    DWORD desiredAccess)  {      HANDLE hFile;      DWORD returnedLength; -    hFile = (*tclWinProcs->createFileProc)(linkDirPath, GENERIC_READ, 0, -	    NULL, OPEN_EXISTING, -	    FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); +    hFile = CreateFile(linkDirPath, desiredAccess, 0, NULL, OPEN_EXISTING, +	    FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);      if (hFile == INVALID_HANDLE_VALUE) {  	/* @@ -752,8 +717,8 @@ NativeReadReparse(  static int  NativeWriteReparse( -    CONST TCHAR *linkDirPath, -    REPARSE_DATA_BUFFER* buffer) +    const TCHAR *linkDirPath, +    REPARSE_DATA_BUFFER *buffer)  {      HANDLE hFile;      DWORD returnedLength; @@ -762,7 +727,7 @@ NativeWriteReparse(       * Create the directory - it must not already exist.       */ -    if ((*tclWinProcs->createDirectoryProc)(linkDirPath, NULL) == 0) { +    if (CreateDirectory(linkDirPath, NULL) == 0) {  	/*  	 * Error creating directory.  	 */ @@ -770,10 +735,9 @@ NativeWriteReparse(  	TclWinConvertError(GetLastError());  	return -1;      } - -    hFile = (*tclWinProcs->createFileProc)(linkDirPath, GENERIC_WRITE, 0, -	    NULL, OPEN_EXISTING, -	    FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); +    hFile = CreateFile(linkDirPath, GENERIC_WRITE, 0, NULL, +	    OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT +	    | FILE_FLAG_BACKUP_SEMANTICS, NULL);      if (hFile == INVALID_HANDLE_VALUE) {  	/*  	 * Error creating directory. @@ -796,7 +760,7 @@ NativeWriteReparse(  	TclWinConvertError(GetLastError());  	CloseHandle(hFile); -	(*tclWinProcs->removeDirectoryProc)(linkDirPath); +	RemoveDirectory(linkDirPath);  	return -1;      }      CloseHandle(hFile); @@ -809,6 +773,65 @@ NativeWriteReparse(  }  /* + *---------------------------------------------------------------------- + * + * tclWinDebugPanic -- + * + *	Display a message. If a debugger is present, present it directly to + *	the debugger, otherwise use a MessageBox. + * + * Results: + *	None. + * + * Side effects: + *	None. + * + *---------------------------------------------------------------------- + */ + +void +tclWinDebugPanic( +    const char *format, ...) +{ +#define TCL_MAX_WARN_LEN 1024 +    va_list argList; +    char buf[TCL_MAX_WARN_LEN * TCL_UTF_MAX]; +    WCHAR msgString[TCL_MAX_WARN_LEN]; + +    va_start(argList, format); +    vsnprintf(buf, sizeof(buf), format, argList); + +    msgString[TCL_MAX_WARN_LEN-1] = L'\0'; +    MultiByteToWideChar(CP_UTF8, 0, buf, -1, msgString, TCL_MAX_WARN_LEN); + +    /* +     * Truncate MessageBox string if it is too long to not overflow the screen +     * and cause possible oversized window error. +     */ + +    if (msgString[TCL_MAX_WARN_LEN-1] != L'\0') { +	memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR)); +    } +    if (IsDebuggerPresent()) { +	OutputDebugStringW(msgString); +    } else { +	MessageBeep(MB_ICONEXCLAMATION); +	MessageBoxW(NULL, msgString, L"Fatal Error", +		MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND); +    } +#if defined(__GNUC__) +    __builtin_trap(); +#elif defined(_WIN64) +    __debugbreak(); +#elif defined(_MSC_VER) +    _asm {int 3} +#else +    DebugBreak(); +#endif +    abort(); +} + +/*   *---------------------------------------------------------------------------   *   * TclpFindExecutable -- @@ -827,27 +850,32 @@ NativeWriteReparse(  void  TclpFindExecutable( -    CONST char *argv0)		/* The value of the application's argv[0] -				 * (native). */ +    const char *argv0)		/* If NULL, install PanicMessageBox, otherwise +				 * ignore. */  {      WCHAR wName[MAX_PATH];      char name[MAX_PATH * TCL_UTF_MAX];      /*       * Under Windows we ignore argv0, and return the path for the file used to -     * create this process. +     * create this process. Only if it is NULL, install a new panic handler.       */ -    if (GetModuleFileNameW(NULL, wName, MAX_PATH) == 0) { -	GetModuleFileNameA(NULL, name, sizeof(name)); +    if (argv0 == NULL) { +	Tcl_SetPanicProc(tclWinDebugPanic); +    } -	/* -	 * Convert to WCHAR to get out of ANSI codepage -	 */ +#ifdef UNICODE +    GetModuleFileNameW(NULL, wName, MAX_PATH); +#else +    GetModuleFileNameA(NULL, name, sizeof(name)); -	MultiByteToWideChar(CP_ACP, 0, name, -1, wName, MAX_PATH); -    } +    /* +     * Convert to WCHAR to get out of ANSI codepage +     */ +    MultiByteToWideChar(CP_ACP, 0, name, -1, wName, MAX_PATH); +#endif      WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL);      TclWinNoBackslash(name);      TclSetObjNameOfExecutable(Tcl_NewStringObj(name, -1), NULL); @@ -877,12 +905,12 @@ TclpMatchInDirectory(      Tcl_Interp *interp,		/* Interpreter to receive errors. */      Tcl_Obj *resultPtr,		/* List object to lappend results. */      Tcl_Obj *pathPtr,		/* Contains path to directory to search. */ -    CONST char *pattern,	/* Pattern to match against. */ +    const char *pattern,	/* Pattern to match against. */      Tcl_GlobTypeData *types)	/* Object containing list of acceptable types.  				 * May be NULL. In particular the directory  				 * flag is very important. */  { -    CONST TCHAR *native; +    const TCHAR *native;      if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {  	/* @@ -894,6 +922,7 @@ TclpMatchInDirectory(      if (pattern == NULL || (*pattern == '\0')) {  	Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr); +  	if (norm != NULL) {  	    /*  	     * Match a single file directly. @@ -901,23 +930,16 @@ TclpMatchInDirectory(  	    int len;  	    DWORD attr; -	    CONST char *str = Tcl_GetStringFromObj(norm,&len); +	    WIN32_FILE_ATTRIBUTE_DATA data; +	    const char *str = Tcl_GetStringFromObj(norm,&len); -	    native = (CONST TCHAR *) Tcl_FSGetNativePath(pathPtr); +	    native = Tcl_FSGetNativePath(pathPtr); -	    if (tclWinProcs->getFileAttributesExProc == NULL) { -		attr = (*tclWinProcs->getFileAttributesProc)(native); -		if (attr == 0xffffffff) { -		    return TCL_OK; -		} -	    } else { -		WIN32_FILE_ATTRIBUTE_DATA data; -		if ((*tclWinProcs->getFileAttributesExProc)(native, -			GetFileExInfoStandard, &data) != TRUE) { -		    return TCL_OK; -		} -		attr = data.dwFileAttributes; +	    if (GetFileAttributesEx(native, +		    GetFileExInfoStandard, &data) != TRUE) { +		return TCL_OK;  	    } +	    attr = data.dwFileAttributes;  	    if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) {  		Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); @@ -927,8 +949,8 @@ TclpMatchInDirectory(      } else {  	DWORD attr;  	HANDLE handle; -	WIN32_FIND_DATAT data; -	CONST char *dirName;	/* UTF-8 dir name, later with pattern +	WIN32_FIND_DATA data; +	const char *dirName;	/* UTF-8 dir name, later with pattern  				 * appended. */  	int dirLength;  	int matchSpecialDots; @@ -956,9 +978,10 @@ TclpMatchInDirectory(  	if (native == NULL) {  	    return TCL_OK;  	} -	attr = (*tclWinProcs->getFileAttributesProc)(native); +	attr = GetFileAttributes(native); -	if ((attr == 0xffffffff) || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) { +	if ((attr == INVALID_FILE_ATTRIBUTES) +	    || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {  	    return TCL_OK;  	} @@ -973,7 +996,7 @@ TclpMatchInDirectory(  	lastChar = dirName[dirLength -1];  	if ((lastChar != '\\') && (lastChar != '/') && (lastChar != ':')) { -	    Tcl_DStringAppend(&dsOrig, "/", 1); +	    TclDStringAppendLiteral(&dsOrig, "/");  	    dirLength++;  	}  	dirName = Tcl_DStringValue(&dsOrig); @@ -993,25 +1016,25 @@ TclpMatchInDirectory(  	    dirName = Tcl_DStringAppend(&dsOrig, pattern, -1);  	} else { -	    dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3); +	    dirName = TclDStringAppendLiteral(&dsOrig, "*.*");  	}  	native = Tcl_WinUtfToTChar(dirName, -1, &ds); -	if (tclWinProcs->findFirstFileExProc == NULL || (types == NULL) -		|| (types->type != TCL_GLOB_TYPE_DIR)) { -	    handle = (*tclWinProcs->findFirstFileProc)(native, &data); +	if ((types == NULL) || (types->type != TCL_GLOB_TYPE_DIR)) { +	    handle = FindFirstFile(native, &data);  	} else {  	    /*  	     * We can be more efficient, for pure directory requests.  	     */ -	    handle = (*tclWinProcs->findFirstFileExProc)(native, +	    handle = FindFirstFileEx(native,  		    FindExInfoStandard, &data,  		    FindExSearchLimitToDirectories, NULL, 0);  	}  	if (handle == INVALID_HANDLE_VALUE) {  	    DWORD err = GetLastError(); +  	    Tcl_DStringFree(&ds);  	    if (err == ERROR_FILE_NOT_FOUND) {  		/* @@ -1025,10 +1048,9 @@ TclpMatchInDirectory(  	    TclWinConvertError(err);  	    if (interp != NULL) { -		Tcl_ResetResult(interp); -		Tcl_AppendResult(interp, "couldn't read directory \"", -			Tcl_DStringValue(&dsOrig), "\": ", -			Tcl_PosixError(interp), NULL); +		Tcl_SetObjResult(interp, Tcl_ObjPrintf( +			"couldn't read directory \"%s\": %s", +			Tcl_DStringValue(&dsOrig), Tcl_PosixError(interp)));  	    }  	    Tcl_DStringFree(&dsOrig);  	    return TCL_ERROR; @@ -1064,19 +1086,12 @@ TclpMatchInDirectory(  	 */  	do { -	    CONST char *utfname; -	    int checkDrive = 0; -	    int isDrive; +	    const char *utfname; +	    int checkDrive = 0, isDrive;  	    DWORD attr; -	    if (tclWinProcs->useWide) { -		native = (CONST TCHAR *) data.w.cFileName; -		attr = data.w.dwFileAttributes; -	    } else { -		native = (CONST TCHAR *) data.a.cFileName; -		attr = data.a.dwFileAttributes; -	    } - +	    native = data.cFileName; +	    attr = data.dwFileAttributes;  	    utfname = Tcl_WinTCharToUtf(native, -1, &ds);  	    if (!matchSpecialDots) { @@ -1117,8 +1132,9 @@ TclpMatchInDirectory(  		 */  		if (checkDrive) { -		    CONST char *fullname = Tcl_DStringAppend(&dsOrig, utfname, +		    const char *fullname = Tcl_DStringAppend(&dsOrig, utfname,  			    Tcl_DStringLength(&ds)); +  		    isDrive = WinIsDrive(fullname, Tcl_DStringLength(&dsOrig));  		    Tcl_DStringSetLength(&dsOrig, dirLength);  		} else { @@ -1136,7 +1152,7 @@ TclpMatchInDirectory(  	     */  	    Tcl_DStringFree(&ds); -	} while ((*tclWinProcs->findNextFileProc)(handle, &data) == TRUE); +	} while (FindNextFile(handle, &data) == TRUE);  	FindClose(handle);  	Tcl_DStringFree(&dsOrig); @@ -1152,10 +1168,11 @@ TclpMatchInDirectory(  static int  WinIsDrive( -    CONST char *name,		/* Name (UTF-8) */ +    const char *name,		/* Name (UTF-8) */      int len)			/* Length of name */  {      int remove = 0; +      while (len > 4) {  	if ((name[len-1] != '.' || name[len-2] != '.')  		|| (name[len-3] != '/' && name[len-3] != '\\')) { @@ -1217,8 +1234,9 @@ WinIsDrive(   * (not any trailing :).   */ -static int WinIsReserved( -   CONST char *path)		/* Path in UTF-8 */ +static int +WinIsReserved( +    const char *path)		/* Path in UTF-8 */  {      if ((path[0] == 'c' || path[0] == 'C')  	    && (path[1] == 'o' || path[1] == 'O')) { @@ -1256,8 +1274,8 @@ static int WinIsReserved(  	    }  	} -    } else if (!stricmp(path, "prn") || !stricmp(path, "nul") -	    || !stricmp(path, "aux")) { +    } else if (!strcasecmp(path, "prn") || !strcasecmp(path, "nul") +	    || !strcasecmp(path, "aux")) {  	/*  	 * Have match for 'prn', 'nul' or 'aux'.  	 */ @@ -1276,7 +1294,7 @@ static int WinIsReserved(   *	because for NTFS root volumes, the getFileAttributesProc returns a   *	'hidden' attribute when it should not.   * - *	We never make any calss to a 'get attributes' routine here, since we + *	We never make any calls to a 'get attributes' routine here, since we   *	have arranged things so that our caller already knows such   *	information.   * @@ -1292,7 +1310,7 @@ NativeMatchType(      int isDrive,		/* Is this a drive. */      DWORD attr,			/* We already know the attributes for the  				 * file. */ -    CONST TCHAR *nativeName,	/* Native path to check. */ +    const TCHAR *nativeName,	/* Native path to check. */      Tcl_GlobTypeData *types)	/* Type description to match against. */  {      /* @@ -1307,81 +1325,80 @@ NativeMatchType(  	 * If invisible, don't return the file.  	 */ -	if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) { +	return !(attr & FILE_ATTRIBUTE_HIDDEN && !isDrive); +    } + +    if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) { +	/* +	 * If invisible. +	 */ + +	if ((types->perm == 0) || !(types->perm & TCL_GLOB_PERM_HIDDEN)) {  	    return 0;  	}      } else { -	if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) { -	    /* -	     * If invisible. -	     */ - -	    if ((types->perm == 0) || !(types->perm & TCL_GLOB_PERM_HIDDEN)) { -		return 0; -	    } -	} else { -	    /* -	     * Visible. -	     */ +	/* +	 * Visible. +	 */ -	    if (types->perm & TCL_GLOB_PERM_HIDDEN) { -		return 0; -	    } +	if (types->perm & TCL_GLOB_PERM_HIDDEN) { +	    return 0;  	} +    } -	if (types->perm != 0) { -	    if (((types->perm & TCL_GLOB_PERM_RONLY) && -			!(attr & FILE_ATTRIBUTE_READONLY)) || -		    ((types->perm & TCL_GLOB_PERM_R) && -			(0 /* File exists => R_OK on Windows */)) || -		    ((types->perm & TCL_GLOB_PERM_W) && -			(attr & FILE_ATTRIBUTE_READONLY)) || -		    ((types->perm & TCL_GLOB_PERM_X) && -			(!(attr & FILE_ATTRIBUTE_DIRECTORY) -			 && !NativeIsExec(nativeName)))) { -		return 0; -	    } +    if (types->perm != 0) { +	if (((types->perm & TCL_GLOB_PERM_RONLY) && +		    !(attr & FILE_ATTRIBUTE_READONLY)) || +		((types->perm & TCL_GLOB_PERM_R) && +		    (0 /* File exists => R_OK on Windows */)) || +		((types->perm & TCL_GLOB_PERM_W) && +		    (attr & FILE_ATTRIBUTE_READONLY)) || +		((types->perm & TCL_GLOB_PERM_X) && +		    (!(attr & FILE_ATTRIBUTE_DIRECTORY) +		    && !NativeIsExec(nativeName)))) { +	    return 0;  	} -	if ((types->type & TCL_GLOB_TYPE_DIR) -		&& (attr & FILE_ATTRIBUTE_DIRECTORY)) { -	    /* -	     * Quicker test for directory, which is a common case. -	     */ +    } -	    return 1; +    if ((types->type & TCL_GLOB_TYPE_DIR) +	    && (attr & FILE_ATTRIBUTE_DIRECTORY)) { +	/* +	 * Quicker test for directory, which is a common case. +	 */ -	} else if (types->type != 0) { -	    unsigned short st_mode; -	    int isExec = NativeIsExec(nativeName); +	return 1; -	    st_mode = NativeStatMode(attr, 0, isExec); +    } else if (types->type != 0) { +	unsigned short st_mode; +	int isExec = NativeIsExec(nativeName); -	    /* -	     * In order bcdpfls as in 'find -t' -	     */ +	st_mode = NativeStatMode(attr, 0, isExec); -	    if (((types->type&TCL_GLOB_TYPE_BLOCK)    && S_ISBLK(st_mode)) || -		    ((types->type&TCL_GLOB_TYPE_CHAR) && S_ISCHR(st_mode)) || -		    ((types->type&TCL_GLOB_TYPE_DIR)  && S_ISDIR(st_mode)) || -		    ((types->type&TCL_GLOB_TYPE_PIPE) && S_ISFIFO(st_mode)) || +	/* +	 * In order bcdpfls as in 'find -t' +	 */ + +	if (((types->type&TCL_GLOB_TYPE_BLOCK)    && S_ISBLK(st_mode)) || +		((types->type&TCL_GLOB_TYPE_CHAR) && S_ISCHR(st_mode)) || +		((types->type&TCL_GLOB_TYPE_DIR)  && S_ISDIR(st_mode)) || +		((types->type&TCL_GLOB_TYPE_PIPE) && S_ISFIFO(st_mode)) ||  #ifdef S_ISSOCK -		    ((types->type&TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) || +		((types->type&TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) ||  #endif -		    ((types->type&TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode))) { -		/* -		 * Do nothing - this file is ok. -		 */ -	    } else { +		((types->type&TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode))) { +	    /* +	     * Do nothing - this file is ok. +	     */ +	} else {  #ifdef S_ISLNK -		if (types->type & TCL_GLOB_TYPE_LINK) { -		    st_mode = NativeStatMode(attr, 1, isExec); -		    if (S_ISLNK(st_mode)) { -			return 1; -		    } +	    if (types->type & TCL_GLOB_TYPE_LINK) { +		st_mode = NativeStatMode(attr, 1, isExec); +		if (S_ISLNK(st_mode)) { +		    return 1;  		} -#endif -		return 0;  	    } +#endif /* S_ISLNK */ +	    return 0;  	}      }      return 1; @@ -1408,81 +1425,56 @@ NativeMatchType(   *----------------------------------------------------------------------   */ -char * +const char *  TclpGetUserHome( -    CONST char *name,		/* User name for desired home directory. */ +    const char *name,		/* User name for desired home directory. */      Tcl_DString *bufferPtr)	/* Uninitialized or free DString filled with  				 * name of user's home directory. */  { -    char *result; -    HINSTANCE netapiInst; - -    result = NULL; +    const char *result = NULL; +    USER_INFO_1 *uiPtr, **uiPtrPtr = &uiPtr; +    Tcl_DString ds; +    int nameLen = -1; +    int badDomain = 0; +    char *domain; +    WCHAR *wName, *wHomeDir, *wDomain, **wDomainPtr = &wDomain; +    WCHAR buf[MAX_PATH];      Tcl_DStringInit(bufferPtr); +    wDomain = NULL; +    domain = strchr(name, '@'); +    if (domain != NULL) { +	Tcl_DStringInit(&ds); +	wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds); +	badDomain = NetGetDCName(NULL, wName, (LPBYTE *) wDomainPtr); +	Tcl_DStringFree(&ds); +	nameLen = domain - name; +    } +    if (badDomain == 0) { +	Tcl_DStringInit(&ds); +	wName = Tcl_UtfToUniCharDString(name, nameLen, &ds); +	if (NetUserGetInfo(wDomain, wName, 1, (LPBYTE *) uiPtrPtr) == 0) { +	    wHomeDir = uiPtr->usri1_home_dir; +	    if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) { +		Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir), +			bufferPtr); +	    } else { +		/* +		 * User exists but has no home dir. Return +		 * "{Windows Drive}:/users/default". +		 */ -    netapiInst = LoadLibraryA("netapi32.dll"); -    if (netapiInst != NULL) { -	NETAPIBUFFERFREEPROC *netApiBufferFreeProc; -	NETGETDCNAMEPROC *netGetDCNameProc; -	NETUSERGETINFOPROC *netUserGetInfoProc; - -	netApiBufferFreeProc = (NETAPIBUFFERFREEPROC *) -		GetProcAddress(netapiInst, "NetApiBufferFree"); -	netGetDCNameProc = (NETGETDCNAMEPROC *) -		GetProcAddress(netapiInst, "NetGetDCName"); -	netUserGetInfoProc = (NETUSERGETINFOPROC *) -		GetProcAddress(netapiInst, "NetUserGetInfo"); -	if ((netUserGetInfoProc != NULL) && (netGetDCNameProc != NULL) -		&& (netApiBufferFreeProc != NULL)) { -	    USER_INFO_1 *uiPtr; -	    Tcl_DString ds; -	    int nameLen, badDomain; -	    char *domain; -	    WCHAR *wName, *wHomeDir, *wDomain; -	    WCHAR buf[MAX_PATH]; - -	    badDomain = 0; -	    nameLen = -1; -	    wDomain = NULL; -	    domain = strchr(name, '@'); -	    if (domain != NULL) { -		Tcl_DStringInit(&ds); -		wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds); -		badDomain = (netGetDCNameProc)(NULL, wName, -			(LPBYTE *) &wDomain); -		Tcl_DStringFree(&ds); -		nameLen = domain - name; -	    } -	    if (badDomain == 0) { -		Tcl_DStringInit(&ds); -		wName = Tcl_UtfToUniCharDString(name, nameLen, &ds); -		if ((netUserGetInfoProc)(wDomain, wName, 1, -			(LPBYTE *) &uiPtr) == 0) { -		    wHomeDir = uiPtr->usri1_home_dir; -		    if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) { -			Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir), -				bufferPtr); -		    } else { -			/* -			 * User exists but has no home dir. Return -			 * "{Windows Drive}:/users/default". -			 */ - -			GetWindowsDirectoryW(buf, MAX_PATH); -			Tcl_UniCharToUtfDString(buf, 2, bufferPtr); -			Tcl_DStringAppend(bufferPtr, "/users/default", -1); -		    } -		    result = Tcl_DStringValue(bufferPtr); -		    (*netApiBufferFreeProc)((void *) uiPtr); -		} -		Tcl_DStringFree(&ds); -	    } -	    if (wDomain != NULL) { -		(*netApiBufferFreeProc)((void *) wDomain); +		GetWindowsDirectoryW(buf, MAX_PATH); +		Tcl_UniCharToUtfDString(buf, 2, bufferPtr); +		TclDStringAppendLiteral(bufferPtr, "/users/default");  	    } +	    result = Tcl_DStringValue(bufferPtr); +	    NetApiBufferFree((void *) uiPtr);  	} -	FreeLibrary(netapiInst); +	Tcl_DStringFree(&ds); +    } +    if (wDomain != NULL) { +	NetApiBufferFree((void *) wDomain);      }      if (result == NULL) {  	/* @@ -1533,30 +1525,44 @@ TclpGetUserHome(  static int  NativeAccess( -    CONST TCHAR *nativePath,	/* Path of file to access, native encoding. */ +    const TCHAR *nativePath,	/* Path of file to access, native encoding. */      int mode)			/* Permission setting. */  {      DWORD attr; -    attr = (*tclWinProcs->getFileAttributesProc)(nativePath); +    attr = GetFileAttributes(nativePath); -    if (attr == 0xffffffff) { +    if (attr == INVALID_FILE_ATTRIBUTES) {  	/* -	 * File doesn't exist. +	 * File might not exist.  	 */ -	TclWinConvertError(GetLastError()); -	return -1; +	DWORD lasterror = GetLastError(); +	if (lasterror != ERROR_SHARING_VIOLATION) { +	    TclWinConvertError(lasterror); +	    return -1; +	} +    } + +    if (mode == F_OK) { +	/* +	 * File exists, nothing else to check. +	 */ + +	return 0;      } -    if ((mode & W_OK)  -      && (tclWinProcs->getFileSecurityProc == NULL) -      && (attr & FILE_ATTRIBUTE_READONLY)) { +    if ((mode & W_OK) +	&& (attr & FILE_ATTRIBUTE_READONLY) +	&& !(attr & FILE_ATTRIBUTE_DIRECTORY)) {  	/* -	 * We don't have the advanced 'getFileSecurityProc', and -	 * our attributes say the file is not writable.  If we -	 * do have 'getFileSecurityProc', we'll do a more -	 * robust XP-related check below. +	 * The attributes say the file is not writable.	 If the file is a +	 * regular file (i.e., not a directory), then the file is not +	 * writable, full stop.	 For directories, the read-only bit is +	 * (mostly) ignored by Windows, so we can't ascertain anything about +	 * directory access from the attrib data.  However, if we have the +	 * advanced 'getFileSecurityProc', then more robust ACL checks +	 * will be done below.  	 */  	Tcl_SetErrno(EACCES); @@ -1580,32 +1586,32 @@ NativeAccess(       * we have a more complex permissions structure so we try to check that.       * The code below is remarkably complex for such a simple thing as finding       * what permissions the OS has set for a file. -     * -     * If we are simply checking for file existence, then we don't need all -     * these complications (which are really quite slow: with this code 'file -     * readable' is 5-6 times slower than 'file exists').       */ -    if ((mode != F_OK) && (tclWinProcs->getFileSecurityProc != NULL)) { +#ifdef UNICODE +    {  	SECURITY_DESCRIPTOR *sdPtr = NULL;  	unsigned long size; +	PSID pSid = 0; +	BOOL SidDefaulted; +	SID_IDENTIFIER_AUTHORITY samba_unmapped = {{0, 0, 0, 0, 0, 22}};  	GENERIC_MAPPING genMap;  	HANDLE hToken = NULL; -	DWORD desiredAccess = 0; -	DWORD grantedAccess = 0; +	DWORD desiredAccess = 0, grantedAccess = 0;  	BOOL accessYesNo = FALSE;  	PRIVILEGE_SET privSet;  	DWORD privSetSize = sizeof(PRIVILEGE_SET);  	int error;  	/* -	 * First find out how big the buffer needs to be +	 * First find out how big the buffer needs to be.  	 */  	size = 0; -	(*tclWinProcs->getFileSecurityProc)(nativePath, +	GetFileSecurity(nativePath,  		OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION -		| DACL_SECURITY_INFORMATION, 0, 0, &size); +		| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, +		0, 0, &size);  	/*  	 * Should have failed with ERROR_INSUFFICIENT_BUFFER @@ -1618,12 +1624,12 @@ NativeAccess(  	     * to EACCES - just what we want!  	     */ -	    TclWinConvertError((DWORD)error); +	    TclWinConvertError((DWORD) error);  	    return -1;  	}  	/* -	 * Now size contains the size of buffer needed +	 * Now size contains the size of buffer needed.  	 */  	sdPtr = (SECURITY_DESCRIPTOR *) HeapAlloc(GetProcessHeap(), 0, size); @@ -1633,12 +1639,13 @@ NativeAccess(  	}  	/* -	 * Call GetFileSecurity() for real +	 * Call GetFileSecurity() for real.  	 */ -	if (!(*tclWinProcs->getFileSecurityProc)(nativePath, +	if (!GetFileSecurity(nativePath,  		OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION -		| DACL_SECURITY_INFORMATION, sdPtr, size, &size)) { +		| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION, +		sdPtr, size, &size)) {  	    /*  	     * Error getting owner SD  	     */ @@ -1647,28 +1654,48 @@ NativeAccess(  	}  	/* -	 * Perform security impersonation of the user and open the -	 * resulting thread token. +	 * As of Samba 3.0.23 (10-Jul-2006), unmapped users and groups are +	 * assigned to SID domains S-1-22-1 and S-1-22-2, where "22" is the +	 * top-level authority.	 If the file owner and group is unmapped then +	 * the ACL access check below will only test against world access, +	 * which is likely to be more restrictive than the actual access +	 * restrictions.  Since the ACL tests are more likely wrong than +	 * right, skip them.  Moreover, the unix owner access permissions are +	 * usually mapped to the Windows attributes, so if the user is the +	 * file owner then the attrib checks above are correct (as far as they +	 * go).  	 */ -	if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) { +	if(!GetSecurityDescriptorOwner(sdPtr,&pSid,&SidDefaulted) || +	   memcmp(GetSidIdentifierAuthority(pSid),&samba_unmapped, +		  sizeof(SID_IDENTIFIER_AUTHORITY))==0) { +	    HeapFree(GetProcessHeap(), 0, sdPtr); +	    return 0; /* Attrib tests say access allowed. */ +	} + +	/* +	 * Perform security impersonation of the user and open the resulting +	 * thread token. +	 */ + +	if (!ImpersonateSelf(SecurityImpersonation)) {  	    /*  	     * Unable to perform security impersonation.  	     */ -	     +  	    goto accessError;  	} -	if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread (), +	if (!OpenThreadToken(GetCurrentThread(),  		TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) {  	    /*  	     * Unable to get current thread's token.  	     */ -	     +  	    goto accessError;  	} -	 -	(*tclWinProcs->revertToSelfProc)(); -	 + +	RevertToSelf(); +  	/*  	 * Setup desiredAccess according to the access priveleges we are  	 * checking. @@ -1684,17 +1711,17 @@ NativeAccess(  	    desiredAccess |= FILE_GENERIC_EXECUTE;  	} -	memset (&genMap, 0x0, sizeof (GENERIC_MAPPING)); +	memset(&genMap, 0x0, sizeof(GENERIC_MAPPING));  	genMap.GenericRead = FILE_GENERIC_READ;  	genMap.GenericWrite = FILE_GENERIC_WRITE;  	genMap.GenericExecute = FILE_GENERIC_EXECUTE;  	genMap.GenericAll = FILE_ALL_ACCESS; -	 +  	/*  	 * Perform access check using the token.  	 */ -	if (!(*tclWinProcs->accessCheckProc)(sdPtr, hToken, desiredAccess, +	if (!AccessCheck(sdPtr, hToken, desiredAccess,  		&genMap, &privSet, &privSetSize, &grantedAccess,  		&accessYesNo)) {  	    /* @@ -1716,23 +1743,15 @@ NativeAccess(  	 * Clean up.  	 */ -	HeapFree(GetProcessHeap (), 0, sdPtr); +	HeapFree(GetProcessHeap(), 0, sdPtr);  	CloseHandle(hToken);  	if (!accessYesNo) {  	    Tcl_SetErrno(EACCES);  	    return -1;  	} -	/* -	 * For directories the above checks are ok.  For files, though, -	 * we must still check the 'attr' value. -	 */ -	if ((mode & W_OK) -	  && !(attr & FILE_ATTRIBUTE_DIRECTORY) -	  && (attr & FILE_ATTRIBUTE_READONLY)) { -	    Tcl_SetErrno(EACCES); -	    return -1; -	} +      } +#endif /* !UNICODE */      return 0;  } @@ -1752,58 +1771,22 @@ NativeAccess(  static int  NativeIsExec( -    CONST TCHAR *nativePath) +    const TCHAR *path)  { -    if (tclWinProcs->useWide) { -	CONST WCHAR *path; -	int len; - -	path = (CONST WCHAR*)nativePath; -	len = wcslen(path); - -	if (len < 5) { -	    return 0; -	} - -	if (path[len-4] != L'.') { -	    return 0; -	} - -	/* -	 * Use wide-char case-insensitive comparison -	 */ - -	if ((_wcsicmp(path+len-3,L"exe") == 0) -		|| (_wcsicmp(path+len-3,L"com") == 0) -		|| (_wcsicmp(path+len-3,L"bat") == 0)) { -	    return 1; -	} -    } else { -	CONST char *p; +    int len = _tcslen(path); -	/* -	 * We are only looking for pure ascii. -	 */ - -	p = strrchr((CONST char*)nativePath, '.'); -	if (p != NULL) { -	    p++; - -	    /* -	     * Note: in the old code, stat considered '.pif' files as -	     * executable, whereas access did not. -	     */ +    if (len < 5) { +	return 0; +    } -	    if ((stricmp(p, "exe") == 0) -		    || (stricmp(p, "com") == 0) -		    || (stricmp(p, "bat") == 0)) { -		/* -		 * File that ends with .exe, .com, or .bat is executable. -		 */ +    if (path[len-4] != '.') { +	return 0; +    } -		return 1; -	    } -	} +    if ((_tcsicmp(path+len-3, TEXT("exe")) == 0) +	    || (_tcsicmp(path+len-3, TEXT("com")) == 0) +	    || (_tcsicmp(path+len-3, TEXT("bat")) == 0)) { +	return 1;      }      return 0;  } @@ -1829,28 +1812,14 @@ TclpObjChdir(      Tcl_Obj *pathPtr)	/* Path to new working directory. */  {      int result; -    CONST TCHAR *nativePath; -#ifdef __CYGWIN__ -    extern int cygwin_conv_to_posix_path(CONST char *, char *); -    char posixPath[MAX_PATH+1]; -    CONST char *path; -    Tcl_DString ds; -#endif /* __CYGWIN__ */ +    const TCHAR *nativePath; -    nativePath = (CONST TCHAR *) Tcl_FSGetNativePath(pathPtr); +    nativePath = Tcl_FSGetNativePath(pathPtr); -#ifdef __CYGWIN__ -    /* -     * Cygwin chdir only groks POSIX path. -     */ - -    path = Tcl_WinTCharToUtf(nativePath, -1, &ds); -    cygwin_conv_to_posix_path(path, posixPath); -    result = (chdir(posixPath) == 0 ? 1 : 0); -    Tcl_DStringFree(&ds); -#else /* __CYGWIN__ */ -    result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath); -#endif /* __CYGWIN__ */ +    if (!nativePath) { +	return -1; +    } +    result = SetCurrentDirectory(nativePath);      if (result == 0) {  	TclWinConvertError(GetLastError()); @@ -1859,51 +1828,6 @@ TclpObjChdir(      return 0;  } -#ifdef __CYGWIN__ -/* - *--------------------------------------------------------------------------- - * - * TclpReadlink -- - * - *	This function replaces the library version of readlink(). - * - * Results: - *	The result is a pointer to a string specifying the contents of the - *	symbolic link given by 'path', or NULL if the symbolic link could not - *	be read. Storage for the result string is allocated in bufferPtr; the - *	caller must call Tcl_DStringFree() when the result is no longer - *	needed. - * - * Side effects: - *	See readlink() documentation. - * - *--------------------------------------------------------------------------- - */ - -char * -TclpReadlink( -    CONST char *path,		/* Path of file to readlink (UTF-8). */ -    Tcl_DString *linkPtr)	/* Uninitialized or free DString filled with -				 * contents of link (UTF-8). */ -{ -    char link[MAXPATHLEN]; -    int length; -    char *native; -    Tcl_DString ds; - -    native = Tcl_UtfToExternalDString(NULL, path, -1, &ds); -    length = readlink(native, link, sizeof(link));	/* INTL: Native. */ -    Tcl_DStringFree(&ds); - -    if (length < 0) { -	return NULL; -    } - -    Tcl_ExternalToUtfDString(NULL, link, length, linkPtr); -    return Tcl_DStringValue(linkPtr); -} -#endif /* __CYGWIN__ */ -  /*   *----------------------------------------------------------------------   * @@ -1926,20 +1850,22 @@ TclpReadlink(   *----------------------------------------------------------------------   */ -CONST char * +const char *  TclpGetCwd(      Tcl_Interp *interp,		/* If non-NULL, used for error reporting. */      Tcl_DString *bufferPtr)	/* Uninitialized or free DString filled with  				 * name of current directory. */  { -    WCHAR buffer[MAX_PATH]; +    TCHAR buffer[MAX_PATH];      char *p; +    WCHAR *native; -    if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) { +    if (GetCurrentDirectory(MAX_PATH, buffer) == 0) {  	TclWinConvertError(GetLastError());  	if (interp != NULL) { -	    Tcl_AppendResult(interp, "error getting working directory name: ", -		    Tcl_PosixError(interp), NULL); +	    Tcl_SetObjResult(interp, Tcl_ObjPrintf( +		    "error getting working directory name: %s", +		    Tcl_PosixError(interp)));  	}  	return NULL;      } @@ -1948,25 +1874,12 @@ TclpGetCwd(       * Watch for the weird Windows c:\\UNC syntax.       */ -    if (tclWinProcs->useWide) { -	WCHAR *native; - -	native = (WCHAR *) buffer; -	if ((native[0] != '\0') && (native[1] == ':') -		&& (native[2] == '\\') && (native[3] == '\\')) { -	    native += 2; -	} -	Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr); -    } else { -	char *native; - -	native = (char *) buffer; -	if ((native[0] != '\0') && (native[1] == ':') -		&& (native[2] == '\\') && (native[3] == '\\')) { -	    native += 2; -	} -	Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr); +    native = (WCHAR *) buffer; +    if ((native[0] != '\0') && (native[1] == ':') +	    && (native[2] == '\\') && (native[3] == '\\')) { +	native += 2;      } +    Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr);      /*       * Convert to forward slashes for easier use in scripts. @@ -1993,7 +1906,7 @@ TclpObjStat(      TclWinFlushDirtyChannels(); -    return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 0); +    return NativeStat(Tcl_FSGetNativePath(pathPtr), statPtr, 0);  }  /* @@ -2021,28 +1934,27 @@ TclpObjStat(  static int  NativeStat( -    CONST TCHAR *nativePath,	/* Path of file to stat */ +    const TCHAR *nativePath,	/* Path of file to stat */      Tcl_StatBuf *statPtr,	/* Filled with results of stat call. */      int checkLinks)		/* If non-zero, behave like 'lstat' */  {      DWORD attr; -    int dev; +    int dev, nlink = 1;      unsigned short mode; -    int nlink = 1;      unsigned int inode = 0;      HANDLE fileHandle;      /* -     * If we can use 'createFile' on this, then we can use the -     * resulting fileHandle to read more information (nlink, ino) -     * than we can get from other attributes reading APIs.  If not, -     * then we try to fall back on the 'getFileAttributesExProc', -     * and if that isn't available, then on even simpler routines. +     * If we can use 'createFile' on this, then we can use the resulting +     * fileHandle to read more information (nlink, ino) than we can get from +     * other attributes reading APIs. If not, then we try to fall back on the +     * 'getFileAttributesExProc', and if that isn't available, then on even +     * simpler routines.       */ -    fileHandle = (tclWinProcs->createFileProc) ( -	nativePath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,  -	NULL, OPEN_EXISTING, -	FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL); + +    fileHandle = CreateFile(nativePath, GENERIC_READ, +	    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, +	    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);      if (fileHandle != INVALID_HANDLE_VALUE) {  	BY_HANDLE_FILE_INFORMATION data; @@ -2056,92 +1968,62 @@ NativeStat(  	attr = data.dwFileAttributes; -	statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) | -		(((Tcl_WideInt)data.nFileSizeHigh) << 32); +	statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) | +		(((Tcl_WideInt) data.nFileSizeHigh) << 32);  	statPtr->st_atime = ToCTime(data.ftLastAccessTime);  	statPtr->st_mtime = ToCTime(data.ftLastWriteTime);  	statPtr->st_ctime = ToCTime(data.ftCreationTime);  	/* -	 * On Unix, for directories, nlink apparently depends on the -	 * number of files in the directory.  We could calculate that, -	 * but it would be a bit of a performance penalty, I think. -	 * Hence we just use what Windows gives us, which is the -	 * same as Unix for files, at least. +	 * On Unix, for directories, nlink apparently depends on the number of +	 * files in the directory.  We could calculate that, but it would be a +	 * bit of a performance penalty, I think. Hence we just use what +	 * Windows gives us, which is the same as Unix for files, at least.  	 */  	nlink = data.nNumberOfLinks;  	/* -	 * Unfortunately our stat definition's inode field (unsigned -	 * short) will throw away most of the precision we have here, -	 * which means we can't rely on inode as a unique identifier of -	 * a file.  We'd really like to do something like how we handle -	 * 'st_size'. +	 * Unfortunately our stat definition's inode field (unsigned short) +	 * will throw away most of the precision we have here, which means we +	 * can't rely on inode as a unique identifier of a file. We'd really +	 * like to do something like how we handle 'st_size'.  	 */  	inode = data.nFileIndexHigh | data.nFileIndexLow; -    } else if (tclWinProcs->getFileAttributesExProc != NULL) { +    } else {  	/* -	 * Fall back on the less capable routines.  This means -	 * no nlink or ino. +	 * Fall back on the less capable routines. This means no nlink or ino.  	 */  	WIN32_FILE_ATTRIBUTE_DATA data; -	if ((*tclWinProcs->getFileAttributesExProc)(nativePath, +	if (GetFileAttributesEx(nativePath,  		GetFileExInfoStandard, &data) != TRUE) { -	    Tcl_SetErrno(ENOENT); -	    return -1; +	    HANDLE hFind; +	    WIN32_FIND_DATA ffd; +	    DWORD lasterror = GetLastError(); + +	    if (lasterror != ERROR_SHARING_VIOLATION) { +		TclWinConvertError(lasterror); +		return -1; +		} +	    hFind = FindFirstFile(nativePath, &ffd); +	    if (hFind == INVALID_HANDLE_VALUE) { +		TclWinConvertError(GetLastError()); +		return -1; +	    } +	    memcpy(&data, &ffd, sizeof(data)); +	    FindClose(hFind);  	}  	attr = data.dwFileAttributes; -	statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) | -		(((Tcl_WideInt)data.nFileSizeHigh) << 32); +	statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) | +		(((Tcl_WideInt) data.nFileSizeHigh) << 32);  	statPtr->st_atime = ToCTime(data.ftLastAccessTime);  	statPtr->st_mtime = ToCTime(data.ftLastWriteTime);  	statPtr->st_ctime = ToCTime(data.ftCreationTime); -    } else { -	/* -	 * We don't have the faster attributes proc, so we're probably -	 * running on Win95. -	 */ - -	WIN32_FIND_DATAT data; -	HANDLE handle; - -	handle = (*tclWinProcs->findFirstFileProc)(nativePath, &data); -	if (handle == INVALID_HANDLE_VALUE) { -	    /* -	     * FindFirstFile() doesn't work on root directories, so call -	     * GetFileAttributes() to see if the specified file exists. -	     */ - -	    attr = (*tclWinProcs->getFileAttributesProc)(nativePath); -	    if (attr == INVALID_FILE_ATTRIBUTES) { -		Tcl_SetErrno(ENOENT); -		return -1; -	    } - -	    /* -	     * Make up some fake information for this file.  It has the -	     * correct file attributes and a time of 0. -	     */ - -	    memset(&data, 0, sizeof(data)); -	    data.a.dwFileAttributes = attr; -	} else { -	    FindClose(handle); -	} - -	attr = data.a.dwFileAttributes; - -	statPtr->st_size = ((Tcl_WideInt)data.a.nFileSizeLow) | -		(((Tcl_WideInt)data.a.nFileSizeHigh) << 32); -	statPtr->st_atime = ToCTime(data.a.ftLastAccessTime); -	statPtr->st_mtime = ToCTime(data.a.ftLastWriteTime); -	statPtr->st_ctime = ToCTime(data.a.ftCreationTime);      }      dev = NativeDev(nativePath); @@ -2169,49 +2051,46 @@ NativeStat(  static int  NativeDev( -    CONST TCHAR *nativePath)	/* Full path of file to stat */ +    const TCHAR *nativePath)	/* Full path of file to stat */  {      int dev;      Tcl_DString ds; -    WCHAR nativeFullPath[MAX_PATH]; +    TCHAR nativeFullPath[MAX_PATH];      TCHAR *nativePart; -    CONST char *fullPath; - -    (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, -	    nativeFullPath, &nativePart); +    const char *fullPath; -    fullPath = Tcl_WinTCharToUtf((TCHAR*)nativeFullPath, -1, &ds); +    GetFullPathName(nativePath, MAX_PATH, nativeFullPath, &nativePart); +    fullPath = Tcl_WinTCharToUtf(nativeFullPath, -1, &ds);      if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) { -	CONST char *p; +	const char *p;  	DWORD dw; -	CONST TCHAR *nativeVol; +	const TCHAR *nativeVol;  	Tcl_DString volString;  	p = strchr(fullPath + 2, '\\');  	p = strchr(p + 1, '\\');  	if (p == NULL) {  	    /* -	     * Add terminating backslash to fullpath or -	     * GetVolumeInformation() won't work. +	     * Add terminating backslash to fullpath or GetVolumeInformation() +	     * won't work.  	     */ -	    fullPath = Tcl_DStringAppend(&ds, "\\", 1); +	    fullPath = TclDStringAppendLiteral(&ds, "\\");  	    p = fullPath + Tcl_DStringLength(&ds);  	} else {  	    p++;  	}  	nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);  	dw = (DWORD) -1; -	(*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw, -		NULL, NULL, NULL, 0); +	GetVolumeInformation(nativeVol, NULL, 0, &dw, NULL, NULL, NULL, 0);  	/* -	 * GetFullPathName() turns special devices like "NUL" into -	 * "\\.\NUL", but GetVolumeInformation() returns failure for -	 * "\\.\NUL". This will cause "NUL" to get a drive number of -1, -	 * which makes about as much sense as anything since the special -	 * devices don't live on any drive. +	 * GetFullPathName() turns special devices like "NUL" into "\\.\NUL", +	 * but GetVolumeInformation() returns failure for "\\.\NUL". This will +	 * cause "NUL" to get a drive number of -1, which makes about as much +	 * sense as anything since the special devices don't live on any +	 * drive.  	 */  	dev = dw; @@ -2246,6 +2125,7 @@ NativeStatMode(      int isExec)  {      int mode; +      if (checkLinks && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) {  	/*  	 * It is a link. @@ -2253,9 +2133,9 @@ NativeStatMode(  	mode = S_IFLNK;      } else { -	mode = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR | S_IEXEC : S_IFREG; +	mode = (attr & FILE_ATTRIBUTE_DIRECTORY) ? S_IFDIR|S_IEXEC : S_IFREG;      } -    mode |= (attr & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD | S_IWRITE; +    mode |= (attr & FILE_ATTRIBUTE_READONLY) ? S_IREAD : S_IREAD|S_IWRITE;      if (isExec) {  	mode |= S_IEXEC;      } @@ -2265,9 +2145,9 @@ NativeStatMode(       * positions.       */ -    mode |= (mode & 0x0700) >> 3; -    mode |= (mode & 0x0700) >> 6; -    return (unsigned short)mode; +    mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 3; +    mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 6; +    return (unsigned short) mode;  }  /* @@ -2292,8 +2172,8 @@ ToCTime(      convertedTime.LowPart = fileTime.dwLowDateTime;      convertedTime.HighPart = (LONG) fileTime.dwHighDateTime; -    return (time_t) ((convertedTime.QuadPart -	    - (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000); +    return (time_t) ((convertedTime.QuadPart - +	    (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000);  }  /* @@ -2312,93 +2192,16 @@ ToCTime(  static void  FromCTime(      time_t posixTime, -    FILETIME* fileTime)		/* UTC Time */ +    FILETIME *fileTime)		/* UTC Time */  {      LARGE_INTEGER convertedTime; +      convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000 -	+ POSIX_EPOCH_AS_FILETIME; +	    + POSIX_EPOCH_AS_FILETIME;      fileTime->dwLowDateTime = convertedTime.LowPart;      fileTime->dwHighDateTime = convertedTime.HighPart;  } -#if 0 -/* - *------------------------------------------------------------------------- - * - * TclWinResolveShortcut -- - * - *	Resolve a potential Windows shortcut to get the actual file or - *	directory in question. - * - * Results: - *	Returns 1 if the shortcut could be resolved, or 0 if there was an - *	error or if the filename was not a shortcut. If bufferPtr did hold the - *	name of a shortcut, it is modified to hold the resolved target of the - *	shortcut instead. - * - * Side effects: - *	Loads and unloads OLE package to determine if filename refers to a - *	shortcut. - * - *------------------------------------------------------------------------- - */ - -int -TclWinResolveShortcut( -    Tcl_DString *bufferPtr)	/* Holds name of file to resolve. On return, -				 * holds resolved file name. */ -{ -    HRESULT hres; -    IShellLink *psl; -    IPersistFile *ppf; -    WIN32_FIND_DATA wfd; -    WCHAR wpath[MAX_PATH]; -    char *path, *ext; -    char realFileName[MAX_PATH]; - -    /* -     * Windows system calls do not automatically resolve shortcuts like UNIX -     * automatically will with symbolic links. -     */ - -    path = Tcl_DStringValue(bufferPtr); -    ext = strrchr(path, '.'); -    if ((ext == NULL) || (stricmp(ext, ".lnk") != 0)) { -	return 0; -    } - -    CoInitialize(NULL); -    path = Tcl_DStringValue(bufferPtr); -    realFileName[0] = '\0'; -    hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, -	    &IID_IShellLink, &psl); -    if (SUCCEEDED(hres)) { -	hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf); -	if (SUCCEEDED(hres)) { -	    MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, sizeof(wpath)); -	    hres = ppf->lpVtbl->Load(ppf, wpath, STGM_READ); -	    if (SUCCEEDED(hres)) { -		hres = psl->lpVtbl->Resolve(psl,NULL,SLR_ANY_MATCH|SLR_NO_UI); -		if (SUCCEEDED(hres)) { -		    hres = psl->lpVtbl->GetPath(psl, realFileName, MAX_PATH, -			    &wfd, 0); -		} -	    } -	    ppf->lpVtbl->Release(ppf); -	} -	psl->lpVtbl->Release(psl); -    } -    CoUninitialize(); - -    if (realFileName[0] != '\0') { -	Tcl_DStringSetLength(bufferPtr, 0); -	Tcl_DStringAppend(bufferPtr, realFileName, -1); -	return 1; -    } -    return 0; -} -#endif -  /*   *---------------------------------------------------------------------------   * @@ -2424,34 +2227,20 @@ ClientData  TclpGetNativeCwd(      ClientData clientData)  { -    WCHAR buffer[MAX_PATH]; +    TCHAR buffer[MAX_PATH]; -    if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) { +    if (GetCurrentDirectory(MAX_PATH, buffer) == 0) {  	TclWinConvertError(GetLastError());  	return NULL;      }      if (clientData != NULL) { -	if (tclWinProcs->useWide) { -	    /* -	     * Unicode representation when running on NT/2K/XP. -	     */ - -	    if (wcscmp((CONST WCHAR*)clientData, (CONST WCHAR*)buffer) == 0) { -		return clientData; -	    } -	} else { -	    /* -	     * ANSI representation when running on 95/98/ME. -	     */ - -	    if (strcmp((CONST char*)clientData, (CONST char*)buffer) == 0) { -		return clientData; -	    } +	if (_tcscmp((const TCHAR*)clientData, buffer) == 0) { +	    return clientData;  	}      } -    return TclNativeDupInternalRep((ClientData)buffer); +    return TclNativeDupInternalRep(buffer);  }  int @@ -2459,7 +2248,7 @@ TclpObjAccess(      Tcl_Obj *pathPtr,      int mode)  { -    return NativeAccess((CONST TCHAR *) Tcl_FSGetNativePath(pathPtr), mode); +    return NativeAccess(Tcl_FSGetNativePath(pathPtr), mode);  }  int @@ -2475,11 +2264,11 @@ TclpObjLstat(      TclWinFlushDirtyChannels(); -    return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 1); +    return NativeStat(Tcl_FSGetNativePath(pathPtr), statPtr, 1);  }  #ifdef S_IFLNK -Tcl_Obj* +Tcl_Obj *  TclpObjLink(      Tcl_Obj *pathPtr,      Tcl_Obj *toPtr, @@ -2487,15 +2276,15 @@ TclpObjLink(  {      if (toPtr != NULL) {  	int res; -	TCHAR *LinkTarget; -	TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr); +	const TCHAR *LinkTarget; +	const TCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr);  	Tcl_Obj *normalizedToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr);  	if (normalizedToPtr == NULL) {  	    return NULL;  	} -	LinkTarget = (TCHAR *) Tcl_FSGetNativePath(normalizedToPtr); +	LinkTarget = Tcl_FSGetNativePath(normalizedToPtr);  	if (LinkSource == NULL || LinkTarget == NULL) {  	    return NULL; @@ -2507,7 +2296,7 @@ TclpObjLink(  	    return NULL;  	}      } else { -	TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr); +	const TCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr);  	if (LinkSource == NULL) {  	    return NULL; @@ -2515,7 +2304,7 @@ TclpObjLink(  	return WinReadLink(LinkSource);      }  } -#endif +#endif /* S_IFLNK */  /*   *--------------------------------------------------------------------------- @@ -2535,15 +2324,15 @@ TclpObjLink(   *---------------------------------------------------------------------------   */ -Tcl_Obj* +Tcl_Obj *  TclpFilesystemPathType( -    Tcl_Obj* pathPtr) +    Tcl_Obj *pathPtr)  {  #define VOL_BUF_SIZE 32      int found; -    WCHAR volType[VOL_BUF_SIZE]; -    char* firstSeparator; -    CONST char *path; +    TCHAR volType[VOL_BUF_SIZE]; +    char *firstSeparator; +    const char *path;      Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathPtr);      if (normPath == NULL) { @@ -2556,16 +2345,14 @@ TclpFilesystemPathType(      firstSeparator = strchr(path, '/');      if (firstSeparator == NULL) { -	found = tclWinProcs->getVolumeInformationProc( -		Tcl_FSGetNativePath(pathPtr), NULL, 0, NULL, NULL, NULL, -		(WCHAR *) volType, VOL_BUF_SIZE); +	found = GetVolumeInformation(Tcl_FSGetNativePath(pathPtr), +		NULL, 0, NULL, NULL, NULL, volType, VOL_BUF_SIZE);      } else {  	Tcl_Obj *driveName = Tcl_NewStringObj(path, firstSeparator - path+1);  	Tcl_IncrRefCount(driveName); -	found = tclWinProcs->getVolumeInformationProc( -		Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, NULL, -		(WCHAR *) volType, VOL_BUF_SIZE); +	found = GetVolumeInformation(Tcl_FSGetNativePath(driveName), +		NULL, 0, NULL, NULL, NULL, volType, VOL_BUF_SIZE);  	Tcl_DecrRefCount(driveName);      } @@ -2573,13 +2360,9 @@ TclpFilesystemPathType(  	return NULL;      } else {  	Tcl_DString ds; -	Tcl_Obj *objPtr; -	Tcl_WinTCharToUtf((CONST char *)volType, -1, &ds); -	objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -		Tcl_DStringLength(&ds)); -	Tcl_DStringFree(&ds); -	return objPtr; +	Tcl_WinTCharToUtf(volType, -1, &ds); +	return TclDStringToObj(&ds);      }  #undef VOL_BUF_SIZE  } @@ -2627,360 +2410,221 @@ TclpObjNormalizePath(  {      char *lastValidPathEnd = NULL;      Tcl_DString dsNorm;		/* This will hold the normalized string. */ -    char *path; -    char *currentPathEndPosition; +    char *path, *currentPathEndPosition; +    Tcl_Obj *temp = NULL; +    int isDrive = 1; +    Tcl_DString ds;		/* Some workspace. */      Tcl_DStringInit(&dsNorm);      path = Tcl_GetString(pathPtr); -    if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) { -	/* -	 * We're on Win95, 98 or ME. There are two assumptions in this block -	 * of code. First that the native (NULL) encoding is basically ascii, -	 * and second that symbolic links are not possible. Both of these -	 * assumptions appear to be true of these operating systems. -	 */ - -	int isDrive = 1; -	Tcl_DString ds; - -	currentPathEndPosition = path + nextCheckpoint; -	if (*currentPathEndPosition == '/') { -	    currentPathEndPosition++; -	} +    currentPathEndPosition = path + nextCheckpoint; +    if (*currentPathEndPosition == '/') { +	currentPathEndPosition++; +    } +    while (1) { +	char cur = *currentPathEndPosition; -	while (1) { -	    char cur = *currentPathEndPosition; -	    if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { -		/* -		 * Reached directory separator, or end of string. -		 */ +	if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) { +	    /* +	     * Reached directory separator, or end of string. +	     */ -		CONST char *nativePath = Tcl_UtfToExternalDString(NULL, path, -			currentPathEndPosition - path, &ds); +	    WIN32_FILE_ATTRIBUTE_DATA data; +	    const TCHAR *nativePath = Tcl_WinUtfToTChar(path, +		    currentPathEndPosition - path, &ds); +	    if (GetFileAttributesEx(nativePath, +		    GetFileExInfoStandard, &data) != TRUE) {  		/* -		 * Now we convert the tail of the current path to its 'long -		 * form', and append it to 'dsNorm' which holds the current -		 * normalized path, if the file exists. +		 * File doesn't exist.  		 */  		if (isDrive) { -		    if (GetFileAttributesA(nativePath) == INVALID_FILE_ATTRIBUTES) { -			/* -			 * File doesn't exist. -			 */ - -			if (isDrive) { -			    int len = WinIsReserved(path); -			    if (len > 0) { -				/* -				 * Actually it does exist - COM1, etc. -				 */ - -				int i; - -				for (i=0;i<len;i++) { -				    if (nativePath[i] >= 'a') { -					((char*)nativePath)[i] -= ('a' - 'A'); -				    } -				} -				Tcl_DStringAppend(&dsNorm, nativePath, len); -				lastValidPathEnd = currentPathEndPosition; -			    } -			} -			Tcl_DStringFree(&ds); -			break; -		    } -		    if (nativePath[0] >= 'a') { -			((char*)nativePath)[0] -= ('a' - 'A'); -		    } -		    Tcl_DStringAppend(&dsNorm, nativePath, -			    Tcl_DStringLength(&ds)); -		} else { -		    char *checkDots = NULL; - -		    if (lastValidPathEnd[1] == '.') { -			checkDots = lastValidPathEnd + 1; -			while (checkDots < currentPathEndPosition) { -			    if (*checkDots != '.') { -				checkDots = NULL; -				break; -			    } -			    checkDots++; -			} -		    } -		    if (checkDots != NULL) { -			int dotLen = currentPathEndPosition - lastValidPathEnd; +		    int len = WinIsReserved(path); +		    if (len > 0) {  			/* -			 * Path is just dots. We shouldn't really ever see a -			 * path like that. However, to be nice we at least -			 * don't mangle the path - we just add the dots as a -			 * path segment and continue +			 * Actually it does exist - COM1, etc.  			 */ -			Tcl_DStringAppend(&dsNorm, (TCHAR *) -				(nativePath + Tcl_DStringLength(&ds) - dotLen), -				dotLen); -		    } else { -			/* -			 * Normal path. -			 */ +			int i; -			WIN32_FIND_DATA fData; -			HANDLE handle; +			for (i=0 ; i<len ; i++) { +			    WCHAR wc = ((WCHAR *) nativePath)[i]; -			handle = FindFirstFileA(nativePath, &fData); -			if (handle == INVALID_HANDLE_VALUE) { -			    if (GetFileAttributesA(nativePath) == INVALID_FILE_ATTRIBUTES) { -				/* -				 * File doesn't exist. -				 */ - -				Tcl_DStringFree(&ds); -				break; +			    if (wc >= L'a') { +				wc -= (L'a' - L'A'); +				((WCHAR *) nativePath)[i] = wc;  			    } - -			    /* -			     * This is usually the '/' in 'c:/' at end of -			     * string. -			     */ - -			    Tcl_DStringAppend(&dsNorm,"/", 1); -			} else { -			    char *nativeName; - -			    if (fData.cFileName[0] != '\0') { -				nativeName = fData.cFileName; -			    } else { -				nativeName = fData.cAlternateFileName; -			    } -			    FindClose(handle); -			    Tcl_DStringAppend(&dsNorm,"/", 1); -			    Tcl_DStringAppend(&dsNorm,nativeName,-1);  			} +			Tcl_DStringAppend(&dsNorm, +				(const char *)nativePath, +				(int)(sizeof(WCHAR) * len)); +			lastValidPathEnd = currentPathEndPosition; +		    } else if (nextCheckpoint == 0) { +			/* Path starts with a drive designation +			 * that's not actually on the system. +			 * We still must normalize up past the +			 * first separator.  [Bug 3603434] */ +			currentPathEndPosition++;  		    }  		}  		Tcl_DStringFree(&ds); -		lastValidPathEnd = currentPathEndPosition; -		if (cur == 0) { -		    break; -		} - -		/* -		 * If we get here, we've got past one directory delimiter, so -		 * we know it is no longer a drive. -		 */ - -		isDrive = 0; +		break;  	    } -	    currentPathEndPosition++; -	} -    } else { -	/* -	 * We're on WinNT (or 2000 or XP; something with an NT core). -	 */ -	Tcl_Obj *temp = NULL; -	int isDrive = 1; -	Tcl_DString ds; +	    /* +	     * File 'nativePath' does exist if we get here. We now want to +	     * check if it is a symlink and otherwise continue with the +	     * rest of the path. +	     */ -	currentPathEndPosition = path + nextCheckpoint; -	if (*currentPathEndPosition == '/') { -	    currentPathEndPosition++; -	} -	while (1) { -	    char cur = *currentPathEndPosition; -	    if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { -		/* -		 * Reached directory separator, or end of string. -		 */ +	    /* +	     * Check for symlinks, except at last component of path (we +	     * don't follow final symlinks). Also a drive (C:/) for +	     * example, may sometimes have the reparse flag set for some +	     * reason I don't understand. We therefore don't perform this +	     * check for drives. +	     */ -		WIN32_FILE_ATTRIBUTE_DATA data; -		CONST char *nativePath = Tcl_WinUtfToTChar(path, -			currentPathEndPosition - path, &ds); +	    if (cur != 0 && !isDrive && +		    data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){ +		Tcl_Obj *to = WinReadLinkDirectory(nativePath); -		if ((*tclWinProcs->getFileAttributesExProc)(nativePath, -			GetFileExInfoStandard, &data) != TRUE) { +		if (to != NULL) {  		    /* -		     * File doesn't exist. +		     * Read the reparse point ok. Now, reparse points need +		     * not be normalized, otherwise we could use: +		     * +		     * Tcl_GetStringFromObj(to, &pathLen); +		     * nextCheckpoint = pathLen; +		     * +		     * So, instead we have to start from the beginning.  		     */ -		    if (isDrive) { -			int len = WinIsReserved(path); - -			if (len > 0) { -			    /* -			     * Actually it does exist - COM1, etc. -			     */ +		    nextCheckpoint = 0; +		    Tcl_AppendToObj(to, currentPathEndPosition, -1); -			    int i; +		    /* +		     * Convert link to forward slashes. +		     */ -			    for (i=0;i<len;i++) { -				WCHAR wc = ((WCHAR*)nativePath)[i]; -				if (wc >= L'a') { -				    wc -= (L'a' - L'A'); -				    ((WCHAR*)nativePath)[i] = wc; -				} -			    } -			    Tcl_DStringAppend(&dsNorm, nativePath, -				    (int)(sizeof(WCHAR)*len)); -			    lastValidPathEnd = currentPathEndPosition; +		    for (path = Tcl_GetString(to); *path != 0; path++) { +			if (*path == '\\') { +			    *path = '/';  			}  		    } -		    Tcl_DStringFree(&ds); -		    break; -		} - -		/* -		 * File 'nativePath' does exist if we get here. We now want to -		 * check if it is a symlink and otherwise continue with the -		 * rest of the path. -		 */ - -		/* -		 * Check for symlinks, except at last component of path (we -		 * don't follow final symlinks). Also a drive (C:/) for -		 * example, may sometimes have the reparse flag set for some -		 * reason I don't understand. We therefore don't perform this -		 * check for drives. -		 */ +		    path = Tcl_GetString(to); +		    currentPathEndPosition = path + nextCheckpoint; +		    if (temp != NULL) { +			Tcl_DecrRefCount(temp); +		    } +		    temp = to; -		if (cur != 0 && !isDrive && -			(data.dwFileAttributes&FILE_ATTRIBUTE_REPARSE_POINT)) { -		    Tcl_Obj *to = WinReadLinkDirectory(nativePath); +		    /* +		     * Reset variables so we can restart normalization. +		     */ -		    if (to != NULL) { -			/* -			 * Read the reparse point ok. Now, reparse points need -			 * not be normalized, otherwise we could use: -			 * -			 * Tcl_GetStringFromObj(to, &pathLen); -			 * nextCheckpoint = pathLen -			 * -			 * So, instead we have to start from the beginning. -			 */ +		    isDrive = 1; +		    Tcl_DStringFree(&dsNorm); +		    Tcl_DStringFree(&ds); +		    continue; +		} +	    } -			nextCheckpoint = 0; -			Tcl_AppendToObj(to, currentPathEndPosition, -1); +#ifndef TclNORM_LONG_PATH +	    /* +	     * Now we convert the tail of the current path to its 'long +	     * form', and append it to 'dsNorm' which holds the current +	     * normalized path +	     */ -			/* -			 * Convert link to forward slashes. -			 */ +	    if (isDrive) { +		WCHAR drive = ((WCHAR *) nativePath)[0]; -			for (path = Tcl_GetString(to); *path != 0; path++) { -			    if (*path == '\\') *path = '/'; -			} -			path = Tcl_GetString(to); -			currentPathEndPosition = path + nextCheckpoint; -			if (temp != NULL) { -			    Tcl_DecrRefCount(temp); +		if (drive >= L'a') { +		    drive -= (L'a' - L'A'); +		    ((WCHAR *) nativePath)[0] = drive; +		} +		Tcl_DStringAppend(&dsNorm, (const char *)nativePath, +			Tcl_DStringLength(&ds)); +	    } else { +		char *checkDots = NULL; + +		if (lastValidPathEnd[1] == '.') { +		    checkDots = lastValidPathEnd + 1; +		    while (checkDots < currentPathEndPosition) { +			if (*checkDots != '.') { +			    checkDots = NULL; +			    break;  			} -			temp = to; - -			/* -			 * Reset variables so we can restart normalization. -			 */ - -			isDrive = 1; -			Tcl_DStringFree(&dsNorm); -			Tcl_DStringInit(&dsNorm); -			Tcl_DStringFree(&ds); -			continue; +			checkDots++;  		    }  		} +		if (checkDots != NULL) { +		    int dotLen = currentPathEndPosition-lastValidPathEnd; -#ifndef TclNORM_LONG_PATH -		/* -		 * Now we convert the tail of the current path to its 'long -		 * form', and append it to 'dsNorm' which holds the current -		 * normalized path -		 */ +		    /* +		     * Path is just dots. We shouldn't really ever see a +		     * path like that. However, to be nice we at least +		     * don't mangle the path - we just add the dots as a +		     * path segment and continue. +		     */ -		if (isDrive) { -		    WCHAR drive = ((WCHAR*)nativePath)[0]; -		    if (drive >= L'a') { -			drive -= (L'a' - L'A'); -			((WCHAR*)nativePath)[0] = drive; -		    } -		    Tcl_DStringAppend(&dsNorm, nativePath, -			    Tcl_DStringLength(&ds)); +		    Tcl_DStringAppend(&dsNorm, ((const char *)nativePath) +			    + Tcl_DStringLength(&ds) +			    - (dotLen * sizeof(TCHAR)), +			    (int)(dotLen * sizeof(TCHAR)));  		} else { -		    char *checkDots = NULL; - -		    if (lastValidPathEnd[1] == '.') { -			checkDots = lastValidPathEnd + 1; -			while (checkDots < currentPathEndPosition) { -			    if (*checkDots != '.') { -				checkDots = NULL; -				break; -			    } -			    checkDots++; -			} -		    } -		    if (checkDots != NULL) { -			int dotLen = currentPathEndPosition - lastValidPathEnd; +		    /* +		     * Normal path. +		     */ -			/* -			 * Path is just dots. We shouldn't really ever see a -			 * path like that. However, to be nice we at least -			 * don't mangle the path - we just add the dots as a -			 * path segment and continue. -			 */ +		    WIN32_FIND_DATAW fData; +		    HANDLE handle; -			Tcl_DStringAppend(&dsNorm, (TCHAR *) -				((WCHAR*)(nativePath + Tcl_DStringLength(&ds)) -				- dotLen), (int)(dotLen * sizeof(WCHAR))); -		    } else { +		    handle = FindFirstFileW((WCHAR *) nativePath, &fData); +		    if (handle == INVALID_HANDLE_VALUE) {  			/* -			 * Normal path. +			 * This is usually the '/' in 'c:/' at end of +			 * string.  			 */ -			WIN32_FIND_DATAW fData; -			HANDLE handle; - -			handle = FindFirstFileW((WCHAR*)nativePath, &fData); -			if (handle == INVALID_HANDLE_VALUE) { -			    /* -			     * This is usually the '/' in 'c:/' at end of -			     * string. -			     */ +			Tcl_DStringAppend(&dsNorm, (const char *) L"/", +				sizeof(WCHAR)); +		    } else { +			WCHAR *nativeName; -			    Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", -				    sizeof(WCHAR)); +			if (fData.cFileName[0] != '\0') { +			    nativeName = fData.cFileName;  			} else { -			    WCHAR *nativeName; - -			    if (fData.cFileName[0] != '\0') { -				nativeName = fData.cFileName; -			    } else { -				nativeName = fData.cAlternateFileName; -			    } -			    FindClose(handle); -			    Tcl_DStringAppend(&dsNorm, (CONST char*)L"/", -				    sizeof(WCHAR)); -			    Tcl_DStringAppend(&dsNorm, (TCHAR *) nativeName, -				    (int) (wcslen(nativeName)*sizeof(WCHAR))); +			    nativeName = fData.cAlternateFileName;  			} +			FindClose(handle); +			Tcl_DStringAppend(&dsNorm, (const char *) L"/", +				sizeof(WCHAR)); +			Tcl_DStringAppend(&dsNorm, +				(const char *) nativeName, +				(int) (wcslen(nativeName)*sizeof(WCHAR)));  		    }  		} -#endif -		Tcl_DStringFree(&ds); -		lastValidPathEnd = currentPathEndPosition; -		if (cur == 0) { -		    break; -		} +	    } +#endif /* !TclNORM_LONG_PATH */ +	    Tcl_DStringFree(&ds); +	    lastValidPathEnd = currentPathEndPosition; +	    if (cur == 0) { +		break; +	    } -		/* -		 * If we get here, we've got past one directory delimiter, so -		 * we know it is no longer a drive. -		 */ +	    /* +	     * If we get here, we've got past one directory delimiter, so +	     * we know it is no longer a drive. +	     */ -		isDrive = 0; -	    } -	    currentPathEndPosition++; +	    isDrive = 0;  	} +	currentPathEndPosition++;  #ifdef TclNORM_LONG_PATH  	/* @@ -2989,10 +2633,10 @@ TclpObjNormalizePath(  	if (1) {  	    WCHAR wpath[MAX_PATH]; -	    CONST char *nativePath = +	    const TCHAR *nativePath =  		    Tcl_WinUtfToTChar(path, lastValidPathEnd - path, &ds); -	    DWORD wpathlen = (*tclWinProcs->getLongPathNameProc)( -		    nativePath, (TCHAR *) wpath, MAX_PATH); +	    DWORD wpathlen = GetLongPathNameProc(nativePath, +		    (TCHAR *) wpath, MAX_PATH);  	    /*  	     * We have to make the drive letter uppercase. @@ -3001,10 +2645,11 @@ TclpObjNormalizePath(  	    if (wpath[0] >= L'a') {  		wpath[0] -= (L'a' - L'A');  	    } -	    Tcl_DStringAppend(&dsNorm, (TCHAR*)wpath, wpathlen*sizeof(WCHAR)); +	    Tcl_DStringAppend(&dsNorm, (const char *) wpath, +		    wpathlen * sizeof(WCHAR));  	    Tcl_DStringFree(&ds);  	} -#endif +#endif /* TclNORM_LONG_PATH */      }      /* @@ -3019,11 +2664,9 @@ TclpObjNormalizePath(  	 * native encoding, so we have to convert it to Utf.  	 */ -	Tcl_DString dsTemp; - -	Tcl_WinTCharToUtf(Tcl_DStringValue(&dsNorm), -		Tcl_DStringLength(&dsNorm), &dsTemp); -	nextCheckpoint = Tcl_DStringLength(&dsTemp); +	Tcl_WinTCharToUtf((const TCHAR *) Tcl_DStringValue(&dsNorm), +		Tcl_DStringLength(&dsNorm), &ds); +	nextCheckpoint = Tcl_DStringLength(&ds);  	if (*lastValidPathEnd != 0) {  	    /*  	     * Not the end of the string. @@ -3033,7 +2676,7 @@ TclpObjNormalizePath(  	    char *path;  	    Tcl_Obj *tmpPathPtr; -	    tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp), +	    tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),  		    nextCheckpoint);  	    Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1);  	    path = Tcl_GetStringFromObj(tmpPathPtr, &len); @@ -3044,12 +2687,21 @@ TclpObjNormalizePath(  	     * End of string was reached above.  	     */ -	    Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&dsTemp), -		    nextCheckpoint); +	    Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&ds), nextCheckpoint);  	} -	Tcl_DStringFree(&dsTemp); +	Tcl_DStringFree(&ds);      }      Tcl_DStringFree(&dsNorm); + +    /* +     * This must be done after we are totally finished with 'path' as we are +     * sharing the same underlying string. +     */ + +    if (temp != NULL) { +	Tcl_DecrRefCount(temp); +    } +      return nextCheckpoint;  } @@ -3080,7 +2732,7 @@ TclpObjNormalizePath(  Tcl_Obj *  TclWinVolumeRelativeNormalize(      Tcl_Interp *interp, -    CONST char *path, +    const char *path,      Tcl_Obj **useThisCwdPtr)  {      Tcl_Obj *absolutePath, *useThisCwd; @@ -3096,7 +2748,7 @@ TclWinVolumeRelativeNormalize(  	 * current volume.  	 */ -	CONST char *drive = Tcl_GetString(useThisCwd); +	const char *drive = Tcl_GetString(useThisCwd);  	absolutePath = Tcl_NewStringObj(drive,2);  	Tcl_AppendToObj(absolutePath, path, -1); @@ -3112,7 +2764,7 @@ TclWinVolumeRelativeNormalize(  	 */  	int cwdLen; -	CONST char *drive = +	const char *drive =  		Tcl_GetStringFromObj(useThisCwd, &cwdLen);  	char drive_cur = path[0]; @@ -3187,11 +2839,9 @@ TclpNativeToNormalized(      Tcl_DString ds;      Tcl_Obj *objPtr;      int len; +    char *copy, *p; -    char *copy; -    char *p; -    Tcl_WinTCharToUtf((CONST char*)clientData, -1, &ds); - +    Tcl_WinTCharToUtf((const TCHAR *) clientData, -1, &ds);      copy = Tcl_DStringValue(&ds);      len = Tcl_DStringLength(&ds); @@ -3247,11 +2897,11 @@ ClientData  TclNativeCreateNativeRep(      Tcl_Obj *pathPtr)  { -    char *nativePathPtr; -    Tcl_DString ds; -    Tcl_Obj* validPathPtr; +    WCHAR *nativePathPtr; +    const char *str; +    Tcl_Obj *validPathPtr;      int len; -    char *str; +    WCHAR *wp;      if (TclFSCwdIsNative()) {  	/* @@ -3277,18 +2927,73 @@ TclNativeCreateNativeRep(      }      str = Tcl_GetStringFromObj(validPathPtr, &len); -    Tcl_WinUtfToTChar(str, len, &ds); -    if (tclWinProcs->useWide) { -	len = Tcl_DStringLength(&ds) + sizeof(WCHAR); -    } else { -	len = Tcl_DStringLength(&ds) + sizeof(char); -    } -    Tcl_DecrRefCount(validPathPtr); -    nativePathPtr = ckalloc((unsigned) len); -    memcpy((VOID*)nativePathPtr, (VOID*)Tcl_DStringValue(&ds), (size_t) len); -    Tcl_DStringFree(&ds); -    return (ClientData)nativePathPtr; +    if (strlen(str)!=len) { +	/* String contains NUL-bytes. This is invalid. */ +	return 0; +    } +    /* Let MultiByteToWideChar check for other invalid sequences, like +     * 0xC0 0x80 (== overlong NUL). See bug [3118489]: NUL in filenames */ +    len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, 0, 0); +    if (len==0) { +	return 0; +    } +    /* Overallocate 6 chars, making some room for extended paths */ +    wp = nativePathPtr = ckalloc( (len+6) * sizeof(WCHAR) ); +    if (nativePathPtr==0) { +      return 0; +    } +    MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, nativePathPtr, len); +    /* +    ** If path starts with "//?/" or "\\?\" (extended path), translate +    ** any slashes to backslashes but leave the '?' intact +    */ +    if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/') +	    && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) { +	wp[0] = wp[1] = wp[3] = '\\'; +	str += 4; +	wp += 4; +    } +    /* +    ** If there is no "\\?\" prefix but there is a drive or UNC +    ** path prefix and the path is larger than MAX_PATH chars, +    ** no Win32 API function can handle that unless it is +    ** prefixed with the extended path prefix. See: +    ** <http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath> +    **/ +    if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z')) +	    && str[1]==':' && (str[2]=='\\' || str[2]=='/')) { +	if (wp==nativePathPtr && len>MAX_PATH) { +	    memmove(wp+4, wp, len*sizeof(WCHAR)); +	    memcpy(wp, L"\\\\?\\", 4*sizeof(WCHAR)); +	    wp += 4; +	} +	/* +	 ** If (remainder of) path starts with "<drive>:/" or "<drive>:\", +	 ** leave the ':' intact but translate the backslash to a slash. +	 */ +	wp[2] = '\\'; +	wp += 3; +    } else if (wp==nativePathPtr && len>MAX_PATH +	    && (str[0]=='\\' || str[0]=='/') +	    && (str[1]=='\\' || str[1]=='/') && str[2]!='?') { +	memmove(wp+6, wp, len*sizeof(WCHAR)); +	memcpy(wp, L"\\\\?\\UNC", 7*sizeof(WCHAR)); +	wp += 7; +    } +    /* +    ** In the remainder of the path, translate invalid characters to +    ** characters in the Unicode private use area. +    */ +    while (*wp != '\0') { +	if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) { +	    *wp |= 0xF000; +	} else if (*wp == '/') { +	    *wp = '\\'; +	} +	++wp; +    } +    return nativePathPtr;  }  /* @@ -3319,23 +3024,11 @@ TclNativeDupInternalRep(  	return NULL;      } -    if (tclWinProcs->useWide) { -	/* -	 * Unicode representation when running on NT/2K/XP. -	 */ - -	len = sizeof(WCHAR) * (wcslen((CONST WCHAR *) clientData) + 1); -    } else { -	/* -	 * ANSI representation when running on 95/98/ME. -	 */ +    len = sizeof(TCHAR) * (_tcslen((const TCHAR *) clientData) + 1); -	len = sizeof(char) * (strlen((CONST char *) clientData) + 1); -    } - -    copy = (char *) ckalloc(len); -    memcpy((VOID *) copy, (VOID *) clientData, len); -    return (ClientData) copy; +    copy = ckalloc(len); +    memcpy(copy, clientData, len); +    return copy;  }  /* @@ -3362,17 +3055,17 @@ TclpUtime(  {      int res = 0;      HANDLE fileHandle; -    CONST TCHAR *native; +    const TCHAR *native;      DWORD attr = 0;      DWORD flags = FILE_ATTRIBUTE_NORMAL;      FILETIME lastAccessTime, lastModTime;      FromCTime(tval->actime, &lastAccessTime);      FromCTime(tval->modtime, &lastModTime); -     -    native = (CONST TCHAR *)Tcl_FSGetNativePath(pathPtr); -    attr = (*tclWinProcs->getFileAttributesProc)(native); +    native = Tcl_FSGetNativePath(pathPtr); + +    attr = GetFileAttributes(native);      if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY) {  	flags = FILE_FLAG_BACKUP_SEMANTICS; @@ -3383,8 +3076,7 @@ TclpUtime(       * savings complications that utime gets wrong.       */ -    fileHandle = (tclWinProcs->createFileProc) ( -	    native, FILE_WRITE_ATTRIBUTES, 0, NULL, +    fileHandle = CreateFile(native, FILE_WRITE_ATTRIBUTES, 0, NULL,  	    OPEN_EXISTING, flags, NULL);      if (fileHandle == INVALID_HANDLE_VALUE || | 
