summaryrefslogtreecommitdiffstats
path: root/win/tclWinFile.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinFile.c')
-rw-r--r--win/tclWinFile.c2920
1 files changed, 1129 insertions, 1791 deletions
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index 7da19ce..4abd215 100644
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -1,21 +1,24 @@
-/*
+/*
* 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.
*/
+#ifndef _WIN64
+/* See [Bug 2935503]: file mtime sets wrong time */
+# define _USE_32BIT_TIME_T
+#endif
+#include <sys/stat.h>
#include "tclWinInt.h"
-#include "tclFileSystem.h"
#include <winioctl.h>
-#include <sys/stat.h>
#include <shlobj.h>
#include <lmaccess.h> /* For TclpGetUserHome(). */
@@ -24,280 +27,234 @@
* on the proleptic Gregorian calendar) and the Posix epoch (1970-01-01).
*/
-#define POSIX_EPOCH_AS_FILETIME \
- ((Tcl_WideInt) 116444736 * (Tcl_WideInt) 1000000000)
+#define POSIX_EPOCH_AS_FILETIME 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
#ifndef INVALID_FILE_ATTRIBUTES
-#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
#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;
- ULONG Flags;
- 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 )
#define HAVE_NO_FINDEX_ENUMS
#elif !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0400)
-#undef HAVE_NO_FINDEX_ENUMS
#define HAVE_NO_FINDEX_ENUMS
#endif
#ifdef HAVE_NO_FINDEX_ENUMS
/* These two aren't in VC++ 5.2 headers */
typedef enum _FINDEX_INFO_LEVELS {
- FindExInfoStandard,
- FindExInfoMaxInfoLevel
+ 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);
-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 functions defined in this file:
+ * Declarations for local procedures defined in this file:
*/
-static int NativeAccess(const TCHAR *path, int mode);
-static int NativeDev(const TCHAR *path);
-static int NativeStat(const TCHAR *path, Tcl_StatBuf *statPtr,
- 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, DWORD desiredAccess);
-static int NativeWriteReparse(const TCHAR *LinkDirectory,
- REPARSE_DATA_BUFFER *buffer);
-static int NativeMatchType(int isDrive, DWORD attr,
- const TCHAR *nativeName, Tcl_GlobTypeData *types);
-static int WinIsDrive(const char *name, int nameLen);
-static int WinIsReserved(const char *path);
-static Tcl_Obj * WinReadLink(const TCHAR *LinkSource);
-static Tcl_Obj * WinReadLinkDirectory(const TCHAR *LinkDirectory);
-static int WinLink(const TCHAR *LinkSource,
- const TCHAR *LinkTarget, int linkAction);
-static int WinSymLinkDirectory(const TCHAR *LinkDirectory,
- const TCHAR *LinkTarget);
+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, DWORD desiredAccess);
+static int NativeWriteReparse(CONST TCHAR* LinkDirectory,
+ REPARSE_DATA_BUFFER* buffer);
+static int NativeMatchType(int isDrive, DWORD attr, CONST TCHAR* nativeName,
+ Tcl_GlobTypeData *types);
+static int WinIsDrive(CONST char *name, int nameLen);
+static int WinIsReserved(CONST char *path);
+static Tcl_Obj* WinReadLink(CONST TCHAR* LinkSource);
+static Tcl_Obj* WinReadLinkDirectory(CONST TCHAR* LinkDirectory);
+static int WinLink(CONST TCHAR* LinkSource, CONST TCHAR* LinkTarget,
+ int linkAction);
+static int WinSymLinkDirectory(CONST TCHAR* LinkDirectory,
+ CONST TCHAR* LinkTarget);
/*
*--------------------------------------------------------------------
*
- * WinLink --
- *
- * Make a link from source to target.
+ * WinLink
*
+ * Make a link from source to target.
*--------------------------------------------------------------------
*/
-
-static int
-WinLink(
- const TCHAR *linkSourcePath,
- const TCHAR *linkTargetPath,
- int linkAction)
+static int
+WinLink(LinkSource, LinkTarget, linkAction)
+ CONST TCHAR* LinkSource;
+ CONST TCHAR* LinkTarget;
+ int linkAction;
{
- WCHAR tempFileName[MAX_PATH];
- TCHAR *tempFilePart;
- DWORD attr;
-
- /*
- * Get the full path referenced by the target.
- */
-
- if (!(*tclWinProcs->getFullPathNameProc)(linkTargetPath, 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.
- */
-
- attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
- if (attr != INVALID_FILE_ATTRIBUTES) {
+ /* Make sure source file doesn't exist */
+ attr = (*tclWinProcs->getFileAttributesProc)(LinkSource);
+ if (attr != -1) {
Tcl_SetErrno(EEXIST);
return -1;
}
- /*
- * Get the full path referenced by the source file/directory.
- */
-
- if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH,
- tempFileName, &tempFilePart)) {
- /*
- * Invalid file.
- */
-
+ /* Get the full path referenced by the directory */
+ if (!(*tclWinProcs->getFullPathNameProc)(LinkSource,
+ MAX_PATH, tempFileName, &tempFilePart)) {
+ /* Invalid file */
TclWinConvertError(GetLastError());
return -1;
}
-
- /*
- * Check the target.
- */
-
- attr = (*tclWinProcs->getFileAttributesProc)(linkTargetPath);
- if (attr == INVALID_FILE_ATTRIBUTES) {
- /*
- * The target doesn't exist.
- */
-
+ /* Check the target */
+ attr = (*tclWinProcs->getFileAttributesProc)(LinkTarget);
+ if (attr == -1) {
+ /* 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)(linkSourcePath,
- linkTargetPath, 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 {
@@ -305,19 +262,10 @@ WinLink(
return -1;
}
} else {
- /*
- * We've got a directory. Now check whether what we're trying to do is
- * reasonable.
- */
-
if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
- return WinSymLinkDirectory(linkSourcePath, linkTargetPath);
-
+ 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 {
@@ -330,213 +278,169 @@ WinLink(
/*
*--------------------------------------------------------------------
*
- * WinReadLink --
- *
- * What does 'LinkSource' point to?
+ * WinReadLink
*
+ * What does 'LinkSource' point to?
*--------------------------------------------------------------------
*/
-
-static Tcl_Obj *
-WinReadLink(
- const TCHAR *linkSourcePath)
+static Tcl_Obj*
+WinReadLink(LinkSource)
+ CONST TCHAR* LinkSource;
{
- WCHAR tempFileName[MAX_PATH];
- TCHAR *tempFilePart;
- DWORD attr;
-
- /*
- * Get the full path referenced by the target.
- */
-
- if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, 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.
- */
-
- attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
- if (attr == INVALID_FILE_ATTRIBUTES) {
- /*
- * The source doesn't exist.
- */
-
+ /* Make sure source file does exist */
+ attr = (*tclWinProcs->getFileAttributesProc)(LinkSource);
+ if (attr == -1) {
+ /* 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 {
- return WinReadLinkDirectory(linkSourcePath);
+ return WinReadLinkDirectory(LinkSource);
}
}
/*
*--------------------------------------------------------------------
*
- * WinSymLinkDirectory --
- *
- * This routine creates a NTFS junction, using the undocumented
- * FSCTL_SET_REPARSE_POINT structure Win2K uses for mount points and
- * junctions.
- *
- * Assumption that linkTargetPath is a valid, existing directory.
+ * WinSymLinkDirectory
*
- * Returns:
- * Zero on success.
+ * 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.
+ *
+ * Returns zero on success.
*--------------------------------------------------------------------
*/
-
-static int
-WinSymLinkDirectory(
- const TCHAR *linkDirPath,
- const TCHAR *linkTargetPath)
+static int
+WinSymLinkDirectory(LinkDirectory, 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.
- */
-
- memcpy(nativeTarget, L"\\??\\", 4 * sizeof(WCHAR));
- memcpy(nativeTarget + 4, linkTargetPath,
- sizeof(WCHAR) * (1+wcslen((WCHAR *) linkTargetPath)));
+ REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy;
+ 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,
+ 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 (*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->MountPointReparseBuffer.SubstituteNameLength =
- wcslen(nativeTarget) * sizeof(WCHAR);
+ reparseBuffer->SymbolicLinkReparseBuffer.SubstituteNameLength =
+ wcslen(nativeTarget) * sizeof(WCHAR);
reparseBuffer->Reserved = 0;
- reparseBuffer->MountPointReparseBuffer.PrintNameLength = 0;
- reparseBuffer->MountPointReparseBuffer.PrintNameOffset =
- reparseBuffer->MountPointReparseBuffer.SubstituteNameLength
- + sizeof(WCHAR);
- memcpy(reparseBuffer->MountPointReparseBuffer.PathBuffer, nativeTarget,
- sizeof(WCHAR)
- + reparseBuffer->MountPointReparseBuffer.SubstituteNameLength);
- reparseBuffer->ReparseDataLength =
- reparseBuffer->MountPointReparseBuffer.SubstituteNameLength+12;
-
- return NativeWriteReparse(linkDirPath, reparseBuffer);
+ 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;
+
+ return NativeWriteReparse(LinkDirectory, reparseBuffer);
}
/*
*--------------------------------------------------------------------
*
- * 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.
+ * 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.
*--------------------------------------------------------------------
*/
-
-int
-TclWinSymLinkCopyDirectory(
- const TCHAR *linkOrigPath, /* Existing junction - reparse point */
- const TCHAR *linkCopyPath) /* Will become a duplicate junction */
+int
+TclWinSymLinkCopyDirectory(LinkOriginal, LinkCopy)
+ 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;
-
- if (NativeReadReparse(linkOrigPath, reparseBuffer, GENERIC_READ)) {
+ REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy;
+
+ if (NativeReadReparse(LinkOriginal, reparseBuffer, GENERIC_READ)) {
return -1;
}
- return NativeWriteReparse(linkCopyPath, reparseBuffer);
+ return NativeWriteReparse(LinkCopy, reparseBuffer);
}
/*
*--------------------------------------------------------------------
*
- * 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.
+ * 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.
*--------------------------------------------------------------------
*/
-
-int
-TclWinSymLinkDelete(
- const TCHAR *linkOrigPath,
- int linkOnly)
+int
+TclWinSymLinkDelete(LinkOriginal, linkOnly)
+ 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)(linkOrigPath, GENERIC_WRITE, 0,
- NULL, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
+ hFile = (*tclWinProcs->createFileProc)(LinkOriginal, GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
- if (!DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, reparseBuffer,
- 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)(linkOrigPath);
+ (*tclWinProcs->removeDirectoryProc)(LinkOriginal);
}
return 0;
}
@@ -547,136 +451,123 @@ TclWinSymLinkDelete(
/*
*--------------------------------------------------------------------
*
- * WinReadLinkDirectory --
+ * WinReadLinkDirectory
*
- * 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.
+ * 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.
*--------------------------------------------------------------------
*/
-
-static Tcl_Obj *
-WinReadLinkDirectory(
- const TCHAR *linkDirPath)
+static Tcl_Obj*
+WinReadLinkDirectory(LinkDirectory)
+ CONST TCHAR* LinkDirectory;
{
- int attr, len, offset;
+ int attr;
DUMMY_REPARSE_BUFFER dummy;
- REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
- Tcl_Obj *retVal;
- Tcl_DString ds;
- const char *copy;
-
- attr = (*tclWinProcs->getFileAttributesProc)(linkDirPath);
+ REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER*)&dummy;
+
+ attr = (*tclWinProcs->getFileAttributesProc)(LinkDirectory);
if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {
- goto invalidError;
- }
- if (NativeReadReparse(linkDirPath, reparseBuffer, 0)) {
+ Tcl_SetErrno(EINVAL);
return NULL;
}
-
+ if (NativeReadReparse(LinkDirectory, reparseBuffer, 0)) {
+ return NULL;
+ }
+
switch (reparseBuffer->ReparseTag) {
- case 0x80000000|IO_REPARSE_TAG_SYMBOLIC_LINK:
- case IO_REPARSE_TAG_SYMBOLIC_LINK:
- case IO_REPARSE_TAG_MOUNT_POINT:
- /*
- * 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.
- */
-
- offset = 0;
- if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') {
- /*
- * Check whether this is a mounted volume.
+ 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 (wcsncmp(reparseBuffer->MountPointReparseBuffer.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->MountPointReparseBuffer.PathBuffer[1]=L'\\';
-
- /*
- * Check if a corresponding drive letter exists, and use that
- * if it is found
- */
-
- drive = TclWinDriveLetterForVolMountPoint(
- reparseBuffer->MountPointReparseBuffer.PathBuffer);
- if (drive != -1) {
- char driveSpec[3] = {
- '\0', ':', '\0'
- };
-
- driveSpec[0] = drive;
- retVal = Tcl_NewStringObj(driveSpec,2);
- Tcl_IncrRefCount(retVal);
- return retVal;
+ 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] = {
+ drive, ':', '\0'
+ };
+ 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;
}
-
- /*
- * 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.
- */
-
- goto invalidError;
- } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer
- .PathBuffer, L"\\\\?\\",4) == 0) {
- /*
- * Strip off the prefix.
- */
-
- offset = 4;
- } else if (wcsncmp(reparseBuffer->MountPointReparseBuffer
- .PathBuffer, L"\\??\\",4) == 0) {
- /*
- * Strip off the prefix.
- */
-
- offset = 4;
}
- }
-
- Tcl_WinTCharToUtf((const char *)
- reparseBuffer->MountPointReparseBuffer.PathBuffer,
- (int) reparseBuffer->MountPointReparseBuffer
+
+ 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;
+
+ copy = Tcl_DStringValue(&ds)+offset;
+ len = Tcl_DStringLength(&ds)-offset;
+ retVal = Tcl_NewStringObj(copy,len);
+ Tcl_IncrRefCount(retVal);
+ Tcl_DStringFree(&ds);
+ return retVal;
+ }
}
-
- invalidError:
Tcl_SetErrno(EINVAL);
return NULL;
}
@@ -684,56 +575,43 @@ WinReadLinkDirectory(
/*
*--------------------------------------------------------------------
*
- * NativeReadReparse --
+ * NativeReadReparse
*
- * Read the junction/reparse information from a given NTFS directory.
- *
- * Assumption that linkDirPath is a valid, existing directory.
- *
- * Returns:
- * Zero on success.
+ * Read the junction/reparse information from a given NTFS directory.
*
+ * Assumption that LinkDirectory is a valid, existing directory.
+ *
+ * Returns zero on success.
*--------------------------------------------------------------------
*/
-
-static int
-NativeReadReparse(
- const TCHAR *linkDirPath, /* The junction to read */
- REPARSE_DATA_BUFFER *buffer,/* Pointer to buffer. Cannot be NULL */
- DWORD desiredAccess)
+static int
+NativeReadReparse(LinkDirectory, buffer, desiredAccess)
+ CONST TCHAR* LinkDirectory; /* The junction to read */
+ REPARSE_DATA_BUFFER* buffer; /* Pointer to buffer. Cannot be NULL */
+ DWORD desiredAccess;
{
HANDLE hFile;
DWORD returnedLength;
-
- hFile = (*tclWinProcs->createFileProc)(linkDirPath, desiredAccess, 0,
- NULL, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
-
+
+ hFile = (*tclWinProcs->createFileProc)(LinkDirectory, desiredAccess, 0,
+ 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;
@@ -744,69 +622,48 @@ NativeReadReparse(
/*
*--------------------------------------------------------------------
*
- * NativeWriteReparse --
- *
- * Write the reparse information for a given directory.
- *
- * Assumption that LinkDirectory does not exist.
+ * NativeWriteReparse
*
+ * Write the reparse information for a given directory.
+ *
+ * Assumption that LinkDirectory does not exist.
*--------------------------------------------------------------------
*/
-
-static int
-NativeWriteReparse(
- const TCHAR *linkDirPath,
- REPARSE_DATA_BUFFER *buffer)
+static int
+NativeWriteReparse(LinkDirectory, buffer)
+ CONST TCHAR* LinkDirectory;
+ REPARSE_DATA_BUFFER* buffer;
{
HANDLE hFile;
DWORD returnedLength;
-
- /*
- * Create the directory - it must not already exist.
- */
-
- if ((*tclWinProcs->createDirectoryProc)(linkDirPath, NULL) == 0) {
- /*
- * Error creating directory.
- */
-
+
+ /* Create the directory - it must not already exist */
+ if ((*tclWinProcs->createDirectoryProc)(LinkDirectory, NULL) == 0) {
+ /* Error creating directory */
TclWinConvertError(GetLastError());
return -1;
}
- hFile = (*tclWinProcs->createFileProc)(linkDirPath, GENERIC_WRITE, 0,
- NULL, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = (*tclWinProcs->createFileProc)(LinkDirectory, GENERIC_WRITE, 0,
+ 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)(linkDirPath);
+ (*tclWinProcs->removeDirectoryProc)(LinkDirectory);
return -1;
}
CloseHandle(hFile);
-
- /*
- * We succeeded.
- */
-
+ /* We succeeded */
return 0;
}
@@ -815,26 +672,39 @@ NativeWriteReparse(
*
* TclpFindExecutable --
*
- * This function computes the absolute path name of the current
- * application.
+ * This procedure computes the absolute path name of the current
+ * application, given its argv[0] value.
*
* Results:
- * None.
+ * A clean UTF string that is the path to the executable. At this
+ * point we may not know the system encoding, but we convert the
+ * string value to UTF-8 using core Windows functions. The path name
+ * contains ASCII string and '/' chars do not conflict with other UTF
+ * chars.
*
* Side effects:
- * The computed path is stored.
+ * The variable tclNativeExecutableName gets filled in with the file
+ * name for the application, if we figured it out. If we couldn't
+ * figure it out, tclNativeExecutableName is set to NULL.
*
*---------------------------------------------------------------------------
*/
-void
-TclpFindExecutable(
- const char *argv0) /* The value of the application's argv[0]
+char *
+TclpFindExecutable(argv0)
+ CONST char *argv0; /* The value of the application's argv[0]
* (native). */
{
WCHAR wName[MAX_PATH];
char name[MAX_PATH * TCL_UTF_MAX];
+ if (argv0 == NULL) {
+ return NULL;
+ }
+ if (tclNativeExecutableName != NULL) {
+ return tclNativeExecutableName;
+ }
+
/*
* Under Windows we ignore argv0, and return the path for the file used to
* create this process.
@@ -842,17 +712,16 @@ TclpFindExecutable(
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);
+ } else {
+ WideCharToMultiByte(CP_UTF8, 0, wName, -1,
+ name, sizeof(name), NULL, NULL);
}
- WideCharToMultiByte(CP_UTF8, 0, wName, -1, name, sizeof(name), NULL,NULL);
- TclWinNoBackslash(name);
- TclSetObjNameOfExecutable(Tcl_NewStringObj(name, -1), NULL);
+ tclNativeExecutableName = ckalloc((unsigned) (strlen(name) + 1));
+ strcpy(tclNativeExecutableName, name);
+
+ TclWinNoBackslash(tclNativeExecutableName);
+ return tclNativeExecutableName;
}
/*
@@ -860,53 +729,42 @@ TclpFindExecutable(
*
* 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(
- Tcl_Interp *interp, /* Interpreter to receive errors. */
- Tcl_Obj *resultPtr, /* List object to lappend results. */
- Tcl_Obj *pathPtr, /* Contains path to directory to search. */
- const char *pattern, /* Pattern to match against. */
- Tcl_GlobTypeData *types) /* Object containing list of acceptable types.
+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. */
+ CONST char *pattern; /* Pattern to match against. */
+ Tcl_GlobTypeData *types; /* Object containing list of acceptable types.
* May be NULL. In particular the directory
* flag is very important. */
{
- const TCHAR *native;
-
- if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {
- /*
- * The native filesystem never adds mounts.
- */
-
- return TCL_OK;
- }
+ CONST TCHAR *native;
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);
+ CONST char *str = Tcl_GetStringFromObj(norm,&len);
+ native = (CONST TCHAR*) Tcl_FSGetNativePath(pathPtr);
+
if (tclWinProcs->getFileAttributesExProc == NULL) {
attr = (*tclWinProcs->getFileAttributesProc)(native);
if (attr == 0xffffffff) {
@@ -920,8 +778,8 @@ TclpMatchInDirectory(
}
attr = data.dwFileAttributes;
}
-
- if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) {
+ if (NativeMatchType(WinIsDrive(str,len), attr,
+ native, types)) {
Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
}
}
@@ -930,127 +788,94 @@ TclpMatchInDirectory(
DWORD attr;
HANDLE handle;
WIN32_FIND_DATAT data;
- const char *dirName; /* UTF-8 dir name, later with pattern
- * appended. */
+ CONST char *dirName;
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 */
+ Tcl_DString dsOrig; /* utf-8 encoding of dir */
+ Tcl_DString dirString; /* utf-8 encoding of dir with \'s */
Tcl_Obj *fileNamePtr;
- char lastChar;
/*
- * Get the normalized path representation (the main thing is we dont
- * want any '~' sequences).
+ * Convert the path to normalized form since some interfaces only
+ * accept backslashes. Also, ensure that the directory ends with a
+ * separator character.
*/
- fileNamePtr = Tcl_FSGetNormalizedPath(interp, pathPtr);
+ fileNamePtr = Tcl_FSGetTranslatedPath(interp, pathPtr);
if (fileNamePtr == NULL) {
return TCL_ERROR;
}
+ Tcl_DStringInit(&dsOrig);
+ dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength);
+ Tcl_DStringAppend(&dsOrig, dirName, dirLength);
+
+ Tcl_DStringInit(&dirString);
+ if (dirLength == 0) {
+ Tcl_DStringAppend(&dirString, ".\\", 2);
+ } else {
+ char *p;
+ Tcl_DStringAppend(&dirString, dirName, dirLength);
+ for (p = Tcl_DStringValue(&dirString); *p != '\0'; p++) {
+ if (*p == '/') {
+ *p = '\\';
+ }
+ }
+ p--;
+ /* Make sure we have a trailing directory delimiter */
+ if ((*p != '\\') && (*p != ':')) {
+ Tcl_DStringAppend(&dirString, "\\", 1);
+ Tcl_DStringAppend(&dsOrig, "/", 1);
+ dirLength++;
+ }
+ }
+ dirName = Tcl_DStringValue(&dirString);
+ Tcl_DecrRefCount(fileNamePtr);
+
/*
- * Verify that the specified path exists and is actually a directory.
+ * First verify that the specified path is actually a directory.
*/
- native = Tcl_FSGetNativePath(pathPtr);
- if (native == NULL) {
- return TCL_OK;
- }
+ native = Tcl_WinUtfToTChar(dirName, Tcl_DStringLength(&dirString),
+ &ds);
attr = (*tclWinProcs->getFileAttributesProc)(native);
+ Tcl_DStringFree(&ds);
if ((attr == 0xffffffff) || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
+ Tcl_DStringFree(&dirString);
return TCL_OK;
}
/*
- * Build up the directory name for searching, including a trailing
- * directory separator.
+ * We need to check all files in the directory, so append a *.*
+ * to the path.
*/
- 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);
- dirLength++;
- }
- 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.
- */
-
- 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.
- */
-
- dirName = Tcl_DStringAppend(&dsOrig, pattern, -1);
- } else {
- dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3);
- }
-
+ dirName = Tcl_DStringAppend(&dirString, "*.*", 3);
native = Tcl_WinUtfToTChar(dirName, -1, &ds);
- 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);
- }
+ handle = (*tclWinProcs->findFirstFileProc)(native, &data);
if (handle == INVALID_HANDLE_VALUE) {
- DWORD err = GetLastError();
+ TclWinConvertError(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.
- */
-
- Tcl_DStringFree(&dsOrig);
- return TCL_OK;
- }
-
- TclWinConvertError(err);
- if (interp != NULL) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "couldn't read directory \"",
- Tcl_DStringValue(&dsOrig), "\": ",
- Tcl_PosixError(interp), NULL);
- }
+ Tcl_DStringFree(&dirString);
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "couldn't read directory \"",
+ 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.
- */
-
- 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] == '.')
@@ -1061,53 +886,51 @@ TclpMatchInDirectory(
}
/*
- * 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 {
- const char *utfname;
- int checkDrive = 0, isDrive;
+ CONST char *utfname;
+ int checkDrive = 0;
+ int isDrive;
DWORD attr;
-
+
if (tclWinProcs->useWide) {
- native = (const TCHAR *) data.w.cFileName;
+ native = (CONST TCHAR *) data.w.cFileName;
attr = data.w.dwFileAttributes;
} else {
- native = (const TCHAR *) data.a.cFileName;
+ 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.
*/
@@ -1118,7 +941,7 @@ TclpMatchInDirectory(
*/
if (checkDrive) {
- const char *fullname = Tcl_DStringAppend(&dsOrig, utfname,
+ CONST char *fullname = Tcl_DStringAppend(&dsOrig, utfname,
Tcl_DStringLength(&ds));
isDrive = WinIsDrive(fullname, Tcl_DStringLength(&dsOrig));
Tcl_DStringSetLength(&dsOrig, dirLength);
@@ -1126,7 +949,7 @@ TclpMatchInDirectory(
isDrive = 0;
}
if (NativeMatchType(isDrive, attr, native, types)) {
- Tcl_ListObjAppendElement(interp, resultPtr,
+ Tcl_ListObjAppendElement(interp, resultPtr,
TclNewFSPathObj(pathPtr, utfname,
Tcl_DStringLength(&ds)));
}
@@ -1135,38 +958,33 @@ TclpMatchInDirectory(
/*
* Free ds here to ensure that native is valid above.
*/
-
Tcl_DStringFree(&ds);
} while ((*tclWinProcs->findNextFileProc)(handle, &data) == TRUE);
FindClose(handle);
+ Tcl_DStringFree(&dirString);
Tcl_DStringFree(&dsOrig);
return TCL_OK;
}
}
-/*
- * 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) {
@@ -1176,95 +994,74 @@ 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 */
+static int WinIsReserved(
+ 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 (!strcasecmp(path, "prn") || !strcasecmp(path, "nul")
- || !strcasecmp(path, "aux")) {
- /*
- * Have match for 'prn', 'nul' or 'aux'.
- */
-
+ } 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' */
return 3;
}
return 0;
@@ -1272,108 +1069,102 @@ 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 calls 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 calls 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)) ||
+ 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))
#ifdef S_ISSOCK
- ((types->type&TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) ||
+ || ((types->type & TCL_GLOB_TYPE_SOCK) &&
+ S_ISSOCK(st_mode))
#endif
- ((types->type&TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode))) {
- /*
- * Do nothing - this file is ok.
- */
+ ) {
+ /* Do nothing -- this file is ok */
} else {
#ifdef S_ISLNK
if (types->type & TCL_GLOB_TYPE_LINK) {
@@ -1385,8 +1176,8 @@ NativeMatchType(
#endif
return 0;
}
- }
- }
+ }
+ }
return 1;
}
@@ -1401,9 +1192,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.
@@ -1412,15 +1203,16 @@ NativeMatchType(
*/
char *
-TclpGetUserHome(
- const char *name, /* User name for desired home directory. */
- Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
- * name of user's home directory. */
+TclpGetUserHome(name, bufferPtr)
+ CONST char *name; /* User name for desired home directory. */
+ Tcl_DString *bufferPtr; /* Uninitialized or free DString filled
+ * with name of user's home directory. */
{
char *result;
HINSTANCE netapiInst;
result = NULL;
+
Tcl_DStringInit(bufferPtr);
netapiInst = LoadLibraryA("netapi32.dll");
@@ -1431,17 +1223,17 @@ TclpGetUserHome(
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)) {
- USER_INFO_1 *uiPtr, **uiPtrPtr = &uiPtr;
+ USER_INFO_1 *uiPtr;
Tcl_DString ds;
int nameLen, badDomain;
char *domain;
- WCHAR *wName, *wHomeDir, *wDomain, **wDomainPtr = &wDomain;
+ WCHAR *wName, *wHomeDir, *wDomain;
WCHAR buf[MAX_PATH];
badDomain = 0;
@@ -1451,23 +1243,23 @@ TclpGetUserHome(
if (domain != NULL) {
Tcl_DStringInit(&ds);
wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds);
- badDomain = (netGetDCNameProc)(NULL, wName,
- (LPBYTE *) wDomainPtr);
+ badDomain = (*netGetDCNameProc)(NULL, wName,
+ (LPBYTE *) &wDomain);
Tcl_DStringFree(&ds);
nameLen = domain - name;
}
if (badDomain == 0) {
Tcl_DStringInit(&ds);
wName = Tcl_UtfToUniCharDString(name, nameLen, &ds);
- if ((netUserGetInfoProc)(wDomain, wName, 1,
- (LPBYTE *) uiPtrPtr) == 0) {
+ if ((*netUserGetInfoProc)(wDomain, wName, 1,
+ (LPBYTE *) &uiPtr) == 0) {
wHomeDir = uiPtr->usri1_home_dir;
if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) {
Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir),
bufferPtr);
} else {
- /*
- * User exists but has no home dir. Return
+ /*
+ * User exists but has no home dir. Return
* "{Windows Drive}:/users/default".
*/
@@ -1488,20 +1280,20 @@ TclpGetUserHome(
}
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);
@@ -1521,7 +1313,7 @@ TclpGetUserHome(
*
* This function replaces the library version of access(), fixing the
* following bugs:
- *
+ *
* 1. access() returns that all files have execute permission.
*
* Results:
@@ -1535,7 +1327,7 @@ TclpGetUserHome(
static int
NativeAccess(
- const TCHAR *nativePath, /* Path of file to access, native encoding. */
+ CONST TCHAR *nativePath, /* Path of file to access (UTF-8). */
int mode) /* Permission setting. */
{
DWORD attr;
@@ -1603,7 +1395,8 @@ NativeAccess(
SID_IDENTIFIER_AUTHORITY samba_unmapped = {{0, 0, 0, 0, 0, 22}};
GENERIC_MAPPING genMap;
HANDLE hToken = NULL;
- DWORD desiredAccess = 0, grantedAccess = 0;
+ DWORD desiredAccess = 0;
+ DWORD grantedAccess = 0;
BOOL accessYesNo = FALSE;
PRIVILEGE_SET privSet;
DWORD privSetSize = sizeof(PRIVILEGE_SET);
@@ -1630,12 +1423,12 @@ NativeAccess(
* to EACCES - just what we want!
*/
- TclWinConvertError((DWORD) error);
+ TclWinConvertError((DWORD)error);
return -1;
}
/*
- * Now size contains the size of buffer needed.
+ * Now size contains the size of buffer needed
*/
sdPtr = (SECURITY_DESCRIPTOR *) HeapAlloc(GetProcessHeap(), 0, size);
@@ -1645,7 +1438,7 @@ NativeAccess(
}
/*
- * Call GetFileSecurity() for real.
+ * Call GetFileSecurity() for real
*/
if (!(*tclWinProcs->getFileSecurityProc)(nativePath,
@@ -1680,28 +1473,28 @@ NativeAccess(
}
/*
- * Perform security impersonation of the user and open the resulting
- * thread token.
+ * Perform security impersonation of the user and open the
+ * resulting thread token.
*/
if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) {
/*
* 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.
*/
-
+
goto accessError;
}
-
+
(*tclWinProcs->revertToSelfProc)();
-
+
/*
* Setup desiredAccess according to the access priveleges we are
* checking.
@@ -1717,12 +1510,12 @@ NativeAccess(
desiredAccess |= FILE_GENERIC_EXECUTE;
}
- memset(&genMap, 0x0, sizeof(GENERIC_MAPPING));
+ memset (&genMap, 0x0, sizeof (GENERIC_MAPPING));
genMap.GenericRead = FILE_GENERIC_READ;
genMap.GenericWrite = FILE_GENERIC_WRITE;
genMap.GenericExecute = FILE_GENERIC_EXECUTE;
genMap.GenericAll = FILE_ALL_ACCESS;
-
+
/*
* Perform access check using the token.
*/
@@ -1749,13 +1542,12 @@ NativeAccess(
* Clean up.
*/
- HeapFree(GetProcessHeap(), 0, sdPtr);
+ HeapFree(GetProcessHeap (), 0, sdPtr);
CloseHandle(hToken);
if (!accessYesNo) {
Tcl_SetErrno(EACCES);
return -1;
}
-
}
return 0;
}
@@ -1765,22 +1557,25 @@ NativeAccess(
*
* 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(
- const TCHAR *nativePath)
+NativeIsExec(nativePath)
+ CONST TCHAR *nativePath;
{
if (tclWinProcs->useWide) {
- const WCHAR *path = (const WCHAR *) nativePath;
- int len = wcslen(path);
+ CONST WCHAR *path;
+ int len;
+
+ path = (CONST WCHAR*)nativePath;
+ len = wcslen(path);
if (len < 5) {
return 0;
@@ -1793,31 +1588,26 @@ NativeIsExec(
/*
* 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)) {
+ if ((_wcsicmp(path+len-3,L"exe") == 0)
+ || (_wcsicmp(path+len-3,L"com") == 0)
+ || (_wcsicmp(path+len-3,L"bat") == 0)) {
return 1;
}
} else {
- const char *p;
+ CONST char *p;
- /*
- * We are only looking for pure ascii.
- */
+ /* We are only looking for pure ascii */
- p = strrchr((const char *) nativePath, '.');
+ 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 ((strcasecmp(p, "exe") == 0)
- || (strcasecmp(p, "com") == 0)
- || (strcasecmp(p, "bat") == 0)) {
+ if ((stricmp(p, "exe") == 0)
+ || (stricmp(p, "com") == 0)
+ || (stricmp(p, "bat") == 0)) {
/*
* File that ends with .exe, .com, or .bat is executable.
*/
@@ -1840,20 +1630,19 @@ NativeIsExec(
* See chdir() documentation.
*
* Side effects:
- * See chdir() documentation.
+ * See chdir() documentation.
*
*----------------------------------------------------------------------
*/
-int
-TclpObjChdir(
- Tcl_Obj *pathPtr) /* Path to new working directory. */
+int
+TclpObjChdir(pathPtr)
+ Tcl_Obj *pathPtr; /* Path to new working directory. */
{
int result;
- const TCHAR *nativePath;
-
- nativePath = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
+ CONST TCHAR *nativePath;
+ nativePath = (CONST TCHAR *) Tcl_FSGetNativePath(pathPtr);
result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath);
if (result == 0) {
@@ -1868,16 +1657,15 @@ TclpObjChdir(
*
* 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().
*
* 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.
@@ -1885,11 +1673,11 @@ TclpObjChdir(
*----------------------------------------------------------------------
*/
-const char *
-TclpGetCwd(
- Tcl_Interp *interp, /* If non-NULL, used for error reporting. */
- Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
- * name of current directory. */
+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. */
{
WCHAR buffer[MAX_PATH];
char *p;
@@ -1897,8 +1685,9 @@ TclpGetCwd(
if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) {
TclWinConvertError(GetLastError());
if (interp != NULL) {
- Tcl_AppendResult(interp, "error getting working directory name: ",
- Tcl_PosixError(interp), NULL);
+ Tcl_AppendResult(interp,
+ "error getting working directory name: ",
+ Tcl_PosixError(interp), (char *) NULL);
}
return NULL;
}
@@ -1911,7 +1700,7 @@ TclpGetCwd(
WCHAR *native;
native = (WCHAR *) buffer;
- if ((native[0] != '\0') && (native[1] == ':')
+ if ((native[0] != '\0') && (native[1] == ':')
&& (native[2] == '\\') && (native[3] == '\\')) {
native += 2;
}
@@ -1920,7 +1709,7 @@ TclpGetCwd(
char *native;
native = (char *) buffer;
- if ((native[0] != '\0') && (native[1] == ':')
+ if ((native[0] != '\0') && (native[1] == ':')
&& (native[2] == '\\') && (native[3] == '\\')) {
native += 2;
}
@@ -1930,7 +1719,7 @@ TclpGetCwd(
/*
* Convert to forward slashes for easier use in scripts.
*/
-
+
for (p = Tcl_DStringValue(bufferPtr); *p != '\0'; p++) {
if (*p == '\\') {
*p = '/';
@@ -1939,21 +1728,38 @@ TclpGetCwd(
return Tcl_DStringValue(bufferPtr);
}
-int
-TclpObjStat(
- Tcl_Obj *pathPtr, /* Path of file to stat. */
- Tcl_StatBuf *statPtr) /* Filled with results of stat call. */
+int
+TclpObjStat(pathPtr, statPtr)
+ 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.
+ */
+
+ transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
+ if (transPtr == NULL || (strpbrk(Tcl_GetString(transPtr), "?*") != NULL)) {
+ if (transPtr != NULL) {
+ Tcl_DecrRefCount(transPtr);
+ }
+ Tcl_SetErrno(ENOENT);
+ return -1;
+ }
+ 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);
+ return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 0);
}
/*
@@ -1961,8 +1767,8 @@ TclpObjStat(
*
* 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.
@@ -1979,97 +1785,31 @@ TclpObjStat(
*----------------------------------------------------------------------
*/
-static int
-NativeStat(
- 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' */
+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' */
{
+ Tcl_DString ds;
DWORD attr;
- int dev, nlink = 1;
+ WCHAR nativeFullPath[MAX_PATH];
+ TCHAR *nativePart;
+ CONST char *fullPath;
+ int dev;
unsigned short mode;
- unsigned int inode = 0;
- HANDLE fileHandle;
-
- /*
- * If we can use 'createFile' on this, then we can use the resulting
- * fileHandle to read more information (nlink, ino) than we can get from
- * other attributes reading APIs. If not, then we try to fall back on the
- * 'getFileAttributesExProc', and if that isn't available, then on even
- * simpler routines.
- */
-
- fileHandle = (tclWinProcs->createFileProc)(nativePath, GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
- FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
-
- if (fileHandle != INVALID_HANDLE_VALUE) {
- BY_HANDLE_FILE_INFORMATION data;
-
- if (GetFileInformationByHandle(fileHandle,&data) != TRUE) {
- CloseHandle(fileHandle);
- Tcl_SetErrno(ENOENT);
- return -1;
- }
- CloseHandle(fileHandle);
-
- attr = data.dwFileAttributes;
-
- statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
- (((Tcl_WideInt) data.nFileSizeHigh) << 32);
- statPtr->st_atime = ToCTime(data.ftLastAccessTime);
- statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
- statPtr->st_ctime = ToCTime(data.ftCreationTime);
-
- /*
- * On Unix, for directories, nlink apparently depends on the number of
- * files in the directory. We could calculate that, but it would be a
- * bit of a performance penalty, I think. Hence we just use what
- * Windows gives us, which is the same as Unix for files, at least.
- */
-
- nlink = data.nNumberOfLinks;
-
- /*
- * Unfortunately our stat definition's inode field (unsigned short)
- * will throw away most of the precision we have here, which means we
- * can't rely on inode as a unique identifier of a file. We'd really
- * like to do something like how we handle 'st_size'.
- */
-
- inode = data.nFileIndexHigh | data.nFileIndexLow;
- } else if (tclWinProcs->getFileAttributesExProc != NULL) {
- /*
- * Fall back on the less capable routines. This means no nlink or ino.
- */
-
- WIN32_FILE_ATTRIBUTE_DATA data;
-
- if ((*tclWinProcs->getFileAttributesExProc)(nativePath,
- GetFileExInfoStandard, &data) != TRUE) {
- Tcl_SetErrno(ENOENT);
- return -1;
- }
-
- attr = data.dwFileAttributes;
-
- statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
- (((Tcl_WideInt) data.nFileSizeHigh) << 32);
- statPtr->st_atime = ToCTime(data.ftLastAccessTime);
- statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
- statPtr->st_ctime = ToCTime(data.ftCreationTime);
- } else {
- /*
- * We don't have the faster attributes proc, so we're probably running
- * on Win95.
- */
-
+
+ if (tclWinProcs->getFileAttributesExProc == NULL) {
+ /*
+ * 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.
*/
@@ -2080,9 +1820,9 @@ NativeStat(
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));
@@ -2091,95 +1831,131 @@ NativeStat(
FindClose(handle);
}
+
+ (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH, nativeFullPath,
+ &nativePart);
+
+ fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds);
+
+ dev = -1;
+ if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
+ CONST char *p;
+ DWORD dw;
+ CONST TCHAR *nativeVol;
+ Tcl_DString volString;
+
+ p = strchr(fullPath + 2, '\\');
+ p = strchr(p + 1, '\\');
+ if (p == NULL) {
+ /*
+ * Add terminating backslash to fullpath or
+ * GetVolumeInformation() won't work.
+ */
+
+ fullPath = Tcl_DStringAppend(&ds, "\\", 1);
+ p = fullPath + Tcl_DStringLength(&ds);
+ } else {
+ p++;
+ }
+ nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);
+ dw = (DWORD) -1;
+ (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw,
+ NULL, NULL, NULL, 0);
+ /*
+ * GetFullPathName() turns special devices like "NUL" into
+ * "\\.\NUL", but GetVolumeInformation() returns failure for
+ * "\\.\NUL". This will cause "NUL" to get a drive number of
+ * -1, which makes about as much sense as anything since the
+ * special devices don't live on any drive.
+ */
+
+ dev = dw;
+ Tcl_DStringFree(&volString);
+ } else if ((fullPath[0] != '\0') && (fullPath[1] == ':')) {
+ dev = Tcl_UniCharToLower(fullPath[0]) - 'a';
+ }
+ Tcl_DStringFree(&ds);
+
attr = data.a.dwFileAttributes;
- statPtr->st_size = ((Tcl_WideInt) data.a.nFileSizeLow) |
- (((Tcl_WideInt) data.a.nFileSizeHigh) << 32);
+ statPtr->st_size = ((Tcl_WideInt)data.a.nFileSizeLow) |
+ (((Tcl_WideInt)data.a.nFileSizeHigh) << 32);
statPtr->st_atime = ToCTime(data.a.ftLastAccessTime);
statPtr->st_mtime = ToCTime(data.a.ftLastWriteTime);
statPtr->st_ctime = ToCTime(data.a.ftCreationTime);
- }
-
- dev = NativeDev(nativePath);
- mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
-
- statPtr->st_dev = (dev_t) dev;
- statPtr->st_ino = inode;
- statPtr->st_mode = mode;
- statPtr->st_nlink = nlink;
- statPtr->st_uid = 0;
- statPtr->st_gid = 0;
- statPtr->st_rdev = (dev_t) dev;
- return 0;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * NativeDev --
- *
- * Calculate just the 'st_dev' field of a 'stat' structure.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-NativeDev(
- const TCHAR *nativePath) /* Full path of file to stat */
-{
- int dev;
- Tcl_DString ds;
- WCHAR nativeFullPath[MAX_PATH];
- TCHAR *nativePart;
- const char *fullPath;
+ } else {
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ 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);
+ fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds);
- if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
- const char *p;
- DWORD dw;
- const TCHAR *nativeVol;
- Tcl_DString volString;
+ dev = -1;
+ if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
+ CONST char *p;
+ DWORD dw;
+ CONST TCHAR *nativeVol;
+ Tcl_DString volString;
+
+ p = strchr(fullPath + 2, '\\');
+ p = strchr(p + 1, '\\');
+ if (p == NULL) {
+ /*
+ * Add terminating backslash to fullpath or
+ * GetVolumeInformation() won't work.
+ */
- p = strchr(fullPath + 2, '\\');
- p = strchr(p + 1, '\\');
- if (p == NULL) {
+ fullPath = Tcl_DStringAppend(&ds, "\\", 1);
+ p = fullPath + Tcl_DStringLength(&ds);
+ } else {
+ p++;
+ }
+ nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);
+ dw = (DWORD) -1;
+ (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw,
+ NULL, NULL, NULL, 0);
/*
- * Add terminating backslash to fullpath or GetVolumeInformation()
- * won't work.
+ * 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.
*/
- fullPath = Tcl_DStringAppend(&ds, "\\", 1);
- p = fullPath + Tcl_DStringLength(&ds);
- } else {
- p++;
+ dev = dw;
+ Tcl_DStringFree(&volString);
+ } else if ((fullPath[0] != '\0') && (fullPath[1] == ':')) {
+ dev = Tcl_UniCharToLower(fullPath[0]) - 'a';
}
- nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);
- 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.
- */
-
- dev = dw;
- Tcl_DStringFree(&volString);
- } else if ((fullPath[0] != '\0') && (fullPath[1] == ':')) {
- dev = Tcl_UniCharToLower(fullPath[0]) - 'a';
- } else {
- dev = -1;
+ Tcl_DStringFree(&ds);
+
+ attr = data.dwFileAttributes;
+
+ statPtr->st_size = ((Tcl_WideInt)data.nFileSizeLow) |
+ (((Tcl_WideInt)data.nFileSizeHigh) << 32);
+ statPtr->st_atime = ToCTime(data.ftLastAccessTime);
+ statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
+ statPtr->st_ctime = ToCTime(data.ftCreationTime);
}
- Tcl_DStringFree(&ds);
- return dev;
+ mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
+
+ statPtr->st_dev = (dev_t) dev;
+ statPtr->st_ino = 0;
+ statPtr->st_mode = mode;
+ statPtr->st_nlink = 1;
+ statPtr->st_uid = 0;
+ statPtr->st_gid = 0;
+ statPtr->st_rdev = (dev_t) dev;
+ return 0;
}
/*
@@ -2189,42 +1965,31 @@ NativeDev(
*
* 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.
- *
*----------------------------------------------------------------------
*/
-
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;
+ 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 & (S_IREAD|S_IWRITE|S_IEXEC)) >> 3;
mode |= (mode & (S_IREAD|S_IWRITE|S_IEXEC)) >> 6;
- return (unsigned short) mode;
+ return (unsigned short)mode;
}
/*
@@ -2249,8 +2014,8 @@ ToCTime(
convertedTime.LowPart = fileTime.dwLowDateTime;
convertedTime.HighPart = (LONG) fileTime.dwHighDateTime;
- return (time_t) ((convertedTime.QuadPart -
- (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000);
+ return (time_t) ((convertedTime.QuadPart
+ - (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000);
}
/*
@@ -2269,7 +2034,7 @@ ToCTime(
static void
FromCTime(
time_t posixTime,
- FILETIME *fileTime) /* UTC Time */
+ FILETIME* fileTime) /* UTC Time */
{
LARGE_INTEGER convertedTime;
convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000
@@ -2278,105 +2043,136 @@ FromCTime(
fileTime->dwHighDateTime = convertedTime.HighPart;
}
+#if 0
/*
- *---------------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*
- * TclpGetNativeCwd --
+ * TclWinResolveShortcut --
*
- * This function replaces the library version of getcwd().
+ * Resolve a potential Windows shortcut to get the actual file or
+ * directory in question.
*
* 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.
+ * 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:
- * None.
+ * Loads and unloads OLE package to determine if filename refers to
+ * a shortcut.
*
- *----------------------------------------------------------------------
+ *-------------------------------------------------------------------------
*/
-ClientData
-TclpGetNativeCwd(
- ClientData clientData)
+int
+TclWinResolveShortcut(bufferPtr)
+ Tcl_DString *bufferPtr; /* Holds name of file to resolve. On
+ * return, holds resolved file name. */
{
- WCHAR buffer[MAX_PATH];
+ HRESULT hres;
+ IShellLink *psl;
+ IPersistFile *ppf;
+ WIN32_FIND_DATA wfd;
+ WCHAR wpath[MAX_PATH];
+ char *path, *ext;
+ char realFileName[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) {
- return clientData;
- }
- } else {
- /*
- * ANSI representation when running on 95/98/ME.
- */
+ /*
+ * Windows system calls do not automatically resolve
+ * shortcuts like UNIX automatically will with symbolic links.
+ */
- if (strcmp((const char*) clientData, (const char*) buffer) == 0) {
- return clientData;
- }
- }
+ path = Tcl_DStringValue(bufferPtr);
+ ext = strrchr(path, '.');
+ if ((ext == NULL) || (stricmp(ext, ".lnk") != 0)) {
+ return 0;
}
- return TclNativeDupInternalRep((ClientData) buffer);
+ CoInitialize(NULL);
+ path = Tcl_DStringValue(bufferPtr);
+ realFileName[0] = '\0';
+ hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
+ &IID_IShellLink, &psl);
+ if (SUCCEEDED(hres)) {
+ hres = psl->lpVtbl->QueryInterface(psl, &IID_IPersistFile, &ppf);
+ if (SUCCEEDED(hres)) {
+ MultiByteToWideChar(CP_ACP, 0, path, -1, wpath, sizeof(wpath));
+ hres = ppf->lpVtbl->Load(ppf, wpath, STGM_READ);
+ if (SUCCEEDED(hres)) {
+ hres = psl->lpVtbl->Resolve(psl, NULL,
+ SLR_ANY_MATCH | SLR_NO_UI);
+ if (SUCCEEDED(hres)) {
+ hres = psl->lpVtbl->GetPath(psl, realFileName, MAX_PATH,
+ &wfd, 0);
+ }
+ }
+ ppf->lpVtbl->Release(ppf);
+ }
+ psl->lpVtbl->Release(psl);
+ }
+ CoUninitialize();
+
+ if (realFileName[0] != '\0') {
+ Tcl_DStringSetLength(bufferPtr, 0);
+ Tcl_DStringAppend(bufferPtr, realFileName, -1);
+ return 1;
+ }
+ return 0;
}
+#endif
-int
-TclpObjAccess(
- Tcl_Obj *pathPtr,
- int mode)
+Tcl_Obj*
+TclpObjGetCwd(interp)
+ Tcl_Interp *interp;
{
- return NativeAccess((const TCHAR *) Tcl_FSGetNativePath(pathPtr), mode);
+ Tcl_DString ds;
+ if (TclpGetCwd(interp, &ds) != NULL) {
+ Tcl_Obj *cwdPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
+ Tcl_IncrRefCount(cwdPtr);
+ Tcl_DStringFree(&ds);
+ return cwdPtr;
+ } else {
+ return NULL;
+ }
}
-
-int
-TclpObjLstat(
- Tcl_Obj *pathPtr,
- Tcl_StatBuf *statPtr)
+
+int
+TclpObjAccess(pathPtr, mode)
+ Tcl_Obj *pathPtr;
+ int mode;
+{
+ return NativeAccess((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), mode);
+}
+
+int
+TclpObjLstat(pathPtr, statPtr)
+ Tcl_Obj *pathPtr;
+ 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();
+ TclWinFlushDirtyChannels ();
- return NativeStat((const TCHAR *) Tcl_FSGetNativePath(pathPtr),
- statPtr, 1);
+ return NativeStat((CONST TCHAR*) Tcl_FSGetNativePath(pathPtr), statPtr, 1);
}
-
+
#ifdef S_IFLNK
-Tcl_Obj *
-TclpObjLink(
- Tcl_Obj *pathPtr,
- Tcl_Obj *toPtr,
- int linkAction)
+
+Tcl_Obj*
+TclpObjLink(pathPtr, toPtr, linkAction)
+ Tcl_Obj *pathPtr;
+ Tcl_Obj *toPtr;
+ int linkAction;
{
if (toPtr != NULL) {
int res;
- TCHAR *LinkTarget;
- TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
- Tcl_Obj *normalizedToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr);
-
- if (normalizedToPtr == NULL) {
- return NULL;
- }
-
- LinkTarget = (TCHAR *) Tcl_FSGetNativePath(normalizedToPtr);
-
+ TCHAR* LinkTarget = (TCHAR*)Tcl_FSGetNativePath(toPtr);
+ TCHAR* LinkSource = (TCHAR*)Tcl_FSGetNativePath(pathPtr);
if (LinkSource == NULL || LinkTarget == NULL) {
return NULL;
}
@@ -2387,65 +2183,60 @@ TclpObjLink(
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(
- Tcl_Obj *pathPtr)
+Tcl_Obj*
+TclpFilesystemPathType(pathObjPtr)
+ Tcl_Obj* pathObjPtr;
{
#define VOL_BUF_SIZE 32
int found;
WCHAR volType[VOL_BUF_SIZE];
- char *firstSeparator;
- const char *path;
- Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathPtr);
-
- if (normPath == NULL) {
- return NULL;
- }
+ char* firstSeparator;
+ CONST char *path;
+
+ Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathObjPtr);
+ 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(pathObjPtr), 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);
}
@@ -2454,118 +2245,91 @@ TclpFilesystemPathType(
} else {
Tcl_DString ds;
Tcl_Obj *objPtr;
-
- Tcl_WinTCharToUtf((const char *) volType, -1, &ds);
- objPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),
- Tcl_DStringLength(&ds));
+
+ Tcl_WinTCharToUtf((CONST char *)volType, -1, &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.
- */
-/* #define TclNORM_LONG_PATH */
/*
*---------------------------------------------------------------------------
*
* 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.
*
*---------------------------------------------------------------------------
*/
int
-TclpObjNormalizePath(
- Tcl_Interp *interp,
- Tcl_Obj *pathPtr,
- int nextCheckpoint)
+TclpObjNormalizePath(interp, pathPtr, nextCheckpoint)
+ Tcl_Interp *interp;
+ Tcl_Obj *pathPtr;
+ int nextCheckpoint;
{
char *lastValidPathEnd = NULL;
- Tcl_DString dsNorm; /* This will hold the normalized string. */
- char *path, *currentPathEndPosition;
+ /* This will hold the normalized string */
+ Tcl_DString dsNorm;
+ char *path;
+ char *currentPathEndPosition;
Tcl_Obj *temp = NULL;
Tcl_DStringInit(&dsNorm);
path = Tcl_GetString(pathPtr);
if (TclWinGetPlatformId() == VER_PLATFORM_WIN32_WINDOWS) {
- /*
- * We're on Win95, 98 or ME. There are two assumptions in this block
- * of code. First that the native (NULL) encoding is basically ascii,
- * and second that symbolic links are not possible. Both of these
- * assumptions appear to be true of these operating systems.
+ /*
+ * 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);
- if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
/*
- * Reached directory separator, or end of string.
+ * 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.
*/
-
- 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.
- */
-
if (isDrive) {
- if (GetFileAttributesA(nativePath)
- == INVALID_FILE_ATTRIBUTES) {
- /*
- * File doesn't exist.
- */
-
+ if (GetFileAttributesA(nativePath) == INVALID_FILE_ATTRIBUTES) {
+ /* File doesn't exist */
if (isDrive) {
int len = WinIsReserved(path);
-
if (len > 0) {
- /*
- * Actually it does exist - COM1, etc.
- */
-
+ /* Actually it does exist - COM1, etc */
int i;
-
- for (i=0 ; i<len ; i++) {
+ for (i=0;i<len;i++) {
if (nativePath[i] >= 'a') {
- ((char *) nativePath)[i] -= ('a'-'A');
+ ((char*)nativePath)[i] -= ('a' - 'A');
}
}
Tcl_DStringAppend(&dsNorm, nativePath, len);
@@ -2576,74 +2340,33 @@ TclpObjNormalizePath(
break;
}
if (nativePath[0] >= 'a') {
- ((char *) nativePath)[0] -= ('a' - '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) {
- if (*checkDots != '.') {
- checkDots = NULL;
- break;
- }
- checkDots++;
+ WIN32_FIND_DATA fData;
+ HANDLE handle;
+
+ handle = FindFirstFileA(nativePath, &fData);
+ if (handle == INVALID_HANDLE_VALUE) {
+ if (GetFileAttributesA(nativePath)
+ == INVALID_FILE_ATTRIBUTES) {
+ /* File doesn't exist */
+ Tcl_DStringFree(&ds);
+ break;
}
- }
- 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
- */
-
- Tcl_DStringAppend(&dsNorm, (TCHAR *)
- (nativePath + Tcl_DStringLength(&ds)-dotLen),
- dotLen);
+ /* This is usually the '/' in 'c:/' at end of string */
+ Tcl_DStringAppend(&dsNorm,"/", 1);
} else {
- /*
- * Normal path.
- */
-
- WIN32_FIND_DATA fData;
- HANDLE handle;
-
- handle = FindFirstFileA(nativePath, &fData);
- if (handle == INVALID_HANDLE_VALUE) {
- if (GetFileAttributesA(nativePath)
- == INVALID_FILE_ATTRIBUTES) {
- /*
- * File doesn't exist.
- */
-
- Tcl_DStringFree(&ds);
- break;
- }
-
- /*
- * This is usually the '/' in 'c:/' at end of
- * string.
- */
-
- Tcl_DStringAppend(&dsNorm,"/", 1);
+ char *nativeName;
+ if (fData.cFileName[0] != '\0') {
+ nativeName = fData.cFileName;
} else {
- char *nativeName;
-
- if (fData.cFileName[0] != '\0') {
- nativeName = fData.cFileName;
- } else {
- nativeName = fData.cAlternateFileName;
- }
- FindClose(handle);
- Tcl_DStringAppend(&dsNorm,"/", 1);
- Tcl_DStringAppend(&dsNorm,nativeName,-1);
+ nativeName = fData.cAlternateFileName;
}
+ FindClose(handle);
+ Tcl_DStringAppend(&dsNorm,"/", 1);
+ Tcl_DStringAppend(&dsNorm,nativeName,-1);
}
}
Tcl_DStringFree(&ds);
@@ -2651,21 +2374,16 @@ TclpObjNormalizePath(
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; something with an NT core).
- */
-
+ /* We're on WinNT or 2000 or XP */
int isDrive = 1;
Tcl_DString ds;
@@ -2675,42 +2393,28 @@ TclpObjNormalizePath(
}
while (1) {
char cur = *currentPathEndPosition;
-
- if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
- /*
- * Reached directory separator, or end of string.
- */
-
+ if ((cur == '/' || cur == 0) && (path != currentPathEndPosition)) {
+ /* Reached directory separator, or end of string */
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);
-
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];
-
+ for (i=0;i<len;i++) {
+ WCHAR wc = ((WCHAR*)nativePath)[i];
if (wc >= L'a') {
wc -= (L'a' - L'A');
- ((WCHAR *) nativePath)[i] = wc;
+ ((WCHAR*)nativePath)[i] = wc;
}
}
Tcl_DStringAppend(&dsNorm, nativePath,
- (int)(sizeof(WCHAR) * len));
+ sizeof(WCHAR)*len);
lastValidPathEnd = currentPathEndPosition;
}
}
@@ -2718,46 +2422,31 @@ TclpObjNormalizePath(
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);
- * nextCheckpoint = pathLen
- *
- * So, instead we have to start from the beginning.
- */
-
- nextCheckpoint = 0;
+ /* Read the reparse point ok */
+ /* Tcl_GetStringFromObj(to, &pathLen); */
+ nextCheckpoint = 0; /* pathLen */
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 = '/';
- }
+ if (*path == '\\') *path = '/';
}
path = Tcl_GetString(to);
currentPathEndPosition = path + nextCheckpoint;
@@ -2765,11 +2454,7 @@ TclpObjNormalizePath(
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);
@@ -2777,25 +2462,21 @@ TclpObjNormalizePath(
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];
+ WCHAR drive = ((WCHAR*)nativePath)[0];
if (drive >= L'a') {
- drive -= (L'a' - L'A');
- ((WCHAR *) nativePath)[0] = drive;
+ 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) {
@@ -2807,132 +2488,86 @@ TclpObjNormalizePath(
}
}
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.
+ 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
*/
-
- 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);
+
+ 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)));
}
}
}
-#endif
Tcl_DStringFree(&ds);
lastValidPathEnd = currentPathEndPosition;
if (cur == 0) {
break;
}
-
- /*
- * If we get here, we've got past one directory delimiter, so
- * we know it is no longer a drive.
+ /*
+ * If we get here, we've got past one directory
+ * delimiter, so we know it is no longer a drive
*/
-
isDrive = 0;
}
currentPathEndPosition++;
}
-
-#ifdef TclNORM_LONG_PATH
- /*
- * Convert the entire known path to long form.
- */
-
- if (1) {
- WCHAR wpath[MAX_PATH];
- 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');
- }
- Tcl_DStringAppend(&dsNorm, (TCHAR*)wpath, wpathlen*sizeof(WCHAR));
- Tcl_DStringFree(&ds);
- }
-#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);
}
@@ -2946,298 +2581,8 @@ TclpObjNormalizePath(
if (temp != NULL) {
Tcl_DecrRefCount(temp);
}
- return 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.
- *
- * Results:
- * A valid normalized path.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-Tcl_Obj *
-TclWinVolumeRelativeNormalize(
- Tcl_Interp *interp,
- const char *path,
- Tcl_Obj **useThisCwdPtr)
-{
- Tcl_Obj *absolutePath, *useThisCwd;
-
- useThisCwd = Tcl_FSGetCwd(interp);
- if (useThisCwd == NULL) {
- return NULL;
- }
-
- if (path[0] == '/') {
- /*
- * 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.
- */
- } else {
- /*
- * 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);
- 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.
- */
-
- 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
- * 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.
- */
-
- absolutePath = Tcl_NewStringObj(path, 2);
- Tcl_AppendToObj(absolutePath, "/", 1);
- }
- Tcl_IncrRefCount(absolutePath);
- Tcl_AppendToObj(absolutePath, path+2, -1);
- }
- *useThisCwdPtr = useThisCwd;
- return absolutePath;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * 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.
- *
- * Results:
- * A valid normalized path.
- *
- * Side effects:
- * None.
- *
- *---------------------------------------------------------------------------
- */
-
-Tcl_Obj *
-TclpNativeToNormalized(
- ClientData clientData)
-{
- Tcl_DString ds;
- Tcl_Obj *objPtr;
- int len;
- char *copy, *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.
- */
-
- if (*copy == '\\') {
- if (0 == strncmp(copy,"\\??\\",4)) {
- copy += 4;
- len -= 4;
- } else if (0 == strncmp(copy,"\\\\?\\",4)) {
- copy += 4;
- len -= 4;
- }
- }
-
- /*
- * Ensure we are using forward slashes only.
- */
-
- for (p = copy; *p != '\0'; p++) {
- if (*p == '\\') {
- *p = '/';
- }
- }
-
- objPtr = Tcl_NewStringObj(copy,len);
- Tcl_DStringFree(&ds);
-
- return objPtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * TclNativeCreateNativeRep --
- *
- * Create a native representation for the given path.
- *
- * Results:
- * The nativePath representation.
- *
- * Side effects:
- * Memory will be allocated. The path may need to be normalized.
- *
- *---------------------------------------------------------------------------
- */
-
-ClientData
-TclNativeCreateNativeRep(
- Tcl_Obj *pathPtr)
-{
- char *nativePathPtr, *str;
- Tcl_DString ds;
- Tcl_Obj *validPathPtr;
- int len;
-
- 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).
- */
-
- validPathPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
- if (validPathPtr == NULL) {
- return NULL;
- }
- } else {
- /*
- * Make sure the normalized path is set.
- */
-
- validPathPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
- if (validPathPtr == NULL) {
- return NULL;
- }
- Tcl_IncrRefCount(validPathPtr);
- }
-
- str = Tcl_GetStringFromObj(validPathPtr, &len);
- if (str[0] == '/' && str[1] == '/' && str[2] == '?' && str[3] == '/') {
- char *p;
-
- for (p = str; p && *p; ++p) {
- if (*p == '/') {
- *p = '\\';
- }
- }
- }
- Tcl_WinUtfToTChar(str, len, &ds);
- if (tclWinProcs->useWide) {
- len = Tcl_DStringLength(&ds) + sizeof(WCHAR);
- } else {
- len = Tcl_DStringLength(&ds) + sizeof(char);
- }
- Tcl_DecrRefCount(validPathPtr);
- nativePathPtr = ckalloc((unsigned) len);
- memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len);
-
- Tcl_DStringFree(&ds);
- return (ClientData) nativePathPtr;
-}
-
-/*
- *---------------------------------------------------------------------------
- *
- * TclNativeDupInternalRep --
- *
- * Duplicate the native representation.
- *
- * Results:
- * The copied native representation, or NULL if it is not possible to
- * copy the representation.
- *
- * Side effects:
- * Memory allocation for the copy.
- *
- *---------------------------------------------------------------------------
- */
-
-ClientData
-TclNativeDupInternalRep(
- ClientData clientData)
-{
- char *copy;
- size_t len;
-
- if (clientData == NULL) {
- return NULL;
- }
-
- if (tclWinProcs->useWide) {
- /*
- * Unicode representation when running on NT/2K/XP.
- */
-
- len = sizeof(WCHAR) * (wcslen((const WCHAR *) clientData) + 1);
- } else {
- /*
- * ANSI representation when running on 95/98/ME.
- */
-
- len = sizeof(char) * (strlen((const char *) clientData) + 1);
- }
- copy = (char *) ckalloc(len);
- memcpy(copy, clientData, len);
- return (ClientData) copy;
+ return nextCheckpoint;
}
/*
@@ -3264,7 +2609,7 @@ TclpUtime(
{
int res = 0;
HANDLE fileHandle;
- const TCHAR *native;
+ CONST TCHAR *native;
DWORD attr = 0;
DWORD flags = FILE_ATTRIBUTE_NORMAL;
FILETIME lastAccessTime, lastModTime;
@@ -3272,7 +2617,7 @@ TclpUtime(
FromCTime(tval->actime, &lastAccessTime);
FromCTime(tval->modtime, &lastModTime);
- native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
+ native = (CONST TCHAR *)Tcl_FSGetNativePath(pathPtr);
attr = (*tclWinProcs->getFileAttributesProc)(native);
@@ -3285,8 +2630,9 @@ TclpUtime(
* savings complications that utime gets wrong.
*/
- fileHandle = (tclWinProcs->createFileProc)(native, FILE_WRITE_ATTRIBUTES,
- 0, NULL, OPEN_EXISTING, flags, NULL);
+ fileHandle = (tclWinProcs->createFileProc) (
+ native, FILE_WRITE_ATTRIBUTES, 0, NULL,
+ OPEN_EXISTING, flags, NULL);
if (fileHandle == INVALID_HANDLE_VALUE ||
!SetFileTime(fileHandle, NULL, &lastAccessTime, &lastModTime)) {
@@ -3298,11 +2644,3 @@ TclpUtime(
}
return res;
}
-
-/*
- * Local Variables:
- * mode: c
- * c-basic-offset: 4
- * fill-column: 78
- * End:
- */