diff options
Diffstat (limited to 'win/tclWinFile.c')
-rw-r--r-- | win/tclWinFile.c | 2344 |
1 files changed, 1327 insertions, 1017 deletions
diff --git a/win/tclWinFile.c b/win/tclWinFile.c index d8f1f81..dc6d5a0 100644 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -1,20 +1,20 @@ -/* +/* * tclWinFile.c -- * - * This file contains temporary wrappers around UNIX file handling - * functions. These wrappers map the UNIX functions to Win32 HANDLE-style - * files, which can be manipulated through the Win32 console redirection - * interfaces. + * This file contains temporary wrappers around UNIX file handling + * functions. These wrappers map the UNIX functions to Win32 HANDLE-style + * files, which can be manipulated through the Win32 console redirection + * interfaces. * * Copyright (c) 1995-1998 Sun Microsystems, Inc. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * 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.75 2005/06/22 21:24:01 dgp Exp $ + * RCS: @(#) $Id: tclWinFile.c,v 1.76 2005/07/24 22:56:47 dkf Exp $ */ -//#define _WIN32_WINNT 0x0500 +//#define _WIN32_WINNT 0x0500 #include "tclWinInt.h" #include "tclFileSystem.h" @@ -24,239 +24,276 @@ #include <lmaccess.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). + * 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 116444736000000000 +#define POSIX_EPOCH_AS_FILETIME 116444736000000000 /* - * Declarations for 'link' related information. This information - * should come with VC++ 6.0, but is not in some older SDKs. - * In any case it is not well documented. + * Declarations for 'link' related information. This information should come + * with VC++ 6.0, but is not in some older SDKs. In any case it is not well + * documented. */ + #ifndef IO_REPARSE_TAG_RESERVED_ONE -# define IO_REPARSE_TAG_RESERVED_ONE 0x000000001 +# define IO_REPARSE_TAG_RESERVED_ONE 0x000000001 #endif #ifndef IO_REPARSE_TAG_RESERVED_RANGE -# define IO_REPARSE_TAG_RESERVED_RANGE 0x000000001 +# define IO_REPARSE_TAG_RESERVED_RANGE 0x000000001 #endif #ifndef IO_REPARSE_TAG_VALID_VALUES -# define IO_REPARSE_TAG_VALID_VALUES 0x0E000FFFF +# define IO_REPARSE_TAG_VALID_VALUES 0x0E000FFFF #endif #ifndef IO_REPARSE_TAG_HSM -# define IO_REPARSE_TAG_HSM 0x0C0000004 +# define IO_REPARSE_TAG_HSM 0x0C0000004 #endif #ifndef IO_REPARSE_TAG_NSS -# define IO_REPARSE_TAG_NSS 0x080000005 +# define IO_REPARSE_TAG_NSS 0x080000005 #endif #ifndef IO_REPARSE_TAG_NSSRECOVER -# define IO_REPARSE_TAG_NSSRECOVER 0x080000006 +# define IO_REPARSE_TAG_NSSRECOVER 0x080000006 #endif #ifndef IO_REPARSE_TAG_SIS -# define IO_REPARSE_TAG_SIS 0x080000007 +# define IO_REPARSE_TAG_SIS 0x080000007 #endif #ifndef IO_REPARSE_TAG_DFS -# define IO_REPARSE_TAG_DFS 0x080000008 +# define IO_REPARSE_TAG_DFS 0x080000008 #endif #ifndef IO_REPARSE_TAG_RESERVED_ZERO -# define IO_REPARSE_TAG_RESERVED_ZERO 0x00000000 +# define IO_REPARSE_TAG_RESERVED_ZERO 0x00000000 #endif #ifndef FILE_FLAG_OPEN_REPARSE_POINT -# define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000 +# define FILE_FLAG_OPEN_REPARSE_POINT 0x00200000 #endif #ifndef IO_REPARSE_TAG_MOUNT_POINT -# define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 +# define IO_REPARSE_TAG_MOUNT_POINT 0xA0000003 #endif #ifndef IsReparseTagValid -# define IsReparseTagValid(x) (!((x)&~IO_REPARSE_TAG_VALID_VALUES)&&((x)>IO_REPARSE_TAG_RESERVED_RANGE)) +# define IsReparseTagValid(x) \ + (!((x)&~IO_REPARSE_TAG_VALID_VALUES)&&((x)>IO_REPARSE_TAG_RESERVED_RANGE)) #endif #ifndef IO_REPARSE_TAG_SYMBOLIC_LINK -# define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO +# define IO_REPARSE_TAG_SYMBOLIC_LINK IO_REPARSE_TAG_RESERVED_ZERO #endif #ifndef FILE_SPECIAL_ACCESS -# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) +# define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS) #endif #ifndef FSCTL_SET_REPARSE_POINT -# define FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) -# define FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) -# define FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) +# define FSCTL_SET_REPARSE_POINT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) +# define FSCTL_GET_REPARSE_POINT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) +# define FSCTL_DELETE_REPARSE_POINT \ + CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) #endif -/* - * Maximum reparse buffer info size. The max user defined reparse - * data is 16KB, plus there's a header. +/* + * Maximum reparse buffer info size. The max user defined reparse data is + * 16KB, plus there's a header. */ -#define MAX_REPARSE_SIZE 17000 +#define MAX_REPARSE_SIZE 17000 /* - * Undocumented REPARSE_MOUNTPOINT_HEADER_SIZE structure definition. - * This is found in winnt.h. - * - * IMPORTANT: caution when using this structure, since the actual - * structures used will want to store a full path in the 'PathBuffer' - * field, but there isn't room (there's only a single WCHAR!). Therefore - * one must artificially create a larger space of memory and then cast it - * to this type. We use the 'DUMMY_REPARSE_BUFFER' struct just below to - * deal with this problem. + * Undocumented REPARSE_MOUNTPOINT_HEADER_SIZE structure definition. This is + * found in winnt.h. + * + * IMPORTANT: caution when using this structure, since the actual structures + * used will want to store a full path in the 'PathBuffer' field, but there + * isn't room (there's only a single WCHAR!). Therefore one must artificially + * create a larger space of memory and then cast it to this type. We use the + * 'DUMMY_REPARSE_BUFFER' struct just below to deal with this problem. */ -#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 +#define REPARSE_MOUNTPOINT_HEADER_SIZE 8 #ifndef REPARSE_DATA_BUFFER_HEADER_SIZE typedef struct _REPARSE_DATA_BUFFER { - DWORD ReparseTag; - WORD ReparseDataLength; - WORD Reserved; + DWORD ReparseTag; + WORD ReparseDataLength; + WORD Reserved; union { - struct { - WORD SubstituteNameOffset; - WORD SubstituteNameLength; - WORD PrintNameOffset; - WORD PrintNameLength; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - struct { - WORD SubstituteNameOffset; - WORD SubstituteNameLength; - WORD PrintNameOffset; - WORD PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - struct { - BYTE DataBuffer[1]; - } GenericReparseBuffer; + struct { + WORD SubstituteNameOffset; + WORD SubstituteNameLength; + WORD PrintNameOffset; + WORD PrintNameLength; + WCHAR PathBuffer[1]; + } SymbolicLinkReparseBuffer; + struct { + WORD SubstituteNameOffset; + WORD SubstituteNameLength; + WORD PrintNameOffset; + WORD PrintNameLength; + WCHAR PathBuffer[1]; + } MountPointReparseBuffer; + struct { + BYTE DataBuffer[1]; + } GenericReparseBuffer; }; } REPARSE_DATA_BUFFER; #endif 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 +#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 +#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 + FindExInfoStandard, + FindExInfoMaxInfoLevel } FINDEX_INFO_LEVELS; typedef enum _FINDEX_SEARCH_OPS { - FindExSearchNameMatch, - FindExSearchLimitToDirectories, - FindExSearchLimitToDevices, - FindExSearchMaxSearchOp + FindExSearchNameMatch, + FindExSearchLimitToDirectories, + FindExSearchLimitToDevices, + FindExSearchMaxSearchOp } FINDEX_SEARCH_OPS; #endif /* HAVE_NO_FINDEX_ENUMS */ -/* Other typedefs required by this code */ +/* + * Other typedefs required by this code. + */ static time_t ToCTime(FILETIME fileTime); -static void FromCTime( time_t posixTime, - 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 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 NETAPIBUFFERFREEPROC(LPVOID Buffer); -typedef NET_API_STATUS NET_API_FUNCTION NETGETDCNAMEPROC - (LPWSTR servername, LPWSTR domainname, LPBYTE *bufptr); +typedef NET_API_STATUS NET_API_FUNCTION NETGETDCNAMEPROC( + LPWSTR servername, LPWSTR domainname, LPBYTE *bufptr); /* - * Declarations for local procedures defined in this file: + * Declarations for local functions defined in this file: */ -static int NativeAccess(CONST TCHAR *path, int mode); -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 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); +static int NativeAccess(CONST TCHAR *path, int mode); +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 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); /* *-------------------------------------------------------------------- * - * WinLink + * WinLink -- + * + * Make a link from source to target. * - * Make a link from source to target. *-------------------------------------------------------------------- */ -static int + +static int WinLink(LinkSource, LinkTarget, linkAction) - CONST TCHAR* LinkSource; - CONST TCHAR* LinkTarget; + CONST TCHAR *LinkSource; + CONST TCHAR *LinkTarget; int linkAction; { - WCHAR tempFileName[MAX_PATH]; - TCHAR* tempFilePart; - int attr; - - /* Get the full path referenced by the target */ - if (!(*tclWinProcs->getFullPathNameProc)(LinkTarget, - MAX_PATH, tempFileName, &tempFilePart)) { - /* Invalid file */ + WCHAR tempFileName[MAX_PATH]; + TCHAR *tempFilePart; + int attr; + + /* + * Get the full path referenced by the target. + */ + + if (!(*tclWinProcs->getFullPathNameProc)(LinkTarget, MAX_PATH, + tempFileName, &tempFilePart)) { + /* + * Invalid file. + */ TclWinConvertError(GetLastError()); return -1; } - /* Make sure source file doesn't exist */ + /* + * Make sure source file doesn't exist. + */ + attr = (*tclWinProcs->getFileAttributesProc)(LinkSource); if (attr != 0xffffffff) { Tcl_SetErrno(EEXIST); return -1; } - /* Get the full path referenced by the source file/directory */ - if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, - MAX_PATH, tempFileName, &tempFilePart)) { - /* Invalid file */ + /* + * Get the full path referenced by the source file/directory. + */ + + if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, MAX_PATH, + tempFileName, &tempFilePart)) { + /* + * Invalid file. + */ + TclWinConvertError(GetLastError()); return -1; } - /* Check the target */ + + /* + * Check the target. + */ + attr = (*tclWinProcs->getFileAttributesProc)(LinkTarget); if (attr == 0xffffffff) { - /* The target doesn't exist */ + /* + * The target doesn't exist. + */ + TclWinConvertError(GetLastError()); return -1; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { - /* It is a file */ + /* + * It is a file. + */ + if (tclWinProcs->createHardLinkProc == NULL) { Tcl_SetErrno(ENOTDIR); return -1; } + if (linkAction & TCL_CREATE_HARD_LINK) { - if (!(*tclWinProcs->createHardLinkProc)(LinkSource, LinkTarget, NULL)) { + if (!(*tclWinProcs->createHardLinkProc)(LinkSource, LinkTarget, + NULL)) { TclWinConvertError(GetLastError()); return -1; } return 0; + } else if (linkAction & TCL_CREATE_SYMBOLIC_LINK) { - /* Can't symlink files */ + /* + * Can't symlink files. + */ + Tcl_SetErrno(ENOTDIR); return -1; } else { @@ -266,8 +303,12 @@ WinLink(LinkSource, LinkTarget, linkAction) } else { if (linkAction & TCL_CREATE_SYMBOLIC_LINK) { return WinSymLinkDirectory(LinkSource, LinkTarget); + } else if (linkAction & TCL_CREATE_HARD_LINK) { - /* Can't hard link directories */ + /* + * Can't hard link directories. + */ + Tcl_SetErrno(EISDIR); return -1; } else { @@ -280,35 +321,53 @@ WinLink(LinkSource, LinkTarget, linkAction) /* *-------------------------------------------------------------------- * - * WinReadLink + * WinReadLink -- + * + * What does 'LinkSource' point to? * - * What does 'LinkSource' point to? *-------------------------------------------------------------------- */ -static Tcl_Obj* + +static Tcl_Obj* WinReadLink(LinkSource) - CONST TCHAR* LinkSource; + CONST TCHAR *LinkSource; { - WCHAR tempFileName[MAX_PATH]; - TCHAR* tempFilePart; - int attr; - - /* Get the full path referenced by the target */ - if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, - MAX_PATH, tempFileName, &tempFilePart)) { - /* Invalid file */ + WCHAR tempFileName[MAX_PATH]; + TCHAR *tempFilePart; + int attr; + + /* + * Get the full path referenced by the target. + */ + + if (!(*tclWinProcs->getFullPathNameProc)(LinkSource, MAX_PATH, + tempFileName, &tempFilePart)) { + /* + * Invalid file. + */ + TclWinConvertError(GetLastError()); return NULL; } - /* Make sure source file does exist */ + /* + * Make sure source file does exist. + */ + attr = (*tclWinProcs->getFileAttributesProc)(LinkSource); if (attr == 0xffffffff) { - /* The source doesn't exist */ + /* + * The source doesn't exist. + */ + TclWinConvertError(GetLastError()); return NULL; + } else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) { - /* It is a file - this is not yet supported */ + /* + * It is a file - this is not yet supported. + */ + Tcl_SetErrno(ENOTDIR); return NULL; } else { @@ -319,84 +378,98 @@ WinReadLink(LinkSource) /* *-------------------------------------------------------------------- * - * WinSymLinkDirectory + * WinSymLinkDirectory -- + * + * This routine creates a NTFS junction, using the undocumented + * FSCTL_SET_REPARSE_POINT structure Win2K uses for mount points and + * junctions. + * + * Assumption that LinkTarget is a valid, existing directory. * - * This routine creates a NTFS junction, using the undocumented - * FSCTL_SET_REPARSE_POINT structure Win2K uses for mount points - * and junctions. + * Returns: + * Zero on success. * - * Assumption that LinkTarget is a valid, existing directory. - * - * Returns zero on success. *-------------------------------------------------------------------- */ -static int + +static int WinSymLinkDirectory(LinkDirectory, LinkTarget) - CONST TCHAR* LinkDirectory; - CONST TCHAR* LinkTarget; + CONST TCHAR *LinkDirectory; + CONST TCHAR *LinkTarget; { DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; - int len; - WCHAR nativeTarget[MAX_PATH]; - WCHAR *loop; - - /* Make the native target name */ + int len; + WCHAR nativeTarget[MAX_PATH]; + WCHAR *loop; + + /* + * Make the native target name. + */ + memcpy((VOID*)nativeTarget, (VOID*)L"\\??\\", 4*sizeof(WCHAR)); - memcpy((VOID*)(nativeTarget + 4), (VOID*)LinkTarget, + memcpy((VOID*)(nativeTarget + 4), (VOID*)LinkTarget, sizeof(WCHAR)*(1+wcslen((WCHAR*)LinkTarget))); len = wcslen(nativeTarget); - /* - * We must have backslashes only. This is VERY IMPORTANT. - * If we have any forward slashes everything appears to work, - * but the resulting symlink is useless! + + /* + * We must have backslashes only. This is VERY IMPORTANT. If we have any + * forward slashes everything appears to work, but the resulting symlink + * is useless! */ + for (loop = nativeTarget; *loop != 0; loop++) { if (*loop == L'/') *loop = L'\\'; } if ((nativeTarget[len-1] == L'\\') && (nativeTarget[len-2] != L':')) { nativeTarget[len-1] = 0; } - - /* Build the reparse info */ + + /* + * Build the reparse info. + */ + memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER)); reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; - reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = - wcslen(nativeTarget) * sizeof(WCHAR); + reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength = + wcslen(nativeTarget) * sizeof(WCHAR); reparseBuffer->Reserved = 0; reparseBuffer->SymbolicLinkReparseBuffer.PrintNameLength = 0; - reparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = - reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength - + sizeof(WCHAR); - memcpy(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, nativeTarget, - sizeof(WCHAR) - + reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength); - reparseBuffer->ReparseDataLength = - reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + 12; - + reparseBuffer->SymbolicLinkReparseBuffer.PrintNameOffset = + reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + + sizeof(WCHAR); + memcpy(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, nativeTarget, + sizeof(WCHAR) + + reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength); + reparseBuffer->ReparseDataLength = + reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength + 12; + return NativeWriteReparse(LinkDirectory, reparseBuffer); } /* *-------------------------------------------------------------------- * - * TclWinSymLinkCopyDirectory + * TclWinSymLinkCopyDirectory -- + * + * Copy a Windows NTFS junction. This function assumes that LinkOriginal + * exists and is a valid junction point, and that LinkCopy does not + * exist. + * + * Returns: + * Zero on success. * - * Copy a Windows NTFS junction. This function assumes that - * LinkOriginal exists and is a valid junction point, and that - * LinkCopy does not exist. - * - * Returns zero on success. *-------------------------------------------------------------------- */ -int + +int TclWinSymLinkCopyDirectory(LinkOriginal, LinkCopy) - CONST TCHAR* LinkOriginal; /* Existing junction - reparse point */ - CONST TCHAR* LinkCopy; /* Will become a duplicate junction */ + CONST TCHAR *LinkOriginal; /* Existing junction - reparse point */ + CONST TCHAR *LinkCopy; /* Will become a duplicate junction */ { DUMMY_REPARSE_BUFFER dummy; - REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; - + REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy; + if (NativeReadReparse(LinkOriginal, reparseBuffer)) { return -1; } @@ -406,43 +479,53 @@ TclWinSymLinkCopyDirectory(LinkOriginal, LinkCopy) /* *-------------------------------------------------------------------- * - * TclWinSymLinkDelete + * TclWinSymLinkDelete -- + * + * Delete a Windows NTFS junction. Once the junction information is + * deleted, the filesystem object becomes an ordinary directory. Unless + * 'linkOnly' is given, that directory is also removed. + * + * Assumption that LinkOriginal is a valid, existing junction. + * + * Returns: + * Zero on success. * - * Delete a Windows NTFS junction. Once the junction information - * is deleted, the filesystem object becomes an ordinary directory. - * Unless 'linkOnly' is given, that directory is also removed. - * - * Assumption that LinkOriginal is a valid, existing junction. - * - * Returns zero on success. *-------------------------------------------------------------------- */ -int + +int TclWinSymLinkDelete(LinkOriginal, linkOnly) - CONST TCHAR* LinkOriginal; + CONST TCHAR *LinkOriginal; int linkOnly; { - /* It is a symbolic link -- remove it */ + /* + * It is a symbolic link - remove it. + */ + DUMMY_REPARSE_BUFFER dummy; - REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; + REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy; HANDLE hFile; DWORD returnedLength; + memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER)); reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; hFile = (*tclWinProcs->createFileProc)(LinkOriginal, GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); + 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, - REPARSE_MOUNTPOINT_HEADER_SIZE, - NULL, 0, &returnedLength, NULL)) { - /* Error setting junction */ + if (!DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, reparseBuffer, + REPARSE_MOUNTPOINT_HEADER_SIZE,NULL,0,&returnedLength,NULL)) { + /* + * Error setting junction. + */ + TclWinConvertError(GetLastError()); CloseHandle(hFile); } else { CloseHandle(hFile); if (!linkOnly) { - (*tclWinProcs->removeDirectoryProc)(LinkOriginal); + (*tclWinProcs->removeDirectoryProc)(LinkOriginal); } return 0; } @@ -453,167 +536,196 @@ TclWinSymLinkDelete(LinkOriginal, linkOnly) /* *-------------------------------------------------------------------- * - * WinReadLinkDirectory + * WinReadLinkDirectory -- * - * This routine reads a NTFS junction, using the undocumented - * FSCTL_GET_REPARSE_POINT structure Win2K uses for mount points - * and junctions. + * This routine reads a NTFS junction, using the undocumented + * FSCTL_GET_REPARSE_POINT structure Win2K uses for mount points and + * junctions. + * + * Assumption that LinkDirectory is a valid, existing directory. + * + * Returns: + * A Tcl_Obj with refCount of 1 (i.e. owned by the caller), or NULL if + * anything went wrong. + * + * In the future we should enhance this to return a path object rather + * than a string. * - * Assumption that LinkDirectory is a valid, existing directory. - * - * Returns a Tcl_Obj with refCount of 1 (i.e. owned by the caller), - * or NULL if anything went wrong. - * - * In the future we should enhance this to return a path object - * rather than a string. *-------------------------------------------------------------------- */ -static Tcl_Obj* + +static Tcl_Obj* WinReadLinkDirectory(LinkDirectory) - CONST TCHAR* LinkDirectory; + CONST TCHAR *LinkDirectory; { int attr; DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy; - + attr = (*tclWinProcs->getFileAttributesProc)(LinkDirectory); if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) { Tcl_SetErrno(EINVAL); return NULL; } if (NativeReadReparse(LinkDirectory, reparseBuffer)) { - return NULL; + return NULL; } - + switch (reparseBuffer->ReparseTag) { - case 0x80000000|IO_REPARSE_TAG_SYMBOLIC_LINK: - case IO_REPARSE_TAG_SYMBOLIC_LINK: - case IO_REPARSE_TAG_MOUNT_POINT: { - Tcl_Obj *retVal; - Tcl_DString ds; - CONST char *copy; - int len; - int offset = 0; - - /* - * Certain native path representations on Windows have a - * special prefix to indicate that they are to be treated - * specially. For example extremely long paths, or symlinks, - * or volumes mounted inside directories. - * - * There is an assumption in this code that 'wide' interfaces - * are being used (see tclWin32Dll.c), which is true for the - * only systems which support reparse tags at present. If - * that changes in the future, this code will have to be - * generalised. + case 0x80000000|IO_REPARSE_TAG_SYMBOLIC_LINK: + case IO_REPARSE_TAG_SYMBOLIC_LINK: + case IO_REPARSE_TAG_MOUNT_POINT: { + Tcl_Obj *retVal; + Tcl_DString ds; + CONST char *copy; + int len; + int offset = 0; + + /* + * Certain native path representations on Windows have a special + * prefix to indicate that they are to be treated specially. For + * example extremely long paths, or symlinks, or volumes mounted + * inside directories. + * + * There is an assumption in this code that 'wide' interfaces are + * being used (see tclWin32Dll.c), which is true for the only systems + * which support reparse tags at present. If that changes in the + * future, this code will have to be generalised. + */ + + if (reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer[0] == L'\\') { + /* + * Check whether this is a mounted volume. */ - if (reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer[0] - == L'\\') { - /* Check whether this is a mounted volume */ - if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, - L"\\??\\Volume{",11) == 0) { - char drive; - /* - * There is some confusion between \??\ and \\?\ which - * we have to fix here. It doesn't seem very well - * documented. - */ - reparseBuffer->SymbolicLinkReparseBuffer - .PathBuffer[1] = L'\\'; - /* - * Check if a corresponding drive letter exists, and - * use that if it is found - */ - drive = TclWinDriveLetterForVolMountPoint(reparseBuffer - ->SymbolicLinkReparseBuffer.PathBuffer); - if (drive != -1) { - char driveSpec[3] = { - '\0', ':', '\0' - }; - driveSpec[0] = drive; - retVal = Tcl_NewStringObj(driveSpec,2); - Tcl_IncrRefCount(retVal); - return retVal; - } - /* - * This is actually a mounted drive, which doesn't - * exists as a DOS drive letter. This means the path - * isn't actually a link, although we partially treat - * it like one ('file type' will return 'link'), but - * then the link will actually just be treated like - * an ordinary directory. I don't believe any - * serious inconsistency will arise from this, but it - * is something to be aware of. - */ - Tcl_SetErrno(EINVAL); - return NULL; - } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer - .PathBuffer, L"\\\\?\\",4) == 0) { - /* Strip off the prefix */ - offset = 4; - } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer - .PathBuffer, L"\\??\\",4) == 0) { - /* Strip off the prefix */ - offset = 4; + + if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, + L"\\??\\Volume{",11) == 0) { + char drive; + + /* + * There is some confusion between \??\ and \\?\ which we have + * to fix here. It doesn't seem very well documented. + */ + + reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer[1] = L'\\'; + + /* + * Check if a corresponding drive letter exists, and use that + * if it is found + */ + + drive = TclWinDriveLetterForVolMountPoint( + reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer); + if (drive != -1) { + char driveSpec[3] = { + '\0', ':', '\0' + }; + + driveSpec[0] = drive; + retVal = Tcl_NewStringObj(driveSpec,2); + Tcl_IncrRefCount(retVal); + return retVal; } + + /* + * This is actually a mounted drive, which doesn't exists as a + * DOS drive letter. This means the path isn't actually a + * link, although we partially treat it like one ('file type' + * will return 'link'), but then the link will actually just + * be treated like an ordinary directory. I don't believe any + * serious inconsistency will arise from this, but it is + * something to be aware of. + */ + + Tcl_SetErrno(EINVAL); + return NULL; + + } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer + .PathBuffer, L"\\\\?\\",4) == 0) { + /* + * Strip off the prefix. + */ + + offset = 4; + } else if (wcsncmp(reparseBuffer->SymbolicLinkReparseBuffer + .PathBuffer, L"\\??\\",4) == 0) { + /* + * Strip off the prefix. + */ + offset = 4; } - - Tcl_WinTCharToUtf( - (CONST char*)reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, - (int)reparseBuffer->SymbolicLinkReparseBuffer - .SubstituteNameLength, &ds); - - copy = Tcl_DStringValue(&ds)+offset; - len = Tcl_DStringLength(&ds)-offset; - retVal = Tcl_NewStringObj(copy,len); - Tcl_IncrRefCount(retVal); - Tcl_DStringFree(&ds); - return retVal; } + + Tcl_WinTCharToUtf((CONST char*) + reparseBuffer->SymbolicLinkReparseBuffer.PathBuffer, + (int) reparseBuffer->SymbolicLinkReparseBuffer + .SubstituteNameLength, &ds); + + copy = Tcl_DStringValue(&ds)+offset; + len = Tcl_DStringLength(&ds)-offset; + retVal = Tcl_NewStringObj(copy,len); + Tcl_IncrRefCount(retVal); + Tcl_DStringFree(&ds); + return retVal; + } + default: + Tcl_SetErrno(EINVAL); + return NULL; } - Tcl_SetErrno(EINVAL); - return NULL; } /* *-------------------------------------------------------------------- * - * NativeReadReparse + * NativeReadReparse -- + * + * Read the junction/reparse information from a given NTFS directory. + * + * Assumption that LinkDirectory is a valid, existing directory. * - * Read the junction/reparse information from a given NTFS directory. + * Returns: + * Zero on success. * - * Assumption that LinkDirectory is a valid, existing directory. - * - * Returns zero on success. *-------------------------------------------------------------------- */ -static int + +static int NativeReadReparse(LinkDirectory, buffer) - CONST TCHAR* LinkDirectory; /* The junction to read */ - REPARSE_DATA_BUFFER* buffer; /* Pointer to buffer. Cannot be NULL */ + CONST TCHAR *LinkDirectory; /* The junction to read */ + REPARSE_DATA_BUFFER *buffer;/* Pointer to buffer. Cannot be NULL */ { HANDLE hFile; DWORD returnedLength; - + hFile = (*tclWinProcs->createFileProc)(LinkDirectory, GENERIC_READ, 0, - NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); + NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); + if (hFile == INVALID_HANDLE_VALUE) { - /* Error creating directory */ + /* + * Error creating directory. + */ + TclWinConvertError(GetLastError()); return -1; } - /* Get the link */ - if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, - 0, buffer, sizeof(DUMMY_REPARSE_BUFFER), - &returnedLength, NULL)) { - /* Error setting junction */ + + /* + * Get the link. + */ + + if (!DeviceIoControl(hFile, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer, + sizeof(DUMMY_REPARSE_BUFFER), &returnedLength, NULL)) { + /* + * Error setting junction. + */ + TclWinConvertError(GetLastError()); CloseHandle(hFile); return -1; } CloseHandle(hFile); - + if (!IsReparseTagValid(buffer->ReparseTag)) { Tcl_SetErrno(EINVAL); return -1; @@ -624,48 +736,69 @@ NativeReadReparse(LinkDirectory, buffer) /* *-------------------------------------------------------------------- * - * NativeWriteReparse + * NativeWriteReparse -- + * + * Write the reparse information for a given directory. + * + * Assumption that LinkDirectory does not exist. * - * Write the reparse information for a given directory. - * - * Assumption that LinkDirectory does not exist. *-------------------------------------------------------------------- */ -static int + +static int NativeWriteReparse(LinkDirectory, buffer) - CONST TCHAR* LinkDirectory; + CONST TCHAR *LinkDirectory; REPARSE_DATA_BUFFER* buffer; { HANDLE hFile; DWORD returnedLength; - - /* Create the directory - it must not already exist */ + + /* + * Create the directory - it must not already exist. + */ + if ((*tclWinProcs->createDirectoryProc)(LinkDirectory, NULL) == 0) { - /* Error creating directory */ + /* + * Error creating directory. + */ + TclWinConvertError(GetLastError()); return -1; } + hFile = (*tclWinProcs->createFileProc)(LinkDirectory, GENERIC_WRITE, 0, - NULL, OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); + NULL, OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) { - /* Error creating directory */ + /* + * Error creating directory. + */ TclWinConvertError(GetLastError()); return -1; } - /* Set the link */ - if (!DeviceIoControl(hFile, FSCTL_SET_REPARSE_POINT, buffer, - (DWORD) buffer->ReparseDataLength - + REPARSE_MOUNTPOINT_HEADER_SIZE, - NULL, 0, &returnedLength, NULL)) { - /* Error setting junction */ + + /* + * Set the link. + */ + + if (!DeviceIoControl(hFile, FSCTL_SET_REPARSE_POINT, buffer, + (DWORD) buffer->ReparseDataLength + REPARSE_MOUNTPOINT_HEADER_SIZE, + NULL, 0, &returnedLength, NULL)) { + /* + * Error setting junction. + */ + TclWinConvertError(GetLastError()); CloseHandle(hFile); (*tclWinProcs->removeDirectoryProc)(LinkDirectory); return -1; } CloseHandle(hFile); - /* We succeeded */ + + /* + * We succeeded. + */ + return 0; } @@ -674,11 +807,11 @@ NativeWriteReparse(LinkDirectory, buffer) * * TclpFindExecutable -- * - * This procedure computes the absolute path name of the current + * This function computes the absolute path name of the current * application. * * Results: - * None. + * None. * * Side effects: * The computed path is stored. @@ -701,11 +834,14 @@ TclpFindExecutable(argv0) if (GetModuleFileNameW(NULL, wName, MAX_PATH) == 0) { GetModuleFileNameA(NULL, name, sizeof(name)); + /* * Convert to WCHAR to get out of ANSI codepage */ + MultiByteToWideChar(CP_ACP, 0, name, -1, wName, MAX_PATH); } + WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL, NULL); TclWinNoBackslash(name); TclSetObjNameOfExecutable(Tcl_NewStringObj(name, -1), NULL); @@ -716,25 +852,25 @@ TclpFindExecutable(argv0) * * TclpMatchInDirectory -- * - * This routine is used by the globbing code to search a - * directory for all files which match a given pattern. + * This routine is used by the globbing code to search a directory for + * all files which match a given pattern. * - * Results: - * - * The return value is a standard Tcl result indicating whether an - * error occurred in globbing. Errors are left in interp, good - * results are lappended to resultPtr (which must be a valid object) + * Results: + * The return value is a standard Tcl result indicating whether an error + * occurred in globbing. Errors are left in interp, good results are + * lappended to resultPtr (which must be a valid object). * * Side effects: * None. * - *---------------------------------------------------------------------- */ + *---------------------------------------------------------------------- + */ int TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) Tcl_Interp *interp; /* Interpreter to receive errors. */ Tcl_Obj *resultPtr; /* List object to lappend results. */ - Tcl_Obj *pathPtr; /* Contains path to directory to search. */ + Tcl_Obj *pathPtr; /* Contains path to directory to search. */ CONST char *pattern; /* Pattern to match against. */ Tcl_GlobTypeData *types; /* Object containing list of acceptable types. * May be NULL. In particular the directory @@ -743,20 +879,26 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) CONST TCHAR *native; if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) { - /* The native filesystem never adds mounts */ + /* + * The native filesystem never adds mounts. + */ + return TCL_OK; } if (pattern == NULL || (*pattern == '\0')) { Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr); if (norm != NULL) { - /* Match a single file directly */ + /* + * Match a single file directly. + */ + int len; DWORD attr; CONST char *str = Tcl_GetStringFromObj(norm,&len); - native = (CONST TCHAR*) Tcl_FSGetNativePath(pathPtr); - + native = (CONST TCHAR *) Tcl_FSGetNativePath(pathPtr); + if (tclWinProcs->getFileAttributesExProc == NULL) { attr = (*tclWinProcs->getFileAttributesProc)(native); if (attr == 0xffffffff) { @@ -770,8 +912,8 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) } attr = data.dwFileAttributes; } - if (NativeMatchType(WinIsDrive(str,len), attr, - native, types)) { + + if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) { Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); } } @@ -780,19 +922,19 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) DWORD attr; HANDLE handle; WIN32_FIND_DATAT data; - CONST char *dirName; /* utf-8 dir name, later - * with pattern appended */ + CONST char *dirName; /* UTF-8 dir name, later with pattern + * appended. */ int dirLength; int matchSpecialDots; - Tcl_DString ds; /* native encoding of dir, also used - * temporarily for other things. */ - Tcl_DString dsOrig; /* utf-8 encoding of dir */ + Tcl_DString ds; /* Native encoding of dir, also used + * temporarily for other things. */ + Tcl_DString dsOrig; /* UTF-8 encoding of dir. */ Tcl_Obj *fileNamePtr; char lastChar; /* - * Get the normalized path representation - * (the main thing is we dont want any '~' sequences). + * Get the normalized path representation (the main thing is we dont + * want any '~' sequences). */ fileNamePtr = Tcl_FSGetNormalizedPath(interp, pathPtr); @@ -801,9 +943,9 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) } /* - * Verify that the specified path exists and - * is actually a directory. + * Verify that the specified path exists and is actually a directory. */ + native = Tcl_FSGetNativePath(pathPtr); if (native == NULL) { return TCL_OK; @@ -814,15 +956,15 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) return TCL_OK; } - /* - * Build up the directory name for searching, including - * a trailing directory separator. + /* + * Build up the directory name for searching, including a trailing + * directory separator. */ Tcl_DStringInit(&dsOrig); dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength); Tcl_DStringAppend(&dsOrig, dirName, dirLength); - + lastChar = dirName[dirLength -1]; if ((lastChar != '\\') && (lastChar != '/') && (lastChar != ':')) { Tcl_DStringAppend(&dsOrig, "/", 1); @@ -831,68 +973,74 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) dirName = Tcl_DStringValue(&dsOrig); /* - * We need to check all files in the directory, so we append - * '*.*' to the path, unless the pattern we've been given is - * rather simple, when we can use that instead. + * We need to check all files in the directory, so we append '*.*' to + * the path, unless the pattern we've been given is rather simple, + * when we can use that instead. */ if (strpbrk(pattern, "[]\\") == NULL) { - /* + /* * The pattern is a simple one containing just '*' and/or '?'. - * This means we can get the OS to help us, by passing - * it the pattern. + * This means we can get the OS to help us, by passing it the + * pattern. */ + dirName = Tcl_DStringAppend(&dsOrig, pattern, -1); } else { dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3); } + native = Tcl_WinUtfToTChar(dirName, -1, &ds); - if (tclWinProcs->findFirstFileExProc == NULL - || (types == NULL) - || (types->type != TCL_GLOB_TYPE_DIR)) { + if (tclWinProcs->findFirstFileExProc == NULL || (types == NULL) + || (types->type != TCL_GLOB_TYPE_DIR)) { handle = (*tclWinProcs->findFirstFileProc)(native, &data); } else { - /* We can be more efficient, for pure directory requests */ - handle = (*tclWinProcs->findFirstFileExProc)(native, - FindExInfoStandard, &data, - FindExSearchLimitToDirectories, NULL, 0); + /* + * We can be more efficient, for pure directory requests. + */ + + handle = (*tclWinProcs->findFirstFileExProc)(native, + FindExInfoStandard, &data, + FindExSearchLimitToDirectories, NULL, 0); } if (handle == INVALID_HANDLE_VALUE) { DWORD err = GetLastError(); Tcl_DStringFree(&ds); if (err == ERROR_FILE_NOT_FOUND) { - /* - * We used our 'pattern' above, and matched nothing - * This means we just return TCL_OK, indicating - * no results found. - */ + /* + * We used our 'pattern' above, and matched nothing. This + * means we just return TCL_OK, indicating no results found. + */ + Tcl_DStringFree(&dsOrig); return TCL_OK; } + TclWinConvertError(err); Tcl_ResetResult(interp); Tcl_AppendResult(interp, "couldn't read directory \"", - Tcl_DStringValue(&dsOrig), "\": ", + Tcl_DStringValue(&dsOrig), "\": ", Tcl_PosixError(interp), (char *) NULL); Tcl_DStringFree(&dsOrig); return TCL_ERROR; } Tcl_DStringFree(&ds); - /* - * We may use this later, so we must restore it to its - * length including the directory delimiter + /* + * We may use this later, so we must restore it to its length + * including the directory delimiter. */ + Tcl_DStringSetLength(&dsOrig, dirLength); /* - * Check to see if the pattern should match the special - * . and .. names, referring to the current directory, - * or the directory above. We need a special check for - * this because paths beginning with a dot are not considered - * hidden on Windows, and so otherwise a relative glob like - * 'glob -join * *' will actually return './. ../..' etc. + * Check to see if the pattern should match the special . and + * .. names, referring to the current directory, or the directory + * above. We need a special check for this because paths beginning + * with a dot are not considered hidden on Windows, and so otherwise a + * relative glob like 'glob -join * *' will actually return + * './. ../..' etc. */ if ((pattern[0] == '.') @@ -903,8 +1051,8 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) } /* - * Now iterate over all of the files in the directory, starting - * with the first one we found. + * Now iterate over all of the files in the directory, starting with + * the first one we found. */ do { @@ -912,7 +1060,7 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) int checkDrive = 0; int isDrive; DWORD attr; - + if (tclWinProcs->useWide) { native = (CONST TCHAR *) data.w.cFileName; attr = data.w.dwFileAttributes; @@ -920,34 +1068,37 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) native = (CONST TCHAR *) data.a.cFileName; attr = data.a.dwFileAttributes; } - + utfname = Tcl_WinTCharToUtf(native, -1, &ds); if (!matchSpecialDots) { - /* If it is exactly '.' or '..' then we ignore it */ - if ((utfname[0] == '.') && (utfname[1] == '\0' + /* + * If it is exactly '.' or '..' then we ignore it. + */ + + if ((utfname[0] == '.') && (utfname[1] == '\0' || (utfname[1] == '.' && utfname[2] == '\0'))) { Tcl_DStringFree(&ds); continue; } } else if (utfname[0] == '.' && utfname[1] == '.' && utfname[2] == '\0') { - /* - * Have to check if this is a drive below, so we can - * correctly match 'hidden' and not hidden files. + /* + * Have to check if this is a drive below, so we can correctly + * match 'hidden' and not hidden files. */ + checkDrive = 1; } - + /* - * Check to see if the file matches the pattern. Note that - * we are ignoring the case sensitivity flag because Windows - * doesn't honor case even if the volume is case sensitive. - * If the volume also doesn't preserve case, then we - * previously returned the lower case form of the name. This - * didn't seem quite right since there are - * non-case-preserving volumes that actually return mixed - * case. So now we are returning exactly what we get from + * Check to see if the file matches the pattern. Note that we are + * ignoring the case sensitivity flag because Windows doesn't + * honor case even if the volume is case sensitive. If the volume + * also doesn't preserve case, then we previously returned the + * lower case form of the name. This didn't seem quite right since + * there are non-case-preserving volumes that actually return + * mixed case. So now we are returning exactly what we get from * the system. */ @@ -966,7 +1117,7 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) isDrive = 0; } if (NativeMatchType(isDrive, attr, native, types)) { - Tcl_ListObjAppendElement(interp, resultPtr, + Tcl_ListObjAppendElement(interp, resultPtr, TclNewFSPathObj(pathPtr, utfname, Tcl_DStringLength(&ds))); } @@ -975,6 +1126,7 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) /* * Free ds here to ensure that native is valid above. */ + Tcl_DStringFree(&ds); } while ((*tclWinProcs->findNextFileProc)(handle, &data) == TRUE); @@ -984,23 +1136,27 @@ TclpMatchInDirectory(interp, resultPtr, pathPtr, pattern, types) } } -/* - * Does the given path represent a root volume? We need this special - * case because for NTFS root volumes, the getFileAttributesProc returns - * a 'hidden' attribute when it should not. +/* + * Does the given path represent a root volume? We need this special case + * because for NTFS root volumes, the getFileAttributesProc returns a 'hidden' + * attribute when it should not. */ + static int WinIsDrive( - CONST char *name, /* Name (UTF-8) */ - int len) /* Length of name */ + 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] != '\\')) { - /* We don't have '/..' at the end */ + if ((name[len-1] != '.' || name[len-2] != '.') + || (name[len-3] != '/' && name[len-3] != '\\')) { + /* + * We don't have '/..' at the end. + */ + if (remove == 0) { - break; + break; } remove--; while (len > 0) { @@ -1010,74 +1166,94 @@ WinIsDrive( } } if (len < 4) { - len++; + len++; break; } - } else { - /* We do have '/..' */ + } else { + /* + * We do have '/..' + */ + len -= 3; remove++; - } + } } + if (len < 4) { if (len == 0) { - /* - * Not sure if this is possible, but we pass it on - * anyway + /* + * Not sure if this is possible, but we pass it on anyway. */ } else if (len == 1 && (name[0] == '/' || name[0] == '\\')) { - /* Path is pointing to the root volume */ + /* + * Path is pointing to the root volume. + */ + return 1; - } else if ((name[1] == ':') + } else if ((name[1] == ':') && (len == 2 || (name[2] == '/' || name[2] == '\\'))) { - /* Path is of the form 'x:' or 'x:/' or 'x:\' */ + /* + * Path is of the form 'x:' or 'x:/' or 'x:\' + */ + return 1; } } + return 0; } -/* - * Does the given path represent a reserved window path name? If not - * return 0, if true, return the number of characters of the path that - * we actually want (not any trailing :). +/* + * Does the given path represent a reserved window path name? If not return 0, + * if true, return the number of characters of the path that we actually want + * (not any trailing :). */ + static int WinIsReserved( - CONST char *path) /* Path in UTF-8 */ + CONST char *path) /* Path in UTF-8 */ { - if ((path[0] == 'c' || path[0] == 'C') - && (path[1] == 'o' || path[1] == 'O')) { + if ((path[0] == 'c' || path[0] == 'C') + && (path[1] == 'o' || path[1] == 'O')) { if ((path[2] == 'm' || path[2] == 'M') - && path[3] >= '1' && path[3] <= '4') { - /* May have match for 'com[1-4]:?', which is a serial port */ + && path[3] >= '1' && path[3] <= '4') { + /* + * May have match for 'com[1-4]:?', which is a serial port. + */ + if (path[4] == '\0') { return 4; } else if (path [4] == ':' && path[5] == '\0') { return 4; } } else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') { - /* Have match for 'con' */ + /* + * Have match for 'con' + */ + return 3; } + } else if ((path[0] == 'l' || path[0] == 'L') - && (path[1] == 'p' || path[1] == 'P') - && (path[2] == 't' || path[2] == 'T')) { + && (path[1] == 'p' || path[1] == 'P') + && (path[2] == 't' || path[2] == 'T')) { if (path[3] >= '1' && path[3] <= '3') { - /* May have match for 'lpt[1-3]:?' */ + /* + * May have match for 'lpt[1-3]:?' + */ + if (path[4] == '\0') { return 4; } else if (path [4] == ':' && path[5] == '\0') { return 4; } } - } else if (stricmp(path, "prn") == 0) { - /* Have match for 'prn' */ - return 3; - } else if (stricmp(path, "nul") == 0) { - /* Have match for 'nul' */ - return 3; - } else if (stricmp(path, "aux") == 0) { - /* Have match for 'aux' */ + + } else if (!stricmp(path, "prn") || !stricmp(path, "nul") + || !stricmp(path, "aux")) { + /* + * Have match for 'prn', 'nul' or 'aux'. + */ + return 3; } return 0; @@ -1085,102 +1261,106 @@ static int WinIsReserved( /* *---------------------------------------------------------------------- - * + * * NativeMatchType -- - * - * This function needs a special case for a path which is a root - * volume, 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 have arranged things so that our caller already knows - * such information. - * + * + * This function needs a special case for a path which is a root volume, + * 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 + * have arranged things so that our caller already knows such + * information. + * * Results: - * 0 = file doesn't match - * 1 = file matches - * + * 0 = file doesn't match + * 1 = file matches + * *---------------------------------------------------------------------- */ -static int + +static int NativeMatchType( - int isDrive, /* Is this a drive */ - DWORD attr, /* We already know the attributes - * for the file */ - CONST TCHAR* nativeName, /* Native path to check */ - Tcl_GlobTypeData *types) /* Type description to match against */ + int isDrive, /* Is this a drive. */ + DWORD attr, /* We already know the attributes for the + * file. */ + CONST TCHAR *nativeName, /* Native path to check. */ + Tcl_GlobTypeData *types) /* Type description to match against. */ { /* - * 'attr' represents the attributes of the file, but we only - * want to retrieve this info if it is absolutely necessary - * because it is an expensive call. Unfortunately, to deal - * with hidden files properly, we must always retrieve it. + * 'attr' represents the attributes of the file, but we only want to + * retrieve this info if it is absolutely necessary because it is an + * expensive call. Unfortunately, to deal with hidden files properly, we + * must always retrieve it. */ if (types == NULL) { - /* If invisible, don't return the file */ + /* + * If invisible, don't return the file. + */ if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) { return 0; } } else { if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) { - /* If invisible */ - if ((types->perm == 0) || - !(types->perm & TCL_GLOB_PERM_HIDDEN)) { + /* + * 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 != 0) { - if ( - ((types->perm & TCL_GLOB_PERM_RONLY) && + if (((types->perm & TCL_GLOB_PERM_RONLY) && !(attr & FILE_ATTRIBUTE_READONLY)) || - ((types->perm & TCL_GLOB_PERM_R) && + ((types->perm & TCL_GLOB_PERM_R) && (0 /* File exists => R_OK on Windows */)) || - ((types->perm & TCL_GLOB_PERM_W) && + ((types->perm & TCL_GLOB_PERM_W) && (attr & FILE_ATTRIBUTE_READONLY)) || - ((types->perm & TCL_GLOB_PERM_X) && + ((types->perm & TCL_GLOB_PERM_X) && (!(attr & FILE_ATTRIBUTE_DIRECTORY) - && !NativeIsExec(nativeName))) - ) { + && !NativeIsExec(nativeName)))) { return 0; } } - if ((types->type & TCL_GLOB_TYPE_DIR) - && (attr & FILE_ATTRIBUTE_DIRECTORY)) { - /* Quicker test for directory, which is a common case */ + if ((types->type & TCL_GLOB_TYPE_DIR) + && (attr & FILE_ATTRIBUTE_DIRECTORY)) { + /* + * Quicker test for directory, which is a common case. + */ + return 1; + } else if (types->type != 0) { unsigned short st_mode; int isExec = NativeIsExec(nativeName); - + st_mode = NativeStatMode(attr, 0, isExec); /* * 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)) || - ((types->type & TCL_GLOB_TYPE_FILE) && - S_ISREG(st_mode)) + + 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 - ) { - /* Do nothing -- this file is ok */ + ((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) { @@ -1192,8 +1372,8 @@ NativeMatchType( #endif return 0; } - } - } + } + } return 1; } @@ -1208,9 +1388,9 @@ NativeMatchType( * Results: * The result is a pointer to a string specifying the user's home * directory, or NULL if the user's home directory could not be - * determined. Storage for the result string is allocated in - * bufferPtr; the caller must call Tcl_DStringFree() when the result - * is no longer needed. + * determined. Storage for the result string is allocated in bufferPtr; + * the caller must call Tcl_DStringFree() when the result is no longer + * needed. * * Side effects: * None. @@ -1239,9 +1419,9 @@ TclpGetUserHome(name, bufferPtr) netApiBufferFreeProc = (NETAPIBUFFERFREEPROC *) GetProcAddress(netapiInst, "NetApiBufferFree"); - netGetDCNameProc = (NETGETDCNAMEPROC *) + netGetDCNameProc = (NETGETDCNAMEPROC *) GetProcAddress(netapiInst, "NetGetDCName"); - netUserGetInfoProc = (NETUSERGETINFOPROC *) + netUserGetInfoProc = (NETUSERGETINFOPROC *) GetProcAddress(netapiInst, "NetUserGetInfo"); if ((netUserGetInfoProc != NULL) && (netGetDCNameProc != NULL) && (netApiBufferFreeProc != NULL)) { @@ -1274,8 +1454,8 @@ TclpGetUserHome(name, bufferPtr) Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir), bufferPtr); } else { - /* - * User exists but has no home dir. Return + /* + * User exists but has no home dir. Return * "{Windows Drive}:/users/default". */ @@ -1296,20 +1476,20 @@ TclpGetUserHome(name, bufferPtr) } if (result == NULL) { /* - * Look in the "Password Lists" section of system.ini for the - * local user. There are also entries in that section that begin - * with a "*" character that are used by Windows for other - * purposes; ignore user names beginning with a "*". + * Look in the "Password Lists" section of system.ini for the local + * user. There are also entries in that section that begin with a "*" + * character that are used by Windows for other purposes; ignore user + * names beginning with a "*". */ char buf[MAX_PATH]; if (name[0] != '*') { - if (GetPrivateProfileStringA("Password Lists", name, "", buf, + if (GetPrivateProfileStringA("Password Lists", name, "", buf, MAX_PATH, "system.ini") > 0) { - /* - * User exists, but there is no such thing as a home - * directory in system.ini. Return "{Windows drive}:/". + /* + * User exists, but there is no such thing as a home directory + * in system.ini. Return "{Windows drive}:/". */ GetWindowsDirectoryA(buf, MAX_PATH); @@ -1329,7 +1509,7 @@ TclpGetUserHome(name, bufferPtr) * * This function replaces the library version of access(), fixing the * following bugs: - * + * * 1. access() returns that all files have execute permission. * * Results: @@ -1343,8 +1523,7 @@ TclpGetUserHome(name, bufferPtr) static int NativeAccess(nativePath, mode) - 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; @@ -1353,7 +1532,7 @@ NativeAccess(nativePath, mode) if (attr == 0xffffffff) { /* - * File doesn't exist. + * File doesn't exist. */ TclWinConvertError(GetLastError()); @@ -1364,6 +1543,7 @@ NativeAccess(nativePath, mode) /* * File is not writable. */ + Tcl_SetErrno(EACCES); return -1; } @@ -1371,27 +1551,26 @@ NativeAccess(nativePath, mode) if (mode & X_OK) { if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) { /* - * It's not a directory and doesn't have the correct - * extension. Therefore it can't be executable + * It's not a directory and doesn't have the correct extension. + * Therefore it can't be executable */ + Tcl_SetErrno(EACCES); return -1; } } - /* - * It looks as if the permissions are ok, but if we are on NT, 2000 - * or XP, 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'). + /* + * It looks as if the permissions are ok, but if we are on NT, 2000 or XP, + * 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)) { SECURITY_DESCRIPTOR *sdPtr = NULL; unsigned long size; @@ -1403,74 +1582,80 @@ NativeAccess(nativePath, mode) 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, - OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION + (*tclWinProcs->getFileSecurityProc)(nativePath, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, 0, 0, &size); - /* - * Should have failed with ERROR_INSUFFICIENT_BUFFER + /* + * Should have failed with ERROR_INSUFFICIENT_BUFFER */ + error = GetLastError(); if (error != ERROR_INSUFFICIENT_BUFFER) { - /* - * Most likely case is ERROR_ACCESS_DENIED, which - * we will convert to EACCES - just what we want! + /* + * Most likely case is ERROR_ACCESS_DENIED, which we will convert + * to EACCES - just what we want! */ + TclWinConvertError(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); if (sdPtr == NULL) { goto accessError; } - /* - * Call GetFileSecurity() for real + /* + * Call GetFileSecurity() for real */ - if (!(*tclWinProcs->getFileSecurityProc)(nativePath, - OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION + + if (!(*tclWinProcs->getFileSecurityProc)(nativePath, + OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, sdPtr, size, &size)) { - /* + /* * Error getting owner SD */ goto accessError; } - /* + /* * Perform security impersonation of the user and open the * resulting thread token. */ if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) { - /* - * Unable to perform security impersonation. + /* + * Unable to perform security impersonation. */ goto accessError; } - if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread (), + if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread (), TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) { - /* - * Unable to get current thread's token. + /* + * Unable to get current thread's token. */ goto accessError; } (*tclWinProcs->revertToSelfProc)(); - + memset (&genMap, 0x00, sizeof (GENERIC_MAPPING)); - - /* - * Setup desiredAccess according to the access priveleges we - * are checking. + + /* + * Setup desiredAccess according to the access priveleges we are + * checking. */ + genMap.GenericAll = 0; if (mode & R_OK) { desiredAccess |= FILE_GENERIC_READ; @@ -1482,28 +1667,32 @@ NativeAccess(nativePath, mode) desiredAccess |= FILE_GENERIC_EXECUTE; } - /* - * Perform access check using the token. + /* + * Perform access check using the token. */ - if (!(*tclWinProcs->accessCheckProc )(sdPtr, hToken, desiredAccess, + + if (!(*tclWinProcs->accessCheckProc)(sdPtr, hToken, desiredAccess, &genMap, &privSet, &privSetSize, &grantedAccess, &accessYesNo)) { - /* - * Unable to perform access check. + /* + * Unable to perform access check. */ - accessError: + + accessError: TclWinConvertError(GetLastError()); if (sdPtr != NULL) { - HeapFree(GetProcessHeap(), 0, sdPtr); + HeapFree(GetProcessHeap(), 0, sdPtr); } if (hToken != NULL) { - CloseHandle(hToken); + CloseHandle(hToken); } return -1; } - /* - * Clean up. + + /* + * Clean up. */ + HeapFree(GetProcessHeap (), 0, sdPtr); CloseHandle(hToken); if (!accessYesNo) { @@ -1519,15 +1708,15 @@ NativeAccess(nativePath, mode) * * NativeIsExec -- * - * Determines if a path is executable. On windows this is - * simply defined by whether the path ends in any of ".exe", - * ".com", or ".bat" + * Determines if a path is executable. On windows this is simply defined + * by whether the path ends in any of ".exe", ".com", or ".bat" * * Results: * 1 = executable, 0 = not. * *---------------------------------------------------------------------- */ + static int NativeIsExec(nativePath) CONST TCHAR *nativePath; @@ -1535,38 +1724,43 @@ NativeIsExec(nativePath) 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)) { + || (_wcsicmp(path+len-3,L"com") == 0) + || (_wcsicmp(path+len-3,L"bat") == 0)) { return 1; } } else { CONST char *p; - - /* We are only looking for pure ascii */ - + + /* + * 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 ((stricmp(p, "exe") == 0) || (stricmp(p, "com") == 0) || (stricmp(p, "bat") == 0)) { @@ -1592,28 +1786,31 @@ NativeIsExec(nativePath) * See chdir() documentation. * * Side effects: - * See chdir() documentation. + * See chdir() documentation. * *---------------------------------------------------------------------- */ -int +int TclpObjChdir(pathPtr) - Tcl_Obj *pathPtr; /* Path to new working directory. */ + Tcl_Obj *pathPtr; /* Path to new working directory. */ { int result; CONST TCHAR *nativePath; #ifdef __CYGWIN__ - extern int cygwin_conv_to_posix_path - _ANSI_ARGS_((CONST char *, char *)); + extern int cygwin_conv_to_posix_path(CONST char *, char *); char posixPath[MAX_PATH+1]; CONST char *path; Tcl_DString ds; #endif /* __CYGWIN__ */ nativePath = (CONST TCHAR *) Tcl_FSGetNativePath(pathPtr); + #ifdef __CYGWIN__ - /* Cygwin chdir only groks POSIX path. */ + /* + * 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); @@ -1635,26 +1832,26 @@ TclpObjChdir(pathPtr) * * TclpReadlink -- * - * This function replaces the library version of readlink(). + * 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. + * 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. + * See readlink() documentation. * *--------------------------------------------------------------------------- */ char * TclpReadlink(path, linkPtr) - CONST char *path; /* Path of file to readlink (UTF-8). */ - Tcl_DString *linkPtr; /* Uninitialized or free DString filled - * with contents of link (UTF-8). */ + 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; @@ -1662,9 +1859,9 @@ TclpReadlink(path, linkPtr) Tcl_DString ds; native = Tcl_UtfToExternalDString(NULL, path, -1, &ds); - length = readlink(native, link, sizeof(link)); /* INTL: Native. */ + length = readlink(native, link, sizeof(link)); /* INTL: Native. */ Tcl_DStringFree(&ds); - + if (length < 0) { return NULL; } @@ -1679,17 +1876,16 @@ TclpReadlink(path, linkPtr) * * TclpGetCwd -- * - * This function replaces the library version of getcwd(). - * (Obsolete function, only retained for old extensions which - * may call it directly). + * This function replaces the library version of getcwd(). (Obsolete + * function, only retained for old extensions which may call it + * directly). * * Results: - * The result is a pointer to a string specifying the current - * directory, or NULL if the current directory could not be - * determined. If NULL is returned, an error message is left in the - * interp's result. Storage for the result string is allocated in - * bufferPtr; the caller must call Tcl_DStringFree() when the result - * is no longer needed. + * The result is a pointer to a string specifying the current directory, + * or NULL if the current directory could not be determined. If NULL is + * returned, an error message is left in the interp's result. Storage for + * the result string is allocated in bufferPtr; the caller must call + * Tcl_DStringFree() when the result is no longer needed. * * Side effects: * None. @@ -1700,8 +1896,8 @@ TclpReadlink(path, linkPtr) CONST char * TclpGetCwd(interp, bufferPtr) Tcl_Interp *interp; /* If non-NULL, used for error reporting. */ - Tcl_DString *bufferPtr; /* Uninitialized or free DString filled - * with name of current directory. */ + Tcl_DString *bufferPtr; /* Uninitialized or free DString filled with + * name of current directory. */ { WCHAR buffer[MAX_PATH]; char *p; @@ -1709,8 +1905,7 @@ TclpGetCwd(interp, bufferPtr) if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) { TclWinConvertError(GetLastError()); if (interp != NULL) { - Tcl_AppendResult(interp, - "error getting working directory name: ", + Tcl_AppendResult(interp, "error getting working directory name: ", Tcl_PosixError(interp), (char *) NULL); } return NULL; @@ -1724,7 +1919,7 @@ TclpGetCwd(interp, bufferPtr) WCHAR *native; native = (WCHAR *) buffer; - if ((native[0] != '\0') && (native[1] == ':') + if ((native[0] != '\0') && (native[1] == ':') && (native[2] == '\\') && (native[3] == '\\')) { native += 2; } @@ -1733,7 +1928,7 @@ TclpGetCwd(interp, bufferPtr) char *native; native = (char *) buffer; - if ((native[0] != '\0') && (native[1] == ':') + if ((native[0] != '\0') && (native[1] == ':') && (native[2] == '\\') && (native[3] == '\\')) { native += 2; } @@ -1743,7 +1938,7 @@ TclpGetCwd(interp, bufferPtr) /* * Convert to forward slashes for easier use in scripts. */ - + for (p = Tcl_DStringValue(bufferPtr); *p != '\0'; p++) { if (*p == '\\') { *p = '/'; @@ -1752,16 +1947,17 @@ TclpGetCwd(interp, bufferPtr) return Tcl_DStringValue(bufferPtr); } -int +int TclpObjStat(pathPtr, statPtr) - Tcl_Obj *pathPtr; /* Path of file to stat */ - Tcl_StatBuf *statPtr; /* Filled with results of stat call. */ + Tcl_Obj *pathPtr; /* Path of file to stat. */ + Tcl_StatBuf *statPtr; /* Filled with results of stat call. */ { #ifdef OLD_API Tcl_Obj *transPtr; + /* - * Eliminate file names containing wildcard characters, or subsequent - * call to FindFirstFile() will expand them, matching some other file. + * Eliminate file names containing wildcard characters, or subsequent call + * to FindFirstFile() will expand them, matching some other file. */ transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); @@ -1774,14 +1970,14 @@ TclpObjStat(pathPtr, statPtr) } Tcl_DecrRefCount(transPtr); #endif - + /* - * Ensure correct file sizes by forcing the OS to write any - * pending data to disk. This is done only for channels which are - * dirty, i.e. have been written to since the last flush here. + * Ensure correct file sizes by forcing the OS to write any pending data + * to disk. This is done only for channels which are dirty, i.e. have been + * written to since the last flush here. */ - TclWinFlushDirtyChannels (); + TclWinFlushDirtyChannels(); return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 0); } @@ -1791,8 +1987,8 @@ TclpObjStat(pathPtr, statPtr) * * NativeStat -- * - * This function replaces the library version of stat(), fixing - * the following bugs: + * This function replaces the library version of stat(), fixing the + * following bugs: * * 1. stat("c:") returns an error. * 2. Borland stat() return time in GMT instead of localtime. @@ -1809,11 +2005,11 @@ TclpObjStat(pathPtr, statPtr) *---------------------------------------------------------------------- */ -static int +static int NativeStat(nativePath, statPtr, checkLinks) - 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' */ + 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' */ { Tcl_DString ds; DWORD attr; @@ -1822,18 +2018,19 @@ NativeStat(nativePath, statPtr, checkLinks) CONST char *fullPath; int dev; unsigned short mode; - + if (tclWinProcs->getFileAttributesExProc == NULL) { - /* - * We don't have the faster attributes proc, so we're - * probably running on Win95 - */ + /* + * 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. */ @@ -1844,9 +2041,9 @@ NativeStat(nativePath, statPtr, checkLinks) return -1; } - /* - * Make up some fake information for this file. It has the - * correct file attributes and a time of 0. + /* + * Make up some fake information for this file. It has the correct + * file attributes and a time of 0. */ memset(&data, 0, sizeof(data)); @@ -1855,9 +2052,8 @@ NativeStat(nativePath, statPtr, checkLinks) FindClose(handle); } - - (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, nativeFullPath, - &nativePart); + (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, + nativeFullPath, &nativePart); fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds); @@ -1872,7 +2068,7 @@ NativeStat(nativePath, statPtr, checkLinks) p = strchr(p + 1, '\\'); if (p == NULL) { /* - * Add terminating backslash to fullpath or + * Add terminating backslash to fullpath or * GetVolumeInformation() won't work. */ @@ -1885,12 +2081,13 @@ NativeStat(nativePath, statPtr, checkLinks) dw = (DWORD) -1; (*tclWinProcs->getVolumeInformationProc)(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. + * "\\.\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; @@ -1899,26 +2096,25 @@ NativeStat(nativePath, statPtr, checkLinks) dev = Tcl_UniCharToLower(fullPath[0]) - 'a'; } Tcl_DStringFree(&ds); - + attr = data.a.dwFileAttributes; - statPtr->st_size = ((Tcl_WideInt)data.a.nFileSizeLow) | + 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); } else { WIN32_FILE_ATTRIBUTE_DATA data; - if((*tclWinProcs->getFileAttributesExProc)(nativePath, - GetFileExInfoStandard, - &data) != TRUE) { + + if ((*tclWinProcs->getFileAttributesExProc)(nativePath, + GetFileExInfoStandard, &data) != TRUE) { Tcl_SetErrno(ENOENT); return -1; } - - (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, - nativeFullPath, &nativePart); + (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, + nativeFullPath, &nativePart); fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds); @@ -1933,7 +2129,7 @@ NativeStat(nativePath, statPtr, checkLinks) p = strchr(p + 1, '\\'); if (p == NULL) { /* - * Add terminating backslash to fullpath or + * Add terminating backslash to fullpath or * GetVolumeInformation() won't work. */ @@ -1946,12 +2142,13 @@ NativeStat(nativePath, statPtr, checkLinks) dw = (DWORD) -1; (*tclWinProcs->getVolumeInformationProc)(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. + * "\\.\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; @@ -1960,10 +2157,10 @@ NativeStat(nativePath, statPtr, checkLinks) dev = Tcl_UniCharToLower(fullPath[0]) - 'a'; } Tcl_DStringFree(&ds); - + attr = data.dwFileAttributes; - - statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) | + + statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) | (((Tcl_WideInt)data.nFileSizeHigh) << 32); statPtr->st_atime = ToCTime(data.ftLastAccessTime); statPtr->st_mtime = ToCTime(data.ftLastWriteTime); @@ -1971,7 +2168,7 @@ NativeStat(nativePath, statPtr, checkLinks) } mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath)); - + statPtr->st_dev = (dev_t) dev; statPtr->st_ino = 0; statPtr->st_mode = mode; @@ -1988,31 +2185,33 @@ NativeStat(nativePath, statPtr, checkLinks) * NativeStatMode -- * * Calculate just the 'st_mode' field of a 'stat' structure. - * - * In many places we don't need the full stat structure, and - * it's much faster just to calculate these pieces, if that's - * all we need. + * + * In many places we don't need the full stat structure, and it's much + * faster just to calculate these pieces, if that's all we need. * *---------------------------------------------------------------------- */ + static unsigned short -NativeStatMode(DWORD attr, int checkLinks, int isExec) +NativeStatMode(DWORD attr, int checkLinks, int isExec) { int mode; if (checkLinks && (attr & FILE_ATTRIBUTE_REPARSE_POINT)) { - /* It is a link */ + /* + * It is a link. + */ 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; if (isExec) { mode |= S_IEXEC; } - + /* - * Propagate the S_IREAD, S_IWRITE, S_IEXEC bits to the group and - * other positions. + * Propagate the S_IREAD, S_IWRITE, S_IEXEC bits to the group and other + * positions. */ mode |= (mode & 0x0700) >> 3; @@ -2037,13 +2236,13 @@ static time_t ToCTime(FILETIME fileTime) /* UTC time */ { LARGE_INTEGER convertedTime; + convertedTime.LowPart = fileTime.dwLowDateTime; convertedTime.HighPart = (LONG) fileTime.dwHighDateTime; + return (time_t) ((convertedTime.QuadPart - - (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) - / (Tcl_WideInt) 10000000); + - (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000); } - /* *------------------------------------------------------------------------ @@ -2059,54 +2258,55 @@ ToCTime(FILETIME fileTime) /* UTC time */ */ static void -FromCTime(time_t posixTime, - FILETIME* fileTime) /* UTC Time */ +FromCTime( + time_t posixTime, + FILETIME* fileTime) /* UTC Time */ { LARGE_INTEGER convertedTime; - convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000 + convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000 + 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. + * 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. + * 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. + * Loads and unloads OLE package to determine if filename refers to a + * shortcut. * *------------------------------------------------------------------------- */ int TclWinResolveShortcut(bufferPtr) - Tcl_DString *bufferPtr; /* Holds name of file to resolve. On - * return, holds resolved file name. */ + 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; + 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. + * Windows system calls do not automatically resolve shortcuts like UNIX + * automatically will with symbolic links. */ path = Tcl_DStringValue(bufferPtr); @@ -2118,25 +2318,24 @@ TclWinResolveShortcut(bufferPtr) CoInitialize(NULL); path = Tcl_DStringValue(bufferPtr); realFileName[0] = '\0'; - hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - &IID_IShellLink, &psl); - if (SUCCEEDED(hres)) { + 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)) { + if (SUCCEEDED(hres)) { MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, sizeof(wpath)); - hres = ppf->lpVtbl->Load(ppf, wpath, STGM_READ); + 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, + 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); - } + } + } + ppf->lpVtbl->Release(ppf); + } + psl->lpVtbl->Release(psl); + } CoUninitialize(); if (realFileName[0] != '\0') { @@ -2156,13 +2355,12 @@ TclWinResolveShortcut(bufferPtr) * This function replaces the library version of getcwd(). * * Results: - * The input and output are filesystem paths in native form. The - * result is either the given clientData, if the working directory - * hasn't changed, or a new clientData (owned by our caller), - * giving the new native path, or NULL if the current directory - * could not be determined. If NULL is returned, the caller can - * examine the standard posix error codes to determine the cause of - * the problem. + * The input and output are filesystem paths in native form. The result + * is either the given clientData, if the working directory hasn't + * changed, or a new clientData (owned by our caller), giving the new + * native path, or NULL if the current directory could not be determined. + * If NULL is returned, the caller can examine the standard posix error + * codes to determine the cause of the problem. * * Side effects: * None. @@ -2175,58 +2373,61 @@ TclpGetNativeCwd(clientData) ClientData clientData; { WCHAR buffer[MAX_PATH]; - + if ((*tclWinProcs->getCurrentDirectoryProc)(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) { + 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) { + /* + * ANSI representation when running on 95/98/ME. + */ + + if (strcmp((CONST char*)clientData, (CONST char*)buffer) == 0) { return clientData; } } } - + return TclNativeDupInternalRep((ClientData)buffer); } - -int + +int TclpObjAccess(pathPtr, mode) Tcl_Obj *pathPtr; int mode; { - return NativeAccess((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), mode); + return NativeAccess((CONST TCHAR *) Tcl_FSGetNativePath(pathPtr), mode); } - -int + +int TclpObjLstat(pathPtr, statPtr) Tcl_Obj *pathPtr; - Tcl_StatBuf *statPtr; + Tcl_StatBuf *statPtr; { /* - * Ensure correct file sizes by forcing the OS to write any - * pending data to disk. This is done only for channels which are - * dirty, i.e. have been written to since the last flush here. + * Ensure correct file sizes by forcing the OS to write any pending data + * to disk. This is done only for channels which are dirty, i.e. have been + * written to since the last flush here. */ TclWinFlushDirtyChannels (); return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 1); } - + #ifdef S_IFLNK - -Tcl_Obj* +Tcl_Obj* TclpObjLink(pathPtr, toPtr, linkAction) Tcl_Obj *pathPtr; Tcl_Obj *toPtr; @@ -2235,11 +2436,13 @@ TclpObjLink(pathPtr, toPtr, linkAction) if (toPtr != NULL) { int res; #if 0 - TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(toPtr); + TCHAR *LinkTarget = (TCHAR *) Tcl_FSGetNativePath(toPtr); #else - TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(Tcl_FSGetNormalizedPath(NULL,toPtr)); + TCHAR *LinkTarget = (TCHAR *) Tcl_FSGetNativePath( + Tcl_FSGetNormalizedPath(NULL, toPtr)); #endif - TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr); + TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr); + if (LinkSource == NULL || LinkTarget == NULL) { return NULL; } @@ -2250,34 +2453,34 @@ TclpObjLink(pathPtr, toPtr, linkAction) return NULL; } } else { - TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr); + TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr); + if (LinkSource == NULL) { return NULL; } return WinReadLink(LinkSource); } } - #endif - /* *--------------------------------------------------------------------------- * * TclpFilesystemPathType -- * - * This function is part of the native filesystem support, and - * returns the path type of the given path. Returns NTFS or FAT - * or whatever is returned by the 'volume information' proc. + * This function is part of the native filesystem support, and returns + * the path type of the given path. Returns NTFS or FAT or whatever is + * returned by the 'volume information' proc. * * Results: - * NULL at present. + * NULL at present. * * Side effects: * None. * *--------------------------------------------------------------------------- */ + Tcl_Obj* TclpFilesystemPathType(pathPtr) Tcl_Obj* pathPtr; @@ -2287,23 +2490,28 @@ TclpFilesystemPathType(pathPtr) WCHAR volType[VOL_BUF_SIZE]; char* firstSeparator; CONST char *path; - Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathPtr); - if (normPath == NULL) return NULL; + + if (normPath == NULL) { + return NULL; + } path = Tcl_GetString(normPath); - if (path == NULL) return NULL; - + if (path == NULL) { + return NULL; + } + firstSeparator = strchr(path, '/'); if (firstSeparator == NULL) { found = tclWinProcs->getVolumeInformationProc( - Tcl_FSGetNativePath(pathPtr), NULL, 0, NULL, NULL, - NULL, (WCHAR *)volType, VOL_BUF_SIZE); + Tcl_FSGetNativePath(pathPtr), NULL, 0, NULL, NULL, NULL, + (WCHAR *) 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); + Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, NULL, + (WCHAR *) volType, VOL_BUF_SIZE); Tcl_DecrRefCount(driveName); } @@ -2312,27 +2520,29 @@ TclpFilesystemPathType(pathPtr) } else { Tcl_DString ds; Tcl_Obj *objPtr; - + Tcl_WinTCharToUtf((CONST char *)volType, -1, &ds); - objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),Tcl_DStringLength(&ds)); + objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), + Tcl_DStringLength(&ds)); Tcl_DStringFree(&ds); return objPtr; } #undef VOL_BUF_SIZE } -/* + +/* * This define can be turned on to experiment with a different way of - * normalizing paths (using a different Windows API). Unfortunately the - * new path seems to take almost exactly the same amount of time as the - * old path! The primary time taken by normalization is in - * GetFileAttributesEx/FindFirstFile or - * GetFileAttributesEx/GetLongPathName. Conversion to/from native is - * not a significant factor at all. - * - * Also, since we have to check for symbolic links (reparse points) - * then we have to call GetFileAttributes on each path segment anyway, - * so there's no benefit to doing anything clever there. + * normalizing paths (using a different Windows API). Unfortunately the new + * path seems to take almost exactly the same amount of time as the old path! + * The primary time taken by normalization is in + * GetFileAttributesEx/FindFirstFile or GetFileAttributesEx/GetLongPathName. + * Conversion to/from native is not a significant factor at all. + * + * Also, since we have to check for symbolic links (reparse points) then we + * have to call GetFileAttributes on each path segment anyway, so there's no + * benefit to doing anything clever there. */ + /* #define TclNORM_LONG_PATH */ /* @@ -2340,18 +2550,17 @@ TclpFilesystemPathType(pathPtr) * * TclpObjNormalizePath -- * - * This function scans through a path specification and replaces it, - * in place, with a normalized version. This means using the - * 'longname', and expanding any symbolic links contained within the - * path. + * This function scans through a path specification and replaces it, in + * place, with a normalized version. This means using the 'longname', and + * expanding any symbolic links contained within the path. * * Results: - * The new 'nextCheckpoint' value, giving as far as we could - * understand in the path. + * The new 'nextCheckpoint' value, giving as far as we could understand + * in the path. * * Side effects: - * The pathPtr string, which must contain a valid path, is - * possibly modified in place. + * The pathPtr string, which must contain a valid path, is possibly + * modified in place. * *--------------------------------------------------------------------------- */ @@ -2362,8 +2571,7 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) int nextCheckpoint; { char *lastValidPathEnd = NULL; - /* This will hold the normalized string */ - Tcl_DString dsNorm; + Tcl_DString dsNorm; /* This will hold the normalized string. */ char *path; char *currentPathEndPosition; @@ -2371,40 +2579,52 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) 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. + /* + * 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 == '/') { + if (*currentPathEndPosition == '/') { currentPathEndPosition++; - } + } + while (1) { char cur = *currentPathEndPosition; if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { - /* Reached directory separator, or end of string */ - CONST char *nativePath = Tcl_UtfToExternalDString(NULL, path, - currentPathEndPosition - path, &ds); + /* + * Reached directory separator, or end of string. + */ + + CONST char *nativePath = Tcl_UtfToExternalDString(NULL, path, + currentPathEndPosition - path, &ds); /* - * 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. + * 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. */ + if (isDrive) { if (GetFileAttributesA(nativePath) == 0xffffffff) { - /* File doesn't exist */ + /* + * File doesn't exist. + */ + if (isDrive) { int len = WinIsReserved(path); if (len > 0) { - /* Actually it does exist - COM1, etc */ + /* + * Actually it does exist - COM1, etc. + */ + int i; + for (i=0;i<len;i++) { if (nativePath[i] >= 'a') { ((char*)nativePath)[i] -= ('a' - 'A'); @@ -2420,10 +2640,11 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) if (nativePath[0] >= 'a') { ((char*)nativePath)[0] -= ('a' - 'A'); } - Tcl_DStringAppend(&dsNorm,nativePath,Tcl_DStringLength(&ds)); + Tcl_DStringAppend(&dsNorm, nativePath, + Tcl_DStringLength(&ds)); } else { char *checkDots = NULL; - + if (lastValidPathEnd[1] == '.') { checkDots = lastValidPathEnd + 1; while (checkDots < currentPathEndPosition) { @@ -2436,33 +2657,45 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) } if (checkDots != NULL) { int dotLen = currentPathEndPosition - lastValidPathEnd; - /* - * 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 + + /* + * 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 */ - Tcl_DStringAppend(&dsNorm, (TCHAR*)(nativePath - + Tcl_DStringLength(&ds) - - dotLen), dotLen); + + Tcl_DStringAppend(&dsNorm, (TCHAR *) + (nativePath + Tcl_DStringLength(&ds) - dotLen), + dotLen); } else { - /* Normal path */ + /* + * Normal path. + */ + WIN32_FIND_DATA fData; HANDLE handle; - + handle = FindFirstFileA(nativePath, &fData); if (handle == INVALID_HANDLE_VALUE) { - if (GetFileAttributesA(nativePath) - == 0xffffffff) { - /* File doesn't exist */ + if (GetFileAttributesA(nativePath) == 0xffffffff) { + /* + * File doesn't exist. + */ + Tcl_DStringFree(&ds); break; } - /* This is usually the '/' in 'c:/' at end of string */ + + /* + * 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 { @@ -2479,20 +2712,23 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) 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++; } } else { - /* We're on WinNT or 2000 or XP */ + /* + * We're on WinNT (or 2000 or XP; something with an NT core). + */ + Tcl_Obj *temp = NULL; int isDrive = 1; Tcl_DString ds; - + currentPathEndPosition = path + nextCheckpoint; if (*currentPathEndPosition == '/') { currentPathEndPosition++; @@ -2500,27 +2736,39 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) while (1) { char cur = *currentPathEndPosition; if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) { - /* Reached directory separator, or end of string */ + /* + * Reached directory separator, or end of string. + */ + WIN32_FILE_ATTRIBUTE_DATA data; - CONST char *nativePath = Tcl_WinUtfToTChar(path, - currentPathEndPosition - path, &ds); + CONST char *nativePath = Tcl_WinUtfToTChar(path, + currentPathEndPosition - path, &ds); + if ((*tclWinProcs->getFileAttributesExProc)(nativePath, - GetFileExInfoStandard, &data) != TRUE) { - /* File doesn't exist */ + GetFileExInfoStandard, &data) != TRUE) { + /* + * File doesn't exist. + */ + if (isDrive) { - int len = WinIsReserved(path); + int len = WinIsReserved(path); + if (len > 0) { - /* Actually it does exist - COM1, etc */ + /* + * Actually it does exist - COM1, etc. + */ + int i; + for (i=0;i<len;i++) { - WCHAR wc = ((WCHAR*)nativePath)[i]; + WCHAR wc = ((WCHAR*)nativePath)[i]; if (wc >= L'a') { wc -= (L'a' - L'A'); ((WCHAR*)nativePath)[i] = wc; } } Tcl_DStringAppend(&dsNorm, nativePath, - sizeof(WCHAR)*len); + sizeof(WCHAR)*len); lastValidPathEnd = currentPathEndPosition; } } @@ -2528,38 +2776,42 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) 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. + /* + * 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 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. */ - if (cur != 0 && !isDrive - && (data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) { + + if (cur != 0 && !isDrive && + (data.dwFileAttributes&FILE_ATTRIBUTE_REPARSE_POINT)) { Tcl_Obj *to = WinReadLinkDirectory(nativePath); + if (to != NULL) { - /* - * Read the reparse point ok. Now, reparse - * points need not be normalized, otherwise - * we could use: - * - * Tcl_GetStringFromObj(to, &pathLen); + /* + * 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. + * + * So, instead we have to start from the beginning. */ + nextCheckpoint = 0; Tcl_AppendToObj(to, currentPathEndPosition, -1); - /* Convert link to forward slashes */ + + /* + * Convert link to forward slashes. + */ + for (path = Tcl_GetString(to); *path != 0; path++) { if (*path == '\\') *path = '/'; } @@ -2569,7 +2821,11 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) Tcl_DecrRefCount(temp); } temp = to; - /* Reset variables so we can restart normalization */ + + /* + * Reset variables so we can restart normalization. + */ + isDrive = 1; Tcl_DStringFree(&dsNorm); Tcl_DStringInit(&dsNorm); @@ -2577,22 +2833,25 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) continue; } } + #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 + * 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 (isDrive) { WCHAR drive = ((WCHAR*)nativePath)[0]; if (drive >= L'a') { - drive -= (L'a' - L'A'); + drive -= (L'a' - L'A'); ((WCHAR*)nativePath)[0] = drive; } - Tcl_DStringAppend(&dsNorm,nativePath,Tcl_DStringLength(&ds)); + Tcl_DStringAppend(&dsNorm, nativePath, + Tcl_DStringLength(&ds)); } else { char *checkDots = NULL; - + if (lastValidPathEnd[1] == '.') { checkDots = lastValidPathEnd + 1; while (checkDots < currentPathEndPosition) { @@ -2605,40 +2864,47 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) } if (checkDots != NULL) { int dotLen = currentPathEndPosition - lastValidPathEnd; - /* - * 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 + + /* + * 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. */ - Tcl_DStringAppend(&dsNorm, - (TCHAR*)((WCHAR*)(nativePath - + Tcl_DStringLength(&ds)) - - dotLen), - (int)(dotLen * sizeof(WCHAR))); + + Tcl_DStringAppend(&dsNorm, (TCHAR *) + ((WCHAR*)(nativePath + Tcl_DStringLength(&ds)) + - dotLen), (int)(dotLen * sizeof(WCHAR))); } else { - /* Normal path */ + /* + * Normal path. + */ + 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)); + /* + * This is usually the '/' in 'c:/' at end of + * string. + */ + + Tcl_DStringAppend(&dsNorm,(CONST char*)L"/", + sizeof(WCHAR)); } 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))); + Tcl_DStringAppend(&dsNorm, (CONST char*)L"/", + sizeof(WCHAR)); + Tcl_DStringAppend(&dsNorm, (TCHAR *) nativeName, + (int) (wcslen(nativeName)*sizeof(WCHAR))); } } } @@ -2648,27 +2914,33 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) 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++; } + #ifdef TclNORM_LONG_PATH - /* + /* * Convert the entire known path to long form. */ + if (1) { WCHAR wpath[MAX_PATH]; - DWORD wpathlen; - CONST char *nativePath = Tcl_WinUtfToTChar(path, - lastValidPathEnd - path, &ds); - wpathlen = (*tclWinProcs->getLongPathNameProc)(nativePath, - (TCHAR*)wpath, - MAX_PATH); - /* We have to make the drive letter uppercase */ + CONST char *nativePath = + Tcl_WinUtfToTChar(path, lastValidPathEnd - path, &ds); + DWORD wpathlen = (*tclWinProcs->getLongPathNameProc)( + nativePath, (TCHAR *) wpath, MAX_PATH); + + /* + * We have to make the drive letter uppercase. + */ + if (wpath[0] >= L'a') { wpath[0] -= (L'a' - L'A'); } @@ -2677,34 +2949,46 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) } #endif } - /* Common code path for all Windows platforms */ + + /* + * Common code path for all Windows platforms. + */ + nextCheckpoint = currentPathEndPosition - path; if (lastValidPathEnd != NULL) { - /* - * Concatenate the normalized string in dsNorm with the - * tail of the path which we didn't recognise. The - * string in dsNorm is in the native encoding, so we - * have to convert it to Utf. + /* + * Concatenate the normalized string in dsNorm with the tail of the + * path which we didn't recognise. The string in dsNorm is in the + * native encoding, so we have to convert it to Utf. */ + Tcl_DString dsTemp; - Tcl_WinTCharToUtf(Tcl_DStringValue(&dsNorm), - Tcl_DStringLength(&dsNorm), &dsTemp); + + Tcl_WinTCharToUtf(Tcl_DStringValue(&dsNorm), + Tcl_DStringLength(&dsNorm), &dsTemp); nextCheckpoint = Tcl_DStringLength(&dsTemp); if (*lastValidPathEnd != 0) { - /* Not the end of the string */ + /* + * Not the end of the string. + */ + int len; char *path; Tcl_Obj *tmpPathPtr; - tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp), - nextCheckpoint); + + tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp), + nextCheckpoint); Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1); path = Tcl_GetStringFromObj(tmpPathPtr, &len); Tcl_SetStringObj(pathPtr, path, len); Tcl_DecrRefCount(tmpPathPtr); } else { - /* End of string was reached above */ + /* + * End of string was reached above. + */ + Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&dsTemp), - nextCheckpoint); + nextCheckpoint); } Tcl_DStringFree(&dsTemp); } @@ -2717,24 +3001,25 @@ TclpObjNormalizePath(interp, pathPtr, nextCheckpoint) * * TclWinVolumeRelativeNormalize -- * - * Only Windows has volume-relative paths. These paths are rather - * rare, but it is nice if Tcl can handle them. It is much better - * if we can handle them here, rather than in the native fs code, - * because we really need to have a real absolute path just below. - * - * We do not let this block compile on non-Windows platforms - * because the test suite's manual forcing of tclPlatform can - * otherwise cause this code path to be executed, causing various - * errors because volume-relative paths really do not exist. + * Only Windows has volume-relative paths. These paths are rather rare, + * but it is nice if Tcl can handle them. It is much better if we can + * handle them here, rather than in the native fs code, because we really + * need to have a real absolute path just below. + * + * We do not let this block compile on non-Windows platforms because the + * test suite's manual forcing of tclPlatform can otherwise cause this + * code path to be executed, causing various errors because + * volume-relative paths really do not exist. * * Results: - * A valid normalized path. + * A valid normalized path. * * Side effects: * None. * *--------------------------------------------------------------------------- */ + Tcl_Obj* TclWinVolumeRelativeNormalize(interp, path, useThisCwdPtr) Tcl_Interp *interp; @@ -2742,69 +3027,71 @@ TclWinVolumeRelativeNormalize(interp, path, useThisCwdPtr) Tcl_Obj **useThisCwdPtr; { Tcl_Obj *absolutePath, *useThisCwd; - + useThisCwd = Tcl_FSGetCwd(interp); if (useThisCwd == NULL) { - return NULL; + return NULL; } - + if (path[0] == '/') { - /* - * Path of form /foo/bar which is a path in the - * root directory of the current volume. + /* + * Path of form /foo/bar which is a path in the root directory of the + * current volume. */ + CONST char *drive = Tcl_GetString(useThisCwd); - + absolutePath = Tcl_NewStringObj(drive,2); Tcl_AppendToObj(absolutePath, path, -1); Tcl_IncrRefCount(absolutePath); - /* We have a refCount on the cwd */ + + /* + * We have a refCount on the cwd. + */ } else { - /* - * Path of form C:foo/bar, but this only makes - * sense if the cwd is also on drive C. + /* + * Path of form C:foo/bar, but this only makes sense if the cwd is + * also on drive C. */ - + int cwdLen; - CONST char *drive = - Tcl_GetStringFromObj(useThisCwd, &cwdLen); + CONST char *drive = + Tcl_GetStringFromObj(useThisCwd, &cwdLen); char drive_cur = path[0]; - + if (drive_cur >= 'a') { drive_cur -= ('a' - 'A'); } if (drive[0] == drive_cur) { absolutePath = Tcl_DuplicateObj(useThisCwd); - /* - * We have a refCount on the cwd, which we - * will release later. + + /* + * We have a refCount on the cwd, which we will release later. */ if (drive[cwdLen-1] != '/' && (path[2] != '\0')) { - /* - * Only add a trailing '/' if needed, which - * is if there isn't one already, and if we - * are going to be adding some more + /* + * Only add a trailing '/' if needed, which is if there isn't + * one already, and if we are going to be adding some more * characters. */ + Tcl_AppendToObj(absolutePath, "/", 1); } } else { Tcl_DecrRefCount(useThisCwd); useThisCwd = NULL; - /* - * The path is not in the current drive, but - * is volume-relative. The way Tcl 8.3 handles - * this is that it treats such a path as - * relative to the root of the drive. We - * therefore behave the same here. This - * behaviour is, however, different to that - * of the windows command-line. If we want - * to fix this at some point in the future - * (at the expense of a behaviour change to - * Tcl), we could use the '_dgetdcwd' Win32 - * API to get the drive's cwd. + + /* + * The path is not in the current drive, but is volume-relative. + * The way Tcl 8.3 handles this is that it treats such a path as + * relative to the root of the drive. We therefore behave the same + * here. This behaviour is, however, different to that of the + * windows command-line. If we want to fix this at some point in + * the future (at the expense of a behaviour change to Tcl), we + * could use the '_dgetdcwd' Win32 API to get the drive's cwd. */ + absolutePath = Tcl_NewStringObj(path, 2); Tcl_AppendToObj(absolutePath, "/", 1); } @@ -2820,42 +3107,43 @@ TclWinVolumeRelativeNormalize(interp, path, useThisCwdPtr) * * TclpNativeToNormalized -- * - * Convert native format to a normalized path object, with refCount - * of zero. - * - * Currently assumes all native paths are actually normalized - * already, so if the path given is not normalized this will - * actually just convert to a valid string path, but not - * necessarily a normalized one. + * Convert native format to a normalized path object, with refCount of + * zero. + * + * Currently assumes all native paths are actually normalized already, so + * if the path given is not normalized this will actually just convert to + * a valid string path, but not necessarily a normalized one. * * Results: - * A valid normalized path. + * A valid normalized path. * * Side effects: * None. * *--------------------------------------------------------------------------- */ -Tcl_Obj* + +Tcl_Obj* TclpNativeToNormalized(clientData) ClientData clientData; { Tcl_DString ds; Tcl_Obj *objPtr; int len; - + char *copy; char *p; Tcl_WinTCharToUtf((CONST char*)clientData, -1, &ds); - + copy = Tcl_DStringValue(&ds); len = Tcl_DStringLength(&ds); - /* - * Certain native path representations on Windows have this special - * prefix to indicate that they are to be treated specially. For - * example extremely long paths, or symlinks + /* + * Certain native path representations on Windows have this special prefix + * to indicate that they are to be treated specially. For example + * extremely long paths, or symlinks. */ + if (*copy == '\\') { if (0 == strncmp(copy,"\\??\\",4)) { copy += 4; @@ -2865,9 +3153,11 @@ TclpNativeToNormalized(clientData) len -= 4; } } - /* + + /* * Ensure we are using forward slashes only. */ + for (p = copy; *p != '\0'; p++) { if (*p == '\\') { *p = '/'; @@ -2876,7 +3166,7 @@ TclpNativeToNormalized(clientData) objPtr = Tcl_NewStringObj(copy,len); Tcl_DStringFree(&ds); - + return objPtr; } @@ -2885,17 +3175,18 @@ TclpNativeToNormalized(clientData) * * TclNativeCreateNativeRep -- * - * Create a native representation for the given path. + * Create a native representation for the given path. * * Results: - * The nativePath representation. + * The nativePath representation. * * Side effects: - * Memory will be allocated. The path may need to be normalized. + * Memory will be allocated. The path may need to be normalized. * *--------------------------------------------------------------------------- */ -ClientData + +ClientData TclNativeCreateNativeRep(pathPtr) Tcl_Obj* pathPtr; { @@ -2906,15 +3197,18 @@ TclNativeCreateNativeRep(pathPtr) char *str; if (TclFSCwdIsNative()) { - /* - * The cwd is native, which means we can use the translated - * path without worrying about normalization (this will also - * usually be shorter so the utf-to-external conversion will - * be somewhat faster). + /* + * The cwd is native, which means we can use the translated path + * without worrying about normalization (this will also usually be + * shorter so the utf-to-external conversion will be somewhat faster). */ + validPathPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr); } else { - /* Make sure the normalized path is set */ + /* + * Make sure the normalized path is set. + */ + validPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr); Tcl_IncrRefCount(validPathPtr); } @@ -2929,7 +3223,7 @@ TclNativeCreateNativeRep(pathPtr) Tcl_DecrRefCount(validPathPtr); nativePathPtr = ckalloc((unsigned) len); memcpy((VOID*)nativePathPtr, (VOID*)Tcl_DStringValue(&ds), (size_t) len); - + Tcl_DStringFree(&ds); return (ClientData)nativePathPtr; } @@ -2939,18 +3233,19 @@ TclNativeCreateNativeRep(pathPtr) * * TclNativeDupInternalRep -- * - * Duplicate the native representation. + * Duplicate the native representation. * * Results: - * The copied native representation, or NULL if it is not possible - * to copy the representation. + * The copied native representation, or NULL if it is not possible to + * copy the representation. * * Side effects: * Memory allocation for the copy. * *--------------------------------------------------------------------------- */ -ClientData + +ClientData TclNativeDupInternalRep(clientData) ClientData clientData; { @@ -2962,16 +3257,22 @@ TclNativeDupInternalRep(clientData) } if (tclWinProcs->useWide) { - /* unicode representation when running on NT/2K/XP */ - len = sizeof(WCHAR) + (wcslen((CONST WCHAR*)clientData) * sizeof(WCHAR)); + /* + * 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(char) + (strlen((CONST char*)clientData) * sizeof(char)); + /* + * ANSI representation when running on 95/98/ME. + */ + + len = sizeof(char) * (strlen((CONST char *) clientData) + 1); } - + copy = (char *) ckalloc(len); - memcpy((VOID*)copy, (VOID*)clientData, len); - return (ClientData)copy; + memcpy((VOID *) copy, (VOID *) clientData, len); + return (ClientData) copy; } /* @@ -2985,34 +3286,35 @@ TclNativeDupInternalRep(clientData) * 0 on success, -1 on error. * * Side effects: - * Sets errno to a representation of any Windows problem that's - * observed in the process. + * Sets errno to a representation of any Windows problem that's observed + * in the process. * *--------------------------------------------------------------------------- */ int TclpUtime(pathPtr, tval) - Tcl_Obj *pathPtr; /* File to modify */ - struct utimbuf *tval; /* New modification date structure */ + Tcl_Obj *pathPtr; /* File to modify */ + struct utimbuf *tval; /* New modification date structure */ { int res = 0; HANDLE fileHandle; FILETIME lastAccessTime, lastModTime; - + FromCTime(tval->actime, &lastAccessTime); FromCTime(tval->modtime, &lastModTime); - + /* - * We use the native APIs (not 'utime') because there are - * some daylight savings complications that utime gets wrong. + * We use the native APIs (not 'utime') because there are some daylight + * savings complications that utime gets wrong. */ + fileHandle = (tclWinProcs->createFileProc) ( - (CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), - FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL, NULL); - - if (fileHandle == INVALID_HANDLE_VALUE - || !SetFileTime(fileHandle, NULL, &lastAccessTime, &lastModTime)) { + (CONST TCHAR *) Tcl_FSGetNativePath(pathPtr), + FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, NULL); + + if (fileHandle == INVALID_HANDLE_VALUE || + !SetFileTime(fileHandle, NULL, &lastAccessTime, &lastModTime)) { TclWinConvertError(GetLastError()); res = -1; } @@ -3021,3 +3323,11 @@ TclpUtime(pathPtr, tval) } return res; } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |