summaryrefslogtreecommitdiffstats
path: root/win/tclWinFile.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinFile.c')
-rwxr-xr-x[-rw-r--r--]win/tclWinFile.c1994
1 files changed, 1025 insertions, 969 deletions
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index b27487f..41de4a8 100644..100755
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -6,7 +6,7 @@
* files, which can be manipulated through the Win32 console redirection
* interfaces.
*
- * Copyright © 1995-1998 Sun Microsystems, Inc.
+ * 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.
@@ -16,20 +16,16 @@
#include "tclFileSystem.h"
#include <winioctl.h>
#include <shlobj.h>
-#include <lm.h> /* For TclpGetUserHome(). */
+#include <lmaccess.h> /* For TclpGetUserHome(). */
#include <userenv.h> /* For TclpGetUserHome(). */
-#include <aclapi.h> /* For GetNamedSecurityInfo */
-#ifdef _MSC_VER
-# pragma comment(lib, "userenv.lib")
-#endif
/*
* The number of 100-ns intervals between the Windows system epoch (1601-01-01
* on the proleptic Gregorian calendar) and the Posix epoch (1970-01-01).
*/
#define POSIX_EPOCH_AS_FILETIME \
- ((long long) 116444736 * (long long) 1000000000)
+ ((Tcl_WideInt) 116444736 * (Tcl_WideInt) 1000000000)
/*
* Declarations for 'link' related information. This information should come
@@ -145,39 +141,72 @@ typedef struct {
WCHAR dummyBuf[MAX_PATH * 3];
} DUMMY_REPARSE_BUFFER;
+#if defined(_MSC_VER) && (_MSC_VER <= 1100)
+#undef HAVE_NO_FINDEX_ENUMS
+#define HAVE_NO_FINDEX_ENUMS
+#elif !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0400)
+#undef HAVE_NO_FINDEX_ENUMS
+#define HAVE_NO_FINDEX_ENUMS
+#endif
+
+#ifdef HAVE_NO_FINDEX_ENUMS
+/* These two aren't in VC++ 5.2 headers */
+typedef enum _FINDEX_INFO_LEVELS {
+ FindExInfoStandard,
+ FindExInfoMaxInfoLevel
+} FINDEX_INFO_LEVELS;
+typedef enum _FINDEX_SEARCH_OPS {
+ FindExSearchNameMatch,
+ FindExSearchLimitToDirectories,
+ FindExSearchLimitToDevices,
+ FindExSearchMaxSearchOp
+} FINDEX_SEARCH_OPS;
+#endif /* HAVE_NO_FINDEX_ENUMS */
+
/*
* Other typedefs required by this code.
*/
-static __time64_t ToCTime(FILETIME fileTime);
-static void FromCTime(__time64_t posixTime, FILETIME *fileTime);
+static time_t ToCTime(FILETIME fileTime);
+static void FromCTime(time_t posixTime, FILETIME *fileTime);
+
+typedef NET_API_STATUS NET_API_FUNCTION NETUSERGETINFOPROC(
+ LPWSTR servername, LPWSTR username, DWORD level, LPBYTE *bufptr);
+
+typedef NET_API_STATUS NET_API_FUNCTION NETAPIBUFFERFREEPROC(LPVOID Buffer);
+
+typedef NET_API_STATUS NET_API_FUNCTION NETGETDCNAMEPROC(
+ LPWSTR servername, LPWSTR domainname, LPBYTE *bufptr);
+
+typedef BOOL WINAPI GETPROFILESDIRECTORYPROC(
+ LPWSTR lpProfilesDir, LPDWORD lpcchSize
+);
/*
* Declarations for local functions defined in this file:
*/
-static int NativeAccess(const WCHAR *path, int mode);
-static int NativeDev(const WCHAR *path);
-static int NativeStat(const WCHAR *path, Tcl_StatBuf *statPtr,
+static int NativeAccess(const TCHAR *path, int mode);
+static int NativeDev(const TCHAR *path);
+static int NativeStat(const TCHAR *path, Tcl_StatBuf *statPtr,
int checkLinks);
static unsigned short NativeStatMode(DWORD attr, int checkLinks,
int isExec);
-static int NativeIsExec(const WCHAR *path);
-static int NativeReadReparse(const WCHAR *LinkDirectory,
+static int NativeIsExec(const TCHAR *path);
+static int NativeReadReparse(const TCHAR *LinkDirectory,
REPARSE_DATA_BUFFER *buffer, DWORD desiredAccess);
-static int NativeWriteReparse(const WCHAR *LinkDirectory,
+static int NativeWriteReparse(const TCHAR *LinkDirectory,
REPARSE_DATA_BUFFER *buffer);
static int NativeMatchType(int isDrive, DWORD attr,
- const WCHAR *nativeName, Tcl_GlobTypeData *types);
-static int WinIsDrive(const char *name, size_t nameLen);
-static size_t WinIsReserved(const char *path);
-static Tcl_Obj * WinReadLink(const WCHAR *LinkSource);
-static Tcl_Obj * WinReadLinkDirectory(const WCHAR *LinkDirectory);
-static int WinLink(const WCHAR *LinkSource,
- const WCHAR *LinkTarget, int linkAction);
-static int WinSymLinkDirectory(const WCHAR *LinkDirectory,
- const WCHAR *LinkTarget);
-MODULE_SCOPE TCL_NORETURN void tclWinDebugPanic(const char *format, ...);
+ 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);
/*
*--------------------------------------------------------------------
@@ -191,25 +220,25 @@ MODULE_SCOPE TCL_NORETURN void tclWinDebugPanic(const char *format, ...);
static int
WinLink(
- const WCHAR *linkSourcePath,
- const WCHAR *linkTargetPath,
+ const TCHAR *linkSourcePath,
+ const TCHAR *linkTargetPath,
int linkAction)
{
WCHAR tempFileName[MAX_PATH];
- WCHAR *tempFilePart;
+ TCHAR *tempFilePart;
DWORD attr;
/*
* Get the full path referenced by the target.
*/
- if (!GetFullPathNameW(linkTargetPath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkTargetPath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -217,7 +246,7 @@ WinLink(
* Make sure source file doesn't exist.
*/
- attr = GetFileAttributesW(linkSourcePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
if (attr != INVALID_FILE_ATTRIBUTES) {
Tcl_SetErrno(EEXIST);
return -1;
@@ -227,13 +256,13 @@ WinLink(
* Get the full path referenced by the source file/directory.
*/
- if (!GetFullPathNameW(linkSourcePath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -241,41 +270,43 @@ WinLink(
* Check the target.
*/
- attr = GetFileAttributesW(linkTargetPath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkTargetPath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The target doesn't exist.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
+ return -1;
+
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
/*
* It is a file.
*/
- if (linkAction & TCL_CREATE_HARD_LINK) {
- if (CreateHardLinkW(linkSourcePath, linkTargetPath, NULL)) {
- /*
- * Success!
- */
+ if (tclWinProcs->createHardLinkProc == NULL) {
+ Tcl_SetErrno(ENOTDIR);
+ return -1;
+ }
- return 0;
+ if (linkAction & TCL_CREATE_HARD_LINK) {
+ if (!(*tclWinProcs->createHardLinkProc)(linkSourcePath,
+ linkTargetPath, NULL)) {
+ TclWinConvertError(GetLastError());
+ return -1;
}
+ return 0;
- Tcl_WinConvertError(GetLastError());
} else if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
- if (CreateSymbolicLinkW(linkSourcePath, linkTargetPath,
- 0x2 /* SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE */)) {
- /*
- * Success!
- */
+ /*
+ * Can't symlink files.
+ */
- return 0;
- } else {
- Tcl_WinConvertError(GetLastError());
- }
+ Tcl_SetErrno(ENOTDIR);
+ return -1;
} else {
Tcl_SetErrno(ENODEV);
+ return -1;
}
} else {
/*
@@ -292,11 +323,12 @@ WinLink(
*/
Tcl_SetErrno(EISDIR);
+ return -1;
} else {
Tcl_SetErrno(ENODEV);
+ return -1;
}
}
- return -1;
}
/*
@@ -311,23 +343,23 @@ WinLink(
static Tcl_Obj *
WinReadLink(
- const WCHAR *linkSourcePath)
+ const TCHAR *linkSourcePath)
{
WCHAR tempFileName[MAX_PATH];
- WCHAR *tempFilePart;
+ TCHAR *tempFilePart;
DWORD attr;
/*
* Get the full path referenced by the target.
*/
- if (!GetFullPathNameW(linkSourcePath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return NULL;
}
@@ -335,13 +367,13 @@ WinReadLink(
* Make sure source file does exist.
*/
- attr = GetFileAttributesW(linkSourcePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The source doesn't exist.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return NULL;
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
@@ -351,9 +383,9 @@ WinReadLink(
Tcl_SetErrno(ENOTDIR);
return NULL;
+ } else {
+ return WinReadLinkDirectory(linkSourcePath);
}
-
- return WinReadLinkDirectory(linkSourcePath);
}
/*
@@ -375,8 +407,8 @@ WinReadLink(
static int
WinSymLinkDirectory(
- const WCHAR *linkDirPath,
- const WCHAR *linkTargetPath)
+ const TCHAR *linkDirPath,
+ const TCHAR *linkTargetPath)
{
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
@@ -400,11 +432,11 @@ WinSymLinkDirectory(
*/
for (loop = nativeTarget; *loop != 0; loop++) {
- if (*loop == '/') {
- *loop = '\\';
+ if (*loop == L'/') {
+ *loop = L'\\';
}
}
- if ((nativeTarget[len-1] == '\\') && (nativeTarget[len-2] != ':')) {
+ if ((nativeTarget[len-1] == L'\\') && (nativeTarget[len-2] != L':')) {
nativeTarget[len-1] = 0;
}
@@ -447,8 +479,8 @@ WinSymLinkDirectory(
int
TclWinSymLinkCopyDirectory(
- const WCHAR *linkOrigPath, /* Existing junction - reparse point */
- const WCHAR *linkCopyPath) /* Will become a duplicate junction */
+ const TCHAR *linkOrigPath, /* Existing junction - reparse point */
+ const TCHAR *linkCopyPath) /* Will become a duplicate junction */
{
DUMMY_REPARSE_BUFFER dummy;
REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy;
@@ -478,7 +510,7 @@ TclWinSymLinkCopyDirectory(
int
TclWinSymLinkDelete(
- const WCHAR *linkOrigPath,
+ const TCHAR *linkOrigPath,
int linkOnly)
{
/*
@@ -492,8 +524,9 @@ TclWinSymLinkDelete(
memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER));
reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
- hFile = CreateFileW(linkOrigPath, GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = (*tclWinProcs->createFileProc)(linkOrigPath, GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile != INVALID_HANDLE_VALUE) {
if (!DeviceIoControl(hFile, FSCTL_DELETE_REPARSE_POINT, reparseBuffer,
@@ -502,12 +535,12 @@ TclWinSymLinkDelete(
* Error setting junction.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
CloseHandle(hFile);
} else {
CloseHandle(hFile);
if (!linkOnly) {
- RemoveDirectoryW(linkOrigPath);
+ (*tclWinProcs->removeDirectoryProc)(linkOrigPath);
}
return 0;
}
@@ -536,14 +569,9 @@ TclWinSymLinkDelete(
*--------------------------------------------------------------------
*/
-#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Warray-bounds"
-#endif
-
static Tcl_Obj *
WinReadLinkDirectory(
- const WCHAR *linkDirPath)
+ const TCHAR *linkDirPath)
{
int attr, len, offset;
DUMMY_REPARSE_BUFFER dummy;
@@ -552,7 +580,7 @@ WinReadLinkDirectory(
Tcl_DString ds;
const char *copy;
- attr = GetFileAttributesW(linkDirPath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkDirPath);
if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {
goto invalidError;
}
@@ -577,7 +605,7 @@ WinReadLinkDirectory(
*/
offset = 0;
- if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == '\\') {
+ if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') {
/*
* Check whether this is a mounted volume.
*/
@@ -591,7 +619,7 @@ WinReadLinkDirectory(
* to fix here. It doesn't seem very well documented.
*/
- reparseBuffer->MountPointReparseBuffer.PathBuffer[1] = '\\';
+ reparseBuffer->MountPointReparseBuffer.PathBuffer[1]=L'\\';
/*
* Check if a corresponding drive letter exists, and use that
@@ -639,11 +667,10 @@ WinReadLinkDirectory(
}
}
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString(
+ Tcl_WinTCharToUtf((const char *)
reparseBuffer->MountPointReparseBuffer.PathBuffer,
- reparseBuffer->MountPointReparseBuffer
- .SubstituteNameLength>>1, &ds);
+ (int) reparseBuffer->MountPointReparseBuffer
+ .SubstituteNameLength, &ds);
copy = Tcl_DStringValue(&ds)+offset;
len = Tcl_DStringLength(&ds)-offset;
@@ -657,10 +684,6 @@ WinReadLinkDirectory(
Tcl_SetErrno(EINVAL);
return NULL;
}
-
-#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
-#pragma GCC diagnostic pop
-#endif
/*
*--------------------------------------------------------------------
@@ -679,23 +702,23 @@ WinReadLinkDirectory(
static int
NativeReadReparse(
- const WCHAR *linkDirPath, /* The junction to read */
+ const TCHAR *linkDirPath, /* The junction to read */
REPARSE_DATA_BUFFER *buffer,/* Pointer to buffer. Cannot be NULL */
DWORD desiredAccess)
{
HANDLE hFile;
DWORD returnedLength;
- hFile = CreateFileW(linkDirPath, desiredAccess, FILE_SHARE_READ, NULL,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = (*tclWinProcs->createFileProc)(linkDirPath, desiredAccess, FILE_SHARE_READ,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
/*
* Error creating directory.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -709,7 +732,7 @@ NativeReadReparse(
* Error setting junction.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
CloseHandle(hFile);
return -1;
}
@@ -736,7 +759,7 @@ NativeReadReparse(
static int
NativeWriteReparse(
- const WCHAR *linkDirPath,
+ const TCHAR *linkDirPath,
REPARSE_DATA_BUFFER *buffer)
{
HANDLE hFile;
@@ -746,23 +769,23 @@ NativeWriteReparse(
* Create the directory - it must not already exist.
*/
- if (CreateDirectoryW(linkDirPath, NULL) == 0) {
+ if ((*tclWinProcs->createDirectoryProc)(linkDirPath, NULL) == 0) {
/*
* Error creating directory.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
- hFile = CreateFileW(linkDirPath, GENERIC_WRITE, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT
- | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ hFile = (*tclWinProcs->createFileProc)(linkDirPath, GENERIC_WRITE, 0,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
/*
* Error creating directory.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
@@ -777,9 +800,9 @@ NativeWriteReparse(
* Error setting junction.
*/
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
CloseHandle(hFile);
- RemoveDirectoryW(linkDirPath);
+ (*tclWinProcs->removeDirectoryProc)(linkDirPath);
return -1;
}
CloseHandle(hFile);
@@ -792,65 +815,6 @@ NativeWriteReparse(
}
/*
- *----------------------------------------------------------------------
- *
- * tclWinDebugPanic --
- *
- * Display a message. If a debugger is present, present it directly to
- * the debugger, otherwise use a MessageBox.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-TCL_NORETURN void
-tclWinDebugPanic(
- const char *format, ...)
-{
-#define TCL_MAX_WARN_LEN 1024
- va_list argList;
- char buf[TCL_MAX_WARN_LEN * 3];
- WCHAR msgString[TCL_MAX_WARN_LEN];
-
- va_start(argList, format);
- vsnprintf(buf, sizeof(buf), format, argList);
-
- msgString[TCL_MAX_WARN_LEN-1] = '\0';
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, msgString, TCL_MAX_WARN_LEN);
-
- /*
- * Truncate MessageBox string if it is too long to not overflow the screen
- * and cause possible oversized window error.
- */
-
- if (msgString[TCL_MAX_WARN_LEN-1] != '\0') {
- memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR));
- }
- if (IsDebuggerPresent()) {
- OutputDebugStringW(msgString);
- } else {
- MessageBeep(MB_ICONEXCLAMATION);
- MessageBoxW(NULL, msgString, L"Fatal Error",
- MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
- }
-#if defined(__GNUC__)
- __builtin_trap();
-#elif defined(_WIN64)
- __debugbreak();
-#elif defined(_MSC_VER) && defined (_M_IX86)
- _asm {int 3}
-#else
- DebugBreak();
-#endif
- abort();
-}
-
-/*
*---------------------------------------------------------------------------
*
* TclpFindExecutable --
@@ -869,26 +833,30 @@ tclWinDebugPanic(
void
TclpFindExecutable(
- const char *argv0) /* If NULL, install PanicMessageBox, otherwise
- * ignore. */
+ const char *argv0) /* The value of the application's argv[0]
+ * (native). */
{
WCHAR wName[MAX_PATH];
- char name[MAX_PATH * 3];
+ char name[MAX_PATH * TCL_UTF_MAX];
/*
* Under Windows we ignore argv0, and return the path for the file used to
- * create this process. Only if it is NULL, install a new panic handler.
+ * create this process.
*/
- if (argv0 == NULL) {
-# undef Tcl_SetPanicProc
- Tcl_SetPanicProc(tclWinDebugPanic);
+ 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);
}
- GetModuleFileNameW(NULL, wName, sizeof(wName)/sizeof(WCHAR));
- 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, TCL_INDEX_NONE), NULL);
+ TclSetObjNameOfExecutable(Tcl_NewStringObj(name, -1), NULL);
}
/*
@@ -920,7 +888,7 @@ TclpMatchInDirectory(
* May be NULL. In particular the directory
* flag is very important. */
{
- const WCHAR *native;
+ const TCHAR *native;
if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) {
/*
@@ -932,26 +900,32 @@ TclpMatchInDirectory(
if (pattern == NULL || (*pattern == '\0')) {
Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr);
-
if (norm != NULL) {
/*
* Match a single file directly.
*/
+ int len;
DWORD attr;
- WIN32_FILE_ATTRIBUTE_DATA data;
- Tcl_Size len = 0;
- const char *str = TclGetStringFromObj(norm, &len);
+ const char *str = Tcl_GetStringFromObj(norm,&len);
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
- if (GetFileAttributesExW(native,
- GetFileExInfoStandard, &data) != TRUE) {
- return TCL_OK;
+ if (tclWinProcs->getFileAttributesExProc == NULL) {
+ attr = (*tclWinProcs->getFileAttributesProc)(native);
+ if (attr == 0xffffffff) {
+ return TCL_OK;
+ }
+ } else {
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ if ((*tclWinProcs->getFileAttributesExProc)(native,
+ GetFileExInfoStandard, &data) != TRUE) {
+ return TCL_OK;
+ }
+ attr = data.dwFileAttributes;
}
- attr = data.dwFileAttributes;
- if (NativeMatchType(WinIsDrive(str, len), attr, native, types)) {
+ if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) {
Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
}
}
@@ -959,10 +933,10 @@ TclpMatchInDirectory(
} else {
DWORD attr;
HANDLE handle;
- WIN32_FIND_DATAW data;
+ WIN32_FIND_DATAT data;
const char *dirName; /* UTF-8 dir name, later with pattern
* appended. */
- Tcl_Size dirLength;
+ int dirLength;
int matchSpecialDots;
Tcl_DString ds; /* Native encoding of dir, also used
* temporarily for other things. */
@@ -984,14 +958,13 @@ TclpMatchInDirectory(
* Verify that the specified path exists and is actually a directory.
*/
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ native = Tcl_FSGetNativePath(pathPtr);
if (native == NULL) {
return TCL_OK;
}
- attr = GetFileAttributesW(native);
+ attr = (*tclWinProcs->getFileAttributesProc)(native);
- if ((attr == INVALID_FILE_ATTRIBUTES)
- || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
+ if ((attr == 0xffffffff) || ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0)) {
return TCL_OK;
}
@@ -1001,12 +974,12 @@ TclpMatchInDirectory(
*/
Tcl_DStringInit(&dsOrig);
- dirName = TclGetStringFromObj(fileNamePtr, &dirLength);
+ dirName = Tcl_GetStringFromObj(fileNamePtr, &dirLength);
Tcl_DStringAppend(&dsOrig, dirName, dirLength);
lastChar = dirName[dirLength -1];
if ((lastChar != '\\') && (lastChar != '/') && (lastChar != ':')) {
- TclDStringAppendLiteral(&dsOrig, "/");
+ Tcl_DStringAppend(&dsOrig, "/", 1);
dirLength++;
}
dirName = Tcl_DStringValue(&dsOrig);
@@ -1024,28 +997,27 @@ TclpMatchInDirectory(
* pattern.
*/
- dirName = Tcl_DStringAppend(&dsOrig, pattern, TCL_INDEX_NONE);
+ dirName = Tcl_DStringAppend(&dsOrig, pattern, -1);
} else {
- dirName = TclDStringAppendLiteral(&dsOrig, "*.*");
+ dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3);
}
- Tcl_DStringInit(&ds);
- native = Tcl_UtfToWCharDString(dirName, TCL_INDEX_NONE, &ds);
- if ((types == NULL) || (types->type != TCL_GLOB_TYPE_DIR)) {
- handle = FindFirstFileW(native, &data);
+ 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 = FindFirstFileExW(native,
+ handle = (*tclWinProcs->findFirstFileExProc)(native,
FindExInfoStandard, &data,
FindExSearchLimitToDirectories, NULL, 0);
}
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
-
Tcl_DStringFree(&ds);
if (err == ERROR_FILE_NOT_FOUND) {
/*
@@ -1057,11 +1029,12 @@ TclpMatchInDirectory(
return TCL_OK;
}
- Tcl_WinConvertError(err);
+ TclWinConvertError(err);
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "couldn't read directory \"%s\": %s",
- Tcl_DStringValue(&dsOrig), Tcl_PosixError(interp)));
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "couldn't read directory \"",
+ Tcl_DStringValue(&dsOrig), "\": ",
+ Tcl_PosixError(interp), NULL);
}
Tcl_DStringFree(&dsOrig);
return TCL_ERROR;
@@ -1099,11 +1072,17 @@ TclpMatchInDirectory(
do {
const char *utfname;
int checkDrive = 0, isDrive;
+ DWORD attr;
+
+ if (tclWinProcs->useWide) {
+ native = (const TCHAR *) data.w.cFileName;
+ attr = data.w.dwFileAttributes;
+ } else {
+ native = (const TCHAR *) data.a.cFileName;
+ attr = data.a.dwFileAttributes;
+ }
- native = data.cFileName;
- attr = data.dwFileAttributes;
- Tcl_DStringInit(&ds);
- utfname = Tcl_WCharToUtfDString(native, TCL_INDEX_NONE, &ds);
+ utfname = Tcl_WinTCharToUtf(native, -1, &ds);
if (!matchSpecialDots) {
/*
@@ -1145,7 +1124,6 @@ TclpMatchInDirectory(
if (checkDrive) {
const char *fullname = Tcl_DStringAppend(&dsOrig, utfname,
Tcl_DStringLength(&ds));
-
isDrive = WinIsDrive(fullname, Tcl_DStringLength(&dsOrig));
Tcl_DStringSetLength(&dsOrig, dirLength);
} else {
@@ -1163,7 +1141,7 @@ TclpMatchInDirectory(
*/
Tcl_DStringFree(&ds);
- } while (FindNextFileW(handle, &data) == TRUE);
+ } while ((*tclWinProcs->findNextFileProc)(handle, &data) == TRUE);
FindClose(handle);
Tcl_DStringFree(&dsOrig);
@@ -1180,7 +1158,7 @@ TclpMatchInDirectory(
static int
WinIsDrive(
const char *name, /* Name (UTF-8) */
- size_t len) /* Length of name */
+ int len) /* Length of name */
{
int remove = 0;
@@ -1245,7 +1223,7 @@ WinIsDrive(
* (not any trailing :).
*/
-static size_t
+static int
WinIsReserved(
const char *path) /* Path in UTF-8 */
{
@@ -1259,7 +1237,7 @@ WinIsReserved(
if (path[4] == '\0') {
return 4;
- } else if (path[4] == ':' && path[5] == '\0') {
+ } else if (path [4] == ':' && path[5] == '\0') {
return 4;
}
} else if ((path[2] == 'n' || path[2] == 'N') && path[3] == '\0') {
@@ -1280,7 +1258,7 @@ WinIsReserved(
if (path[4] == '\0') {
return 4;
- } else if (path[4] == ':' && path[5] == '\0') {
+ } else if (path [4] == ':' && path[5] == '\0') {
return 4;
}
}
@@ -1321,7 +1299,7 @@ NativeMatchType(
int isDrive, /* Is this a drive. */
DWORD attr, /* We already know the attributes for the
* file. */
- const WCHAR *nativeName, /* Native path to check. */
+ const TCHAR *nativeName, /* Native path to check. */
Tcl_GlobTypeData *types) /* Type description to match against. */
{
/*
@@ -1336,80 +1314,81 @@ NativeMatchType(
* If invisible, don't return the file.
*/
- return !(attr & FILE_ATTRIBUTE_HIDDEN && !isDrive);
- }
-
- if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) {
- /*
- * If invisible.
- */
-
- if ((types->perm == 0) || !(types->perm & TCL_GLOB_PERM_HIDDEN)) {
+ if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) {
return 0;
}
} else {
- /*
- * Visible.
- */
+ if (attr & FILE_ATTRIBUTE_HIDDEN && !isDrive) {
+ /*
+ * If invisible.
+ */
- if (types->perm & TCL_GLOB_PERM_HIDDEN) {
- return 0;
- }
- }
+ if ((types->perm == 0) || !(types->perm & TCL_GLOB_PERM_HIDDEN)) {
+ return 0;
+ }
+ } else {
+ /*
+ * Visible.
+ */
- if (types->perm != 0) {
- if (((types->perm & TCL_GLOB_PERM_RONLY) &&
- !(attr & FILE_ATTRIBUTE_READONLY)) ||
- ((types->perm & TCL_GLOB_PERM_R) &&
- (0 /* File exists => R_OK on Windows */)) ||
- ((types->perm & TCL_GLOB_PERM_W) &&
- (attr & FILE_ATTRIBUTE_READONLY)) ||
- ((types->perm & TCL_GLOB_PERM_X) &&
- (!(attr & FILE_ATTRIBUTE_DIRECTORY)
- && !NativeIsExec(nativeName)))) {
- return 0;
+ if (types->perm & TCL_GLOB_PERM_HIDDEN) {
+ return 0;
+ }
}
- }
- if ((types->type & TCL_GLOB_TYPE_DIR)
- && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
- /*
- * Quicker test for directory, which is a common case.
- */
+ if (types->perm != 0) {
+ if (((types->perm & TCL_GLOB_PERM_RONLY) &&
+ !(attr & FILE_ATTRIBUTE_READONLY)) ||
+ ((types->perm & TCL_GLOB_PERM_R) &&
+ (0 /* File exists => R_OK on Windows */)) ||
+ ((types->perm & TCL_GLOB_PERM_W) &&
+ (attr & FILE_ATTRIBUTE_READONLY)) ||
+ ((types->perm & TCL_GLOB_PERM_X) &&
+ (!(attr & FILE_ATTRIBUTE_DIRECTORY)
+ && !NativeIsExec(nativeName)))) {
+ return 0;
+ }
+ }
+ if ((types->type & TCL_GLOB_TYPE_DIR)
+ && (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ /*
+ * Quicker test for directory, which is a common case.
+ */
- return 1;
+ return 1;
- } else if (types->type != 0) {
- unsigned short st_mode;
- int isExec = NativeIsExec(nativeName);
+ } else if (types->type != 0) {
+ unsigned short st_mode;
+ int isExec = NativeIsExec(nativeName);
- st_mode = NativeStatMode(attr, 0, isExec);
+ st_mode = NativeStatMode(attr, 0, isExec);
- /*
- * In order bcdpfls as in 'find -t'
- */
+ /*
+ * 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)) ||
#ifdef S_ISSOCK
- ((types->type&TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) ||
+ ((types->type&TCL_GLOB_TYPE_SOCK) && S_ISSOCK(st_mode)) ||
#endif
- ((types->type&TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode))) {
- /*
- * Do nothing - this file is ok.
- */
- } else {
+ ((types->type&TCL_GLOB_TYPE_FILE) && S_ISREG(st_mode))) {
+ /*
+ * Do nothing - this file is ok.
+ */
+ } else {
#ifdef S_ISLNK
- if (types->type & TCL_GLOB_TYPE_LINK) {
- st_mode = NativeStatMode(attr, 1, isExec);
- if (S_ISLNK(st_mode)) {
- return 1;
+ if (types->type & TCL_GLOB_TYPE_LINK) {
+ st_mode = NativeStatMode(attr, 1, isExec);
+ if (S_ISLNK(st_mode)) {
+ return 1;
+ }
}
+#endif
+ return 0;
}
-#endif /* S_ISLNK */
- return 0;
}
}
return 1;
@@ -1436,130 +1415,114 @@ NativeMatchType(
*----------------------------------------------------------------------
*/
-const char *
+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. */
{
- char *result = NULL;
- USER_INFO_1 *uiPtr;
- Tcl_DString ds;
- int nameLen = -1;
- int rc = 0;
- const char *domain;
- WCHAR *wName, *wHomeDir, *wDomain;
+ char *result;
+ HINSTANCE netapiInst;
+ HINSTANCE userenvInst;
+ result = NULL;
Tcl_DStringInit(bufferPtr);
- wDomain = NULL;
- domain = Tcl_UtfFindFirst(name, '@');
- if (domain == NULL) {
- const char *ptr;
-
- /*
- * Treat the current user as a special case because the general case
- * below does not properly retrieve the path. The NetUserGetInfo
- * call returns an empty path and the code defaults to the user's
- * name in the profiles directory. On modern Windows systems, this
- * is generally wrong as when the account is a Microsoft account,
- * for example abcdefghi@outlook.com, the directory name is
- * abcde and not abcdefghi.
- *
- * Note we could have just used env(USERPROFILE) here but
- * the intent is to retrieve (as on Unix) the system's view
- * of the home irrespective of environment settings of HOME
- * and USERPROFILE.
- *
- * Fixing this for the general user needs more investigating but
- * at least for the current user we can use a direct call.
- */
- ptr = TclpGetUserName(&ds);
- if (ptr != NULL && strcasecmp(name, ptr) == 0) {
- HANDLE hProcess;
+ netapiInst = LoadLibraryA("netapi32.dll");
+ userenvInst = LoadLibraryA("userenv.dll");
+ if (netapiInst != NULL && userenvInst != NULL) {
+ NETAPIBUFFERFREEPROC *netApiBufferFreeProc;
+ NETGETDCNAMEPROC *netGetDCNameProc;
+ NETUSERGETINFOPROC *netUserGetInfoProc;
+ GETPROFILESDIRECTORYPROC *getProfilesDirectoryProc;
+
+ netApiBufferFreeProc = (NETAPIBUFFERFREEPROC *)
+ GetProcAddress(netapiInst, "NetApiBufferFree");
+ netGetDCNameProc = (NETGETDCNAMEPROC *)
+ GetProcAddress(netapiInst, "NetGetDCName");
+ netUserGetInfoProc = (NETUSERGETINFOPROC *)
+ GetProcAddress(netapiInst, "NetUserGetInfo");
+ getProfilesDirectoryProc = (GETPROFILESDIRECTORYPROC *)
+ GetProcAddress(userenvInst, "GetProfilesDirectoryW");
+ if ((netUserGetInfoProc != NULL) && (netGetDCNameProc != NULL)
+ && (netApiBufferFreeProc != NULL) && (getProfilesDirectoryProc != NULL)) {
+ USER_INFO_1 *uiPtr, **uiPtrPtr = &uiPtr;
+ Tcl_DString ds;
+ int nameLen, badDomain;
+ char *domain;
+ WCHAR *wName, *wHomeDir, *wDomain, **wDomainPtr = &wDomain;
WCHAR buf[MAX_PATH];
- DWORD nChars = sizeof(buf) / sizeof(buf[0]);
- /* Sadly GetCurrentProcessToken not in Win 7 so slightly longer */
- hProcess = GetCurrentProcess(); /* Need not be closed */
- if (hProcess) {
- HANDLE hToken;
- if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
- if (GetUserProfileDirectoryW(hToken, buf, &nChars)) {
- result = Tcl_WCharToUtfDString(buf, nChars-1, (bufferPtr));
- rc = 1;
+
+ badDomain = 0;
+ nameLen = -1;
+ wDomain = NULL;
+ domain = strchr(name, '@');
+ if (domain != NULL) {
+ Tcl_DStringInit(&ds);
+ wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds);
+ badDomain = (netGetDCNameProc)(NULL, wName,
+ (LPBYTE *) wDomainPtr);
+ 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) {
+ 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
+ * "{GetProfilesDirectory}/<user>".
+ */
+ DWORD i, size = MAX_PATH;
+ getProfilesDirectoryProc(buf, &size);
+ for (i = 0; i < size; ++i){
+ if (buf[i] == '\\') buf[i] = '/';
+ }
+ Tcl_UniCharToUtfDString(buf, size-1, bufferPtr);
+ Tcl_DStringAppend(bufferPtr, "/", -1);
+ Tcl_DStringAppend(bufferPtr, name, -1);
}
- CloseHandle(hToken);
+ result = Tcl_DStringValue(bufferPtr);
+ (*netApiBufferFreeProc)((void *) uiPtr);
}
+ Tcl_DStringFree(&ds);
+ }
+ if (wDomain != NULL) {
+ (*netApiBufferFreeProc)((void *) wDomain);
}
}
- Tcl_DStringFree(&ds);
- } else {
- Tcl_DStringInit(&ds);
- wName = Tcl_UtfToWCharDString(domain + 1, TCL_INDEX_NONE, &ds);
- rc = NetGetDCName(NULL, wName, (LPBYTE *) &wDomain);
- Tcl_DStringFree(&ds);
- nameLen = domain - name;
+ FreeLibrary(userenvInst);
+ FreeLibrary(netapiInst);
}
- if (rc == 0) {
- Tcl_DStringInit(&ds);
- wName = Tcl_UtfToWCharDString(name, nameLen, &ds);
- while (NetUserGetInfo(wDomain, wName, 1, (LPBYTE *) &uiPtr) != 0) {
- /*
- * User does not exist; if domain was not specified, try again
- * using current domain.
- */
-
- rc = 1;
- if (domain != NULL) {
- break;
- }
-
- /*
- * Get current domain
- */
+ 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 "*".
+ */
- rc = NetGetDCName(NULL, NULL, (LPBYTE *) &wDomain);
- if (rc != 0) {
- break;
- }
- domain = (const char *)INT2PTR(-1); /* repeat once */
- }
- if (rc == 0) {
- DWORD i, size = MAX_PATH;
+ char buf[MAX_PATH];
- wHomeDir = uiPtr->usri1_home_dir;
- if ((wHomeDir != NULL) && (wHomeDir[0] != '\0')) {
- size = lstrlenW(wHomeDir);
- Tcl_WCharToUtfDString(wHomeDir, size, bufferPtr);
- } else {
- WCHAR buf[MAX_PATH];
+ if (name[0] != '*') {
+ if (GetPrivateProfileStringA("Password Lists", name, "", buf,
+ MAX_PATH, "system.ini") > 0) {
/*
- * User exists but has no home dir. Return
- * "{GetProfilesDirectory}/<user>".
+ * User exists, but there is no such thing as a home directory
+ * in system.ini. Return "{Windows drive}:/".
*/
- GetProfilesDirectoryW(buf, &size);
- Tcl_WCharToUtfDString(buf, size-1, bufferPtr);
- Tcl_DStringAppend(bufferPtr, "/", 1);
- Tcl_DStringAppend(bufferPtr, name, nameLen);
- }
- result = Tcl_DStringValue(bufferPtr);
-
- /*
- * Be sure we return normalized path
- */
-
- for (i = 0; i < size; ++i) {
- if (result[i] == '\\') {
- result[i] = '/';
- }
+ GetWindowsDirectoryA(buf, MAX_PATH);
+ Tcl_DStringAppend(bufferPtr, buf, 3);
+ result = Tcl_DStringValue(bufferPtr);
}
- NetApiBufferFree((void *) uiPtr);
}
- Tcl_DStringFree(&ds);
- }
- if (wDomain != NULL) {
- NetApiBufferFree((void *) wDomain);
}
return result;
@@ -1586,21 +1549,21 @@ TclpGetUserHome(
static int
NativeAccess(
- const WCHAR *nativePath, /* Path of file to access, native encoding. */
+ const TCHAR *nativePath, /* Path of file to access, native encoding. */
int mode) /* Permission setting. */
{
DWORD attr;
- attr = GetFileAttributesW(nativePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
- if (attr == INVALID_FILE_ATTRIBUTES) {
+ if (attr == 0xffffffff) {
/*
* File might not exist.
*/
DWORD lasterror = GetLastError();
if (lasterror != ERROR_SHARING_VIOLATION) {
- Tcl_WinConvertError(lasterror);
+ TclWinConvertError(lasterror);
return -1;
}
}
@@ -1613,75 +1576,33 @@ NativeAccess(
return 0;
}
- /*
- * If it's not a directory (assume file), do several fast checks:
- */
-
- if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ if ((mode & W_OK)
+ && (attr & FILE_ATTRIBUTE_READONLY)
+ && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
/*
- * If the attributes say this is not writable at all. The file is a
+ * The attributes say the file is not writable. If the file is a
* regular file (i.e., not a directory), then the file is not
- * writable, full stop. For directories, the read-only bit is
+ * writable, full stop. For directories, the read-only bit is
* (mostly) ignored by Windows, so we can't ascertain anything about
* directory access from the attrib data. However, if we have the
- * advanced 'getFileSecurityProc', then more robust ACL checks will be
- * done below.
- */
-
- if ((mode & W_OK) && (attr & FILE_ATTRIBUTE_READONLY)) {
- Tcl_SetErrno(EACCES);
- return -1;
- }
-
- /*
- * If doesn't have the correct extension, it can't be executable
- */
-
- if ((mode & X_OK) && !NativeIsExec(nativePath)) {
- Tcl_SetErrno(EACCES);
- return -1;
- }
-
- /*
- * Special case for read/write/executable check on file
+ * advanced 'getFileSecurityProc', then more robust ACL checks
+ * will be done below.
*/
- if ((mode & (R_OK|W_OK|X_OK)) && !(mode & ~(R_OK|W_OK|X_OK))) {
- DWORD mask = 0;
- HANDLE hFile;
-
- if (mode & R_OK) {
- mask |= GENERIC_READ;
- }
- if (mode & W_OK) {
- mask |= GENERIC_WRITE;
- }
- if (mode & X_OK) {
- mask |= GENERIC_EXECUTE;
- }
-
- hFile = CreateFileW(nativePath, mask,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL);
- if (hFile != INVALID_HANDLE_VALUE) {
- CloseHandle(hFile);
- return 0;
- }
+ Tcl_SetErrno(EACCES);
+ return -1;
+ }
+ if (mode & X_OK) {
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) {
/*
- * Fast exit if access was denied
+ * It's not a directory and doesn't have the correct extension.
+ * Therefore it can't be executable
*/
- if (GetLastError() == ERROR_ACCESS_DENIED) {
- Tcl_SetErrno(EACCES);
- return -1;
- }
+ Tcl_SetErrno(EACCES);
+ return -1;
}
-
- /*
- * We cannot verify the access fast, check it below using security
- * info.
- */
}
/*
@@ -1691,7 +1612,7 @@ NativeAccess(
* what permissions the OS has set for a file.
*/
- {
+ if (tclWinProcs->getFileSecurityProc != NULL) {
SECURITY_DESCRIPTOR *sdPtr = NULL;
unsigned long size;
PSID pSid = 0;
@@ -1706,11 +1627,11 @@ NativeAccess(
int error;
/*
- * First find out how big the buffer needs to be.
+ * First find out how big the buffer needs to be
*/
size = 0;
- GetFileSecurityW(nativePath,
+ (*tclWinProcs->getFileSecurityProc)(nativePath,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
0, 0, &size);
@@ -1726,7 +1647,7 @@ NativeAccess(
* to EACCES - just what we want!
*/
- Tcl_WinConvertError((DWORD) error);
+ TclWinConvertError((DWORD) error);
return -1;
}
@@ -1741,10 +1662,10 @@ NativeAccess(
}
/*
- * Call GetFileSecurityW() for real.
+ * Call GetFileSecurity() for real.
*/
- if (!GetFileSecurityW(nativePath,
+ if (!(*tclWinProcs->getFileSecurityProc)(nativePath,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
sdPtr, size, &size)) {
@@ -1780,14 +1701,14 @@ NativeAccess(
* thread token.
*/
- if (!ImpersonateSelf(SecurityImpersonation)) {
+ if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) {
/*
* Unable to perform security impersonation.
*/
goto accessError;
}
- if (!OpenThreadToken(GetCurrentThread(),
+ if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread(),
TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) {
/*
* Unable to get current thread's token.
@@ -1796,10 +1717,10 @@ NativeAccess(
goto accessError;
}
- RevertToSelf();
+ (*tclWinProcs->revertToSelfProc)();
/*
- * Setup desiredAccess according to the access privileges we are
+ * Setup desiredAccess according to the access priveleges we are
* checking.
*/
@@ -1823,7 +1744,7 @@ NativeAccess(
* Perform access check using the token.
*/
- if (!AccessCheck(sdPtr, hToken, desiredAccess,
+ if (!(*tclWinProcs->accessCheckProc)(sdPtr, hToken, desiredAccess,
&genMap, &privSet, &privSetSize, &grantedAccess,
&accessYesNo)) {
/*
@@ -1831,7 +1752,7 @@ NativeAccess(
*/
accessError:
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
if (sdPtr != NULL) {
HeapFree(GetProcessHeap(), 0, sdPtr);
}
@@ -1862,7 +1783,7 @@ NativeAccess(
* NativeIsExec --
*
* Determines if a path is executable. On windows this is simply defined
- * by whether the path ends in a standard executable extension.
+ * by whether the path ends in any of ".exe", ".com", or ".bat"
*
* Results:
* 1 = executable, 0 = not.
@@ -1872,24 +1793,55 @@ NativeAccess(
static int
NativeIsExec(
- const WCHAR *path)
+ const TCHAR *nativePath)
{
- int len = wcslen(path);
+ if (tclWinProcs->useWide) {
+ const WCHAR *path = (const WCHAR *) nativePath;
+ int len = wcslen(path);
- if (len < 5) {
- return 0;
- }
+ if (len < 5) {
+ return 0;
+ }
- if (path[len-4] != '.') {
- return 0;
- }
+ if (path[len-4] != L'.') {
+ return 0;
+ }
+
+ /*
+ * Use wide-char case-insensitive comparison
+ */
+
+ if ((_wcsicmp(path+len-3, L"exe") == 0)
+ || (_wcsicmp(path+len-3, L"com") == 0)
+ || (_wcsicmp(path+len-3, L"bat") == 0)) {
+ return 1;
+ }
+ } else {
+ const char *p;
+
+ /*
+ * We are only looking for pure ascii.
+ */
+
+ p = strrchr((const char *) nativePath, '.');
+ if (p != NULL) {
+ p++;
+
+ /*
+ * Note: in the old code, stat considered '.pif' files as
+ * executable, whereas access did not.
+ */
- path += len-3;
- if ((_wcsicmp(path, L"exe") == 0)
- || (_wcsicmp(path, L"com") == 0)
- || (_wcsicmp(path, L"cmd") == 0)
- || (_wcsicmp(path, L"bat") == 0)) {
- return 1;
+ if ((strcasecmp(p, "exe") == 0)
+ || (strcasecmp(p, "com") == 0)
+ || (strcasecmp(p, "bat") == 0)) {
+ /*
+ * File that ends with .exe, .com, or .bat is executable.
+ */
+
+ return 1;
+ }
+ }
}
return 0;
}
@@ -1915,17 +1867,17 @@ TclpObjChdir(
Tcl_Obj *pathPtr) /* Path to new working directory. */
{
int result;
- const WCHAR *nativePath;
+ const TCHAR *nativePath;
- nativePath = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ nativePath = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
if (!nativePath) {
return -1;
}
- result = SetCurrentDirectoryW(nativePath);
+ result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath);
if (result == 0) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
return 0;
@@ -1961,14 +1913,12 @@ TclpGetCwd(
{
WCHAR buffer[MAX_PATH];
char *p;
- WCHAR *native;
- if (GetCurrentDirectoryW(MAX_PATH, buffer) == 0) {
- Tcl_WinConvertError(GetLastError());
+ if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) {
+ TclWinConvertError(GetLastError());
if (interp != NULL) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "error getting working directory name: %s",
- Tcl_PosixError(interp)));
+ Tcl_AppendResult(interp, "error getting working directory name: ",
+ Tcl_PosixError(interp), NULL);
}
return NULL;
}
@@ -1977,13 +1927,25 @@ TclpGetCwd(
* Watch for the weird Windows c:\\UNC syntax.
*/
- native = (WCHAR *) buffer;
- if ((native[0] != '\0') && (native[1] == ':')
- && (native[2] == '\\') && (native[3] == '\\')) {
- native += 2;
+ if (tclWinProcs->useWide) {
+ WCHAR *native;
+
+ native = (WCHAR *) buffer;
+ if ((native[0] != '\0') && (native[1] == ':')
+ && (native[2] == '\\') && (native[3] == '\\')) {
+ native += 2;
+ }
+ Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr);
+ } else {
+ char *native;
+
+ native = (char *) buffer;
+ if ((native[0] != '\0') && (native[1] == ':')
+ && (native[2] == '\\') && (native[3] == '\\')) {
+ native += 2;
+ }
+ Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr);
}
- Tcl_DStringInit(bufferPtr);
- Tcl_WCharToUtfDString(native, TCL_INDEX_NONE, bufferPtr);
/*
* Convert to forward slashes for easier use in scripts.
@@ -2010,7 +1972,8 @@ TclpObjStat(
TclWinFlushDirtyChannels();
- return NativeStat((const WCHAR *)Tcl_FSGetNativePath(pathPtr), statPtr, 0);
+ return NativeStat((const TCHAR *) Tcl_FSGetNativePath(pathPtr),
+ statPtr, 0);
}
/*
@@ -2038,7 +2001,7 @@ TclpObjStat(
static int
NativeStat(
- const WCHAR *nativePath, /* Path of file to stat */
+ const TCHAR *nativePath, /* Path of file to stat */
Tcl_StatBuf *statPtr, /* Filled with results of stat call. */
int checkLinks) /* If non-zero, behave like 'lstat' */
{
@@ -2047,7 +2010,6 @@ NativeStat(
unsigned short mode;
unsigned int inode = 0;
HANDLE fileHandle;
- DWORD fileType = FILE_TYPE_UNKNOWN;
/*
* If we can use 'createFile' on this, then we can use the resulting
@@ -2055,48 +2017,29 @@ NativeStat(
* 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.
- *
- * Special consideration must be given to Windows hard-coded names like
- * CON, NULL, COM1, LPT1 etc. For these, we still need to do the
- * CreateFile as some may not exist (e.g. there is no CON in wish by
- * default). However the subsequent GetFileInformationByHandle will
- * fail. We do a WinIsReserved to see if it is one of the special names,
- * and if successful, mock up a BY_HANDLE_FILE_INFORMATION structure.
*/
- fileHandle = CreateFileW(nativePath, GENERIC_READ,
- FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
- NULL, OPEN_EXISTING,
+ 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) {
- fileType = GetFileType(fileHandle);
- CloseHandle(fileHandle);
- if (fileType != FILE_TYPE_CHAR && fileType != FILE_TYPE_DISK) {
- Tcl_SetErrno(ENOENT);
- return -1;
- }
-
- /*
- * Mock up the expected structure
- */
+ CloseHandle(fileHandle);
+ Tcl_SetErrno(ENOENT);
+ return -1;
+ }
+ CloseHandle(fileHandle);
- memset(&data, 0, sizeof(data));
- statPtr->st_atime = 0;
- statPtr->st_mtime = 0;
- statPtr->st_ctime = 0;
- } else {
- CloseHandle(fileHandle);
- statPtr->st_atime = ToCTime(data.ftLastAccessTime);
- statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
- statPtr->st_ctime = ToCTime(data.ftCreationTime);
- }
attr = data.dwFileAttributes;
- statPtr->st_size = ((long long) data.nFileSizeLow) |
- (((long long) data.nFileSizeHigh) << 32);
+
+ statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
+ (((Tcl_WideInt) data.nFileSizeHigh) << 32);
+ statPtr->st_atime = ToCTime(data.ftLastAccessTime);
+ statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
+ statPtr->st_ctime = ToCTime(data.ftCreationTime);
/*
* On Unix, for directories, nlink apparently depends on the number of
@@ -2115,26 +2058,26 @@ NativeStat(
*/
inode = data.nFileIndexHigh | data.nFileIndexLow;
- } else {
+ } else if (tclWinProcs->getFileAttributesExProc != NULL) {
/*
* Fall back on the less capable routines. This means no nlink or ino.
*/
WIN32_FILE_ATTRIBUTE_DATA data;
- if (GetFileAttributesExW(nativePath,
+ if ((*tclWinProcs->getFileAttributesExProc)(nativePath,
GetFileExInfoStandard, &data) != TRUE) {
HANDLE hFind;
- WIN32_FIND_DATAW ffd;
+ WIN32_FIND_DATAT ffd;
DWORD lasterror = GetLastError();
if (lasterror != ERROR_SHARING_VIOLATION) {
- Tcl_WinConvertError(lasterror);
+ TclWinConvertError(lasterror);
return -1;
}
- hFind = FindFirstFileW(nativePath, &ffd);
+ hFind = (*tclWinProcs->findFirstFileProc)(nativePath, &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
return -1;
}
memcpy(&data, &ffd, sizeof(data));
@@ -2143,22 +2086,55 @@ NativeStat(
attr = data.dwFileAttributes;
- statPtr->st_size = ((long long) data.nFileSizeLow) |
- (((long long) data.nFileSizeHigh) << 32);
+ statPtr->st_size = ((Tcl_WideInt) data.nFileSizeLow) |
+ (((Tcl_WideInt) data.nFileSizeHigh) << 32);
statPtr->st_atime = ToCTime(data.ftLastAccessTime);
statPtr->st_mtime = ToCTime(data.ftLastWriteTime);
statPtr->st_ctime = ToCTime(data.ftCreationTime);
+ } else {
+ /*
+ * We don't have the faster attributes proc, so we're probably running
+ * on Win95.
+ */
+
+ WIN32_FIND_DATAT data;
+ HANDLE handle;
+
+ handle = (*tclWinProcs->findFirstFileProc)(nativePath, &data);
+ if (handle == INVALID_HANDLE_VALUE) {
+ /*
+ * FindFirstFile() doesn't work on root directories, so call
+ * GetFileAttributes() to see if the specified file exists.
+ */
+
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
+ if (attr == INVALID_FILE_ATTRIBUTES) {
+ Tcl_SetErrno(ENOENT);
+ return -1;
+ }
+
+ /*
+ * Make up some fake information for this file. It has the correct
+ * file attributes and a time of 0.
+ */
+
+ memset(&data, 0, sizeof(data));
+ data.a.dwFileAttributes = attr;
+ } else {
+ FindClose(handle);
+ }
+
+ attr = data.a.dwFileAttributes;
+
+ statPtr->st_size = ((Tcl_WideInt) data.a.nFileSizeLow) |
+ (((Tcl_WideInt) data.a.nFileSizeHigh) << 32);
+ statPtr->st_atime = ToCTime(data.a.ftLastAccessTime);
+ statPtr->st_mtime = ToCTime(data.a.ftLastWriteTime);
+ statPtr->st_ctime = ToCTime(data.a.ftCreationTime);
}
dev = NativeDev(nativePath);
mode = NativeStatMode(attr, checkLinks, NativeIsExec(nativePath));
- if (fileType == FILE_TYPE_CHAR) {
- mode &= ~S_IFMT;
- mode |= S_IFCHR;
- } else if (fileType == FILE_TYPE_DISK) {
- mode &= ~S_IFMT;
- mode |= S_IFBLK;
- }
statPtr->st_dev = (dev_t) dev;
statPtr->st_ino = inode;
@@ -2182,45 +2158,46 @@ NativeStat(
static int
NativeDev(
- const WCHAR *nativePath) /* Full path of file to stat */
+ const TCHAR *nativePath) /* Full path of file to stat */
{
int dev;
Tcl_DString ds;
WCHAR nativeFullPath[MAX_PATH];
- WCHAR *nativePart;
+ TCHAR *nativePart;
const char *fullPath;
- GetFullPathNameW(nativePath, MAX_PATH, nativeFullPath, &nativePart);
- Tcl_DStringInit(&ds);
- fullPath = Tcl_WCharToUtfDString(nativeFullPath, TCL_INDEX_NONE, &ds);
+ (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH,
+ nativeFullPath, &nativePart);
+
+ fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds);
if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
const char *p;
DWORD dw;
- const WCHAR *nativeVol;
+ const TCHAR *nativeVol;
Tcl_DString volString;
p = strchr(fullPath + 2, '\\');
p = strchr(p + 1, '\\');
if (p == NULL) {
/*
- * Add terminating backslash to fullpath or GetVolumeInformationW()
+ * Add terminating backslash to fullpath or GetVolumeInformation()
* won't work.
*/
- fullPath = TclDStringAppendLiteral(&ds, "\\");
+ fullPath = Tcl_DStringAppend(&ds, "\\", 1);
p = fullPath + Tcl_DStringLength(&ds);
} else {
p++;
}
- Tcl_DStringInit(&volString);
- nativeVol = Tcl_UtfToWCharDString(fullPath, p - fullPath, &volString);
+ nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);
dw = (DWORD) -1;
- GetVolumeInformationW(nativeVol, NULL, 0, &dw, NULL, NULL, NULL, 0);
+ (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw,
+ NULL, NULL, NULL, 0);
/*
- * GetFullPathNameW() turns special devices like "NUL" into "\\.\NUL",
- * but GetVolumeInformationW() returns failure for "\\.\NUL". This will
+ * 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.
@@ -2288,7 +2265,7 @@ NativeStatMode(
*
* ToCTime --
*
- * Converts a Windows FILETIME to a __time64_t in UTC.
+ * Converts a Windows FILETIME to a time_t in UTC.
*
* Results:
* Returns the count of seconds from the Posix epoch.
@@ -2296,7 +2273,7 @@ NativeStatMode(
*------------------------------------------------------------------------
*/
-static __time64_t
+static time_t
ToCTime(
FILETIME fileTime) /* UTC time */
{
@@ -2305,8 +2282,8 @@ ToCTime(
convertedTime.LowPart = fileTime.dwLowDateTime;
convertedTime.HighPart = (LONG) fileTime.dwHighDateTime;
- return (__time64_t) ((convertedTime.QuadPart -
- (long long) POSIX_EPOCH_AS_FILETIME) / (long long) 10000000);
+ return (time_t) ((convertedTime.QuadPart -
+ (Tcl_WideInt) POSIX_EPOCH_AS_FILETIME) / (Tcl_WideInt) 10000000);
}
/*
@@ -2314,7 +2291,7 @@ ToCTime(
*
* FromCTime --
*
- * Converts a __time64_t to a Windows FILETIME
+ * Converts a time_t to a Windows FILETIME
*
* Results:
* Returns the count of 100-ns ticks seconds from the Windows epoch.
@@ -2324,13 +2301,12 @@ ToCTime(
static void
FromCTime(
- __time64_t posixTime,
+ time_t posixTime,
FILETIME *fileTime) /* UTC Time */
{
LARGE_INTEGER convertedTime;
-
convertedTime.QuadPart = ((LONGLONG) posixTime) * 10000000
- + POSIX_EPOCH_AS_FILETIME;
+ + POSIX_EPOCH_AS_FILETIME;
fileTime->dwLowDateTime = convertedTime.LowPart;
fileTime->dwHighDateTime = convertedTime.HighPart;
}
@@ -2347,7 +2323,7 @@ FromCTime(
* 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
+ * If NULL is returned, the caller can examine the standard posix error
* codes to determine the cause of the problem.
*
* Side effects:
@@ -2356,24 +2332,38 @@ FromCTime(
*----------------------------------------------------------------------
*/
-void *
+ClientData
TclpGetNativeCwd(
- void *clientData)
+ ClientData clientData)
{
WCHAR buffer[MAX_PATH];
- if (GetCurrentDirectoryW(MAX_PATH, buffer) == 0) {
- Tcl_WinConvertError(GetLastError());
+ if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) {
+ TclWinConvertError(GetLastError());
return NULL;
}
if (clientData != NULL) {
- if (wcscmp((const WCHAR *) clientData, buffer) == 0) {
- return clientData;
+ if (tclWinProcs->useWide) {
+ /*
+ * Unicode representation when running on NT/2K/XP.
+ */
+
+ if (wcscmp((const WCHAR*)clientData, (const WCHAR*)buffer) == 0) {
+ return clientData;
+ }
+ } else {
+ /*
+ * ANSI representation when running on 95/98/ME.
+ */
+
+ if (strcmp((const char*) clientData, (const char*) buffer) == 0) {
+ return clientData;
+ }
}
}
- return TclNativeDupInternalRep(buffer);
+ return TclNativeDupInternalRep((ClientData) buffer);
}
int
@@ -2381,7 +2371,7 @@ TclpObjAccess(
Tcl_Obj *pathPtr,
int mode)
{
- return NativeAccess((const WCHAR *)Tcl_FSGetNativePath(pathPtr), mode);
+ return NativeAccess((const TCHAR *) Tcl_FSGetNativePath(pathPtr), mode);
}
int
@@ -2397,7 +2387,8 @@ TclpObjLstat(
TclWinFlushDirtyChannels();
- return NativeStat((const WCHAR *)Tcl_FSGetNativePath(pathPtr), statPtr, 1);
+ return NativeStat((const TCHAR *) Tcl_FSGetNativePath(pathPtr),
+ statPtr, 1);
}
#ifdef S_IFLNK
@@ -2409,15 +2400,15 @@ TclpObjLink(
{
if (toPtr != NULL) {
int res;
- const WCHAR *LinkTarget;
- const WCHAR *LinkSource = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ TCHAR *LinkTarget;
+ TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
Tcl_Obj *normalizedToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr);
if (normalizedToPtr == NULL) {
return NULL;
}
- LinkTarget = (const WCHAR *)Tcl_FSGetNativePath(normalizedToPtr);
+ LinkTarget = (TCHAR *) Tcl_FSGetNativePath(normalizedToPtr);
if (LinkSource == NULL || LinkTarget == NULL) {
return NULL;
@@ -2429,7 +2420,7 @@ TclpObjLink(
return NULL;
}
} else {
- const WCHAR *LinkSource = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
if (LinkSource == NULL) {
return NULL;
@@ -2437,7 +2428,7 @@ TclpObjLink(
return WinReadLink(LinkSource);
}
}
-#endif /* S_IFLNK */
+#endif
/*
*---------------------------------------------------------------------------
@@ -2471,21 +2462,23 @@ TclpFilesystemPathType(
if (normPath == NULL) {
return NULL;
}
- path = TclGetString(normPath);
+ path = Tcl_GetString(normPath);
if (path == NULL) {
return NULL;
}
- firstSeparator = strchr((char *)path, '/');
+ firstSeparator = strchr(path, '/');
if (firstSeparator == NULL) {
- found = GetVolumeInformationW((const WCHAR *)Tcl_FSGetNativePath(pathPtr),
- NULL, 0, NULL, NULL, NULL, volType, VOL_BUF_SIZE);
+ found = tclWinProcs->getVolumeInformationProc(
+ Tcl_FSGetNativePath(pathPtr), NULL, 0, NULL, NULL, NULL,
+ (WCHAR *) volType, VOL_BUF_SIZE);
} else {
Tcl_Obj *driveName = Tcl_NewStringObj(path, firstSeparator - path+1);
Tcl_IncrRefCount(driveName);
- found = GetVolumeInformationW((const WCHAR *)Tcl_FSGetNativePath(driveName),
- NULL, 0, NULL, NULL, NULL, volType, VOL_BUF_SIZE);
+ found = tclWinProcs->getVolumeInformationProc(
+ Tcl_FSGetNativePath(driveName), NULL, 0, NULL, NULL, NULL,
+ (WCHAR *) volType, VOL_BUF_SIZE);
Tcl_DecrRefCount(driveName);
}
@@ -2493,10 +2486,13 @@ TclpFilesystemPathType(
return NULL;
} else {
Tcl_DString ds;
+ Tcl_Obj *objPtr;
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString(volType, TCL_INDEX_NONE, &ds);
- return Tcl_DStringToObj(&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
}
@@ -2538,257 +2534,409 @@ TclpFilesystemPathType(
int
TclpObjNormalizePath(
- TCL_UNUSED(Tcl_Interp *),
- Tcl_Obj *pathPtr, /* An unshared object containing the path to
- * normalize */
- int nextCheckpoint) /* offset to start at in pathPtr */
+ Tcl_Interp *interp,
+ Tcl_Obj *pathPtr,
+ int nextCheckpoint)
{
char *lastValidPathEnd = NULL;
Tcl_DString dsNorm; /* This will hold the normalized string. */
char *path, *currentPathEndPosition;
Tcl_Obj *temp = NULL;
- int isDrive = 1;
- Tcl_DString ds; /* Some workspace. */
Tcl_DStringInit(&dsNorm);
- path = TclGetString(pathPtr);
+ path = Tcl_GetString(pathPtr);
- currentPathEndPosition = path + nextCheckpoint;
- if (*currentPathEndPosition == '/') {
- currentPathEndPosition++;
- }
- while (1) {
- char cur = *currentPathEndPosition;
+ 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.
+ */
- if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
- /*
- * Reached directory separator, or end of string.
- */
+ int isDrive = 1;
+ Tcl_DString ds;
- WIN32_FILE_ATTRIBUTE_DATA data;
- const WCHAR *nativePath;
+ currentPathEndPosition = path + nextCheckpoint;
+ if (*currentPathEndPosition == '/') {
+ currentPathEndPosition++;
+ }
- Tcl_DStringInit(&ds);
- nativePath = Tcl_UtfToWCharDString(path,
- currentPathEndPosition - path, &ds);
+ while (1) {
+ char cur = *currentPathEndPosition;
- if (GetFileAttributesExW(nativePath,
- GetFileExInfoStandard, &data) != TRUE) {
+ if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
/*
- * File doesn't exist.
+ * Reached directory separator, or end of string.
*/
- if (isDrive) {
- size_t len = WinIsReserved(path);
+ const char *nativePath = Tcl_UtfToExternalDString(NULL, path,
+ currentPathEndPosition - path, &ds);
- if (len > 0) {
+ /*
+ * 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) {
/*
- * Actually it does exist - COM1, etc.
+ * File doesn't exist.
*/
- size_t i;
-
- for (i=0 ; i<len ; i++) {
- WCHAR wc = ((WCHAR *)nativePath)[i];
-
- if (wc >= 'a') {
- wc -= ('a' - 'A');
- ((WCHAR *) nativePath)[i] = wc;
+ if (isDrive) {
+ int len = WinIsReserved(path);
+
+ if (len > 0) {
+ /*
+ * Actually it does exist - COM1, etc.
+ */
+
+ int i;
+
+ for (i=0 ; i<len ; i++) {
+ if (nativePath[i] >= 'a') {
+ ((char *) nativePath)[i] -= ('a'-'A');
+ }
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath, len);
+ lastValidPathEnd = currentPathEndPosition;
+ } else if (nextCheckpoint == 0) {
+ /* Path starts with a drive designation
+ * that's not actually on the system.
+ * We still must normalize up past the
+ * first separator. [Bug 3603434] */
+ currentPathEndPosition++;
+ }
+ }
+ Tcl_DStringFree(&ds);
+ break;
+ }
+ if (nativePath[0] >= 'a') {
+ ((char *) nativePath)[0] -= ('a' - 'A');
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath,
+ Tcl_DStringLength(&ds));
+ } else {
+ char *checkDots = NULL;
+
+ if (lastValidPathEnd[1] == '.') {
+ checkDots = lastValidPathEnd + 1;
+ while (checkDots < currentPathEndPosition) {
+ if (*checkDots != '.') {
+ checkDots = NULL;
+ break;
}
+ checkDots++;
}
- Tcl_DStringAppend(&dsNorm,
- (const char *)nativePath,
- sizeof(WCHAR) * len);
- lastValidPathEnd = currentPathEndPosition;
- } else if (nextCheckpoint == 0) {
+ }
+ 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);
+ } else {
/*
- * Path starts with a drive designation that's not
- * actually on the system. We still must normalize up
- * past the first separator. [Bug 3603434]
+ * Normal path.
*/
- currentPathEndPosition++;
+ 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);
+ } else {
+ char *nativeName;
+
+ if (fData.cFileName[0] != '\0') {
+ nativeName = fData.cFileName;
+ } else {
+ nativeName = fData.cAlternateFileName;
+ }
+ FindClose(handle);
+ Tcl_DStringAppend(&dsNorm,"/", 1);
+ Tcl_DStringAppend(&dsNorm,nativeName,-1);
+ }
}
}
Tcl_DStringFree(&ds);
- break;
+ lastValidPathEnd = currentPathEndPosition;
+ if (cur == 0) {
+ break;
+ }
+
+ /*
+ * If we get here, we've got past one directory delimiter, so
+ * we know it is no longer a drive.
+ */
+
+ isDrive = 0;
}
+ currentPathEndPosition++;
+ }
+ } else {
+ /*
+ * We're on WinNT (or 2000 or XP; something with an NT core).
+ */
- /*
- * 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.
- */
+ int isDrive = 1;
+ Tcl_DString ds;
- /*
- * 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.
- */
+ currentPathEndPosition = path + nextCheckpoint;
+ if (*currentPathEndPosition == '/') {
+ currentPathEndPosition++;
+ }
+ while (1) {
+ char cur = *currentPathEndPosition;
- if (cur != 0 && !isDrive &&
- data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
- Tcl_Obj *to = WinReadLinkDirectory(nativePath);
+ if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
+ /*
+ * Reached directory separator, or end of string.
+ */
- if (to != NULL) {
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ const char *nativePath = Tcl_WinUtfToTChar(path,
+ currentPathEndPosition - path, &ds);
+
+ if ((*tclWinProcs->getFileAttributesExProc)(nativePath,
+ GetFileExInfoStandard, &data) != TRUE) {
/*
- * 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.
+ * File doesn't exist.
*/
- nextCheckpoint = 0;
- Tcl_AppendToObj(to, currentPathEndPosition, TCL_INDEX_NONE);
+ if (isDrive) {
+ int len = WinIsReserved(path);
- /*
- * Convert link to forward slashes.
- */
+ if (len > 0) {
+ /*
+ * Actually it does exist - COM1, etc.
+ */
- for (path = TclGetString(to); *path != 0; path++) {
- if (*path == '\\') {
- *path = '/';
- }
- }
- path = TclGetString(to);
- currentPathEndPosition = path + nextCheckpoint;
- if (temp != NULL) {
- Tcl_DecrRefCount(temp);
- }
- temp = to;
+ int i;
- /*
- * Reset variables so we can restart normalization.
- */
+ for (i=0 ; i<len ; i++) {
+ WCHAR wc = ((WCHAR *) nativePath)[i];
- isDrive = 1;
- Tcl_DStringFree(&dsNorm);
+ if (wc >= L'a') {
+ wc -= (L'a' - L'A');
+ ((WCHAR *) nativePath)[i] = wc;
+ }
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath,
+ (int)(sizeof(WCHAR) * len));
+ lastValidPathEnd = currentPathEndPosition;
+ } else if (nextCheckpoint == 0) {
+ /* Path starts with a drive designation
+ * that's not actually on the system.
+ * We still must normalize up past the
+ * first separator. [Bug 3603434] */
+ currentPathEndPosition++;
+ }
+ }
Tcl_DStringFree(&ds);
- continue;
+ break;
}
- }
-#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
- */
+ /*
+ * 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.
+ */
- if (isDrive) {
- WCHAR drive = ((WCHAR *) nativePath)[0];
+ /*
+ * 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 (drive >= 'a') {
- drive -= ('a' - 'A');
- ((WCHAR *) nativePath)[0] = drive;
- }
- Tcl_DStringAppend(&dsNorm, (const char *)nativePath,
- Tcl_DStringLength(&ds));
- } else {
- char *checkDots = NULL;
-
- if (lastValidPathEnd[1] == '.') {
- checkDots = lastValidPathEnd + 1;
- while (checkDots < currentPathEndPosition) {
- if (*checkDots != '.') {
- checkDots = NULL;
- break;
+ 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;
+ Tcl_AppendToObj(to, currentPathEndPosition, -1);
+
+ /*
+ * Convert link to forward slashes.
+ */
+
+ for (path = Tcl_GetString(to); *path != 0; path++) {
+ if (*path == '\\') {
+ *path = '/';
+ }
}
- checkDots++;
+ path = Tcl_GetString(to);
+ currentPathEndPosition = path + nextCheckpoint;
+ if (temp != NULL) {
+ Tcl_DecrRefCount(temp);
+ }
+ temp = to;
+
+ /*
+ * Reset variables so we can restart normalization.
+ */
+
+ isDrive = 1;
+ Tcl_DStringFree(&dsNorm);
+ Tcl_DStringInit(&dsNorm);
+ Tcl_DStringFree(&ds);
+ continue;
}
}
- 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.
- */
+#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
+ */
- Tcl_DStringAppend(&dsNorm, ((const char *)nativePath)
- + Tcl_DStringLength(&ds)
- - (dotLen * sizeof(WCHAR)),
- dotLen * sizeof(WCHAR));
+ if (isDrive) {
+ WCHAR drive = ((WCHAR *) nativePath)[0];
+ if (drive >= L'a') {
+ drive -= (L'a' - L'A');
+ ((WCHAR *) nativePath)[0] = drive;
+ }
+ Tcl_DStringAppend(&dsNorm, nativePath,
+ Tcl_DStringLength(&ds));
} else {
- /*
- * Normal path.
- */
-
- WIN32_FIND_DATAW fData;
- HANDLE handle;
+ char *checkDots = NULL;
+
+ if (lastValidPathEnd[1] == '.') {
+ checkDots = lastValidPathEnd + 1;
+ while (checkDots < currentPathEndPosition) {
+ if (*checkDots != '.') {
+ checkDots = NULL;
+ break;
+ }
+ checkDots++;
+ }
+ }
+ if (checkDots != NULL) {
+ int dotLen = currentPathEndPosition-lastValidPathEnd;
- handle = FindFirstFileW((WCHAR *) nativePath, &fData);
- if (handle == INVALID_HANDLE_VALUE) {
/*
- * This is usually the '/' in 'c:/' at end of string.
+ * 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, (const char *) L"/",
- sizeof(WCHAR));
+ Tcl_DStringAppend(&dsNorm, (TCHAR *)
+ ((WCHAR*)(nativePath + Tcl_DStringLength(&ds))
+ - dotLen), (int)(dotLen * sizeof(WCHAR)));
} else {
- WCHAR *nativeName;
+ /*
+ * Normal path.
+ */
- if (fData.cFileName[0] != '\0') {
- nativeName = fData.cFileName;
+ WIN32_FIND_DATAW fData;
+ HANDLE handle;
+
+ handle = FindFirstFileW((WCHAR *) nativePath, &fData);
+ if (handle == INVALID_HANDLE_VALUE) {
+ /*
+ * This is usually the '/' in 'c:/' at end of
+ * string.
+ */
+
+ Tcl_DStringAppend(&dsNorm, (const char *) L"/",
+ sizeof(WCHAR));
} else {
- nativeName = fData.cAlternateFileName;
+ 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)));
}
- FindClose(handle);
- Tcl_DStringAppend(&dsNorm, (const char *) L"/",
- sizeof(WCHAR));
- Tcl_DStringAppend(&dsNorm,
- (const char *) nativeName,
- wcslen(nativeName)*sizeof(WCHAR));
}
}
- }
-#endif /* !TclNORM_LONG_PATH */
- Tcl_DStringFree(&ds);
- lastValidPathEnd = currentPathEndPosition;
- if (cur == 0) {
- break;
- }
+#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;
+ isDrive = 0;
+ }
+ currentPathEndPosition++;
}
- currentPathEndPosition++;
#ifdef TclNORM_LONG_PATH
/*
* Convert the entire known path to long form.
*/
- WCHAR wpath[MAX_PATH];
- const WCHAR *nativePath;
- DWORD wpathlen;
+ if (1) {
+ WCHAR wpath[MAX_PATH];
+ const char *nativePath =
+ Tcl_WinUtfToTChar(path, lastValidPathEnd - path, &ds);
+ DWORD wpathlen = (*tclWinProcs->getLongPathNameProc)(
+ nativePath, (TCHAR *) wpath, MAX_PATH);
- Tcl_DStringInit(&ds);
- nativePath =
- Tcl_UtfToWCharDString(path, lastValidPathEnd - path, &ds);
- wpathlen = GetLongPathNameProc(nativePath,
- (WCHAR *) wpath, MAX_PATH);
- /*
- * We have to make the drive letter uppercase.
- */
+ /*
+ * We have to make the drive letter uppercase.
+ */
- if (wpath[0] >= 'a') {
- wpath[0] -= ('a' - 'A');
+ if (wpath[0] >= L'a') {
+ wpath[0] -= (L'a' - L'A');
+ }
+ Tcl_DStringAppend(&dsNorm, (TCHAR*)wpath, wpathlen*sizeof(WCHAR));
+ Tcl_DStringFree(&ds);
}
- Tcl_DStringAppend(&dsNorm, (const char *) wpath,
- wpathlen * sizeof(WCHAR));
- Tcl_DStringFree(&ds);
-#endif /* TclNORM_LONG_PATH */
+#endif
}
/*
@@ -2803,22 +2951,24 @@ TclpObjNormalizePath(
* native encoding, so we have to convert it to Utf.
*/
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString((const WCHAR *) Tcl_DStringValue(&dsNorm),
- Tcl_DStringLength(&dsNorm)>>1, &ds);
- nextCheckpoint = Tcl_DStringLength(&ds);
+ Tcl_DString dsTemp;
+
+ Tcl_WinTCharToUtf(Tcl_DStringValue(&dsNorm),
+ Tcl_DStringLength(&dsNorm), &dsTemp);
+ nextCheckpoint = Tcl_DStringLength(&dsTemp);
if (*lastValidPathEnd != 0) {
/*
* Not the end of the string.
*/
+ int len;
+ char *path;
Tcl_Obj *tmpPathPtr;
- Tcl_Size len;
- tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),
+ tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp),
nextCheckpoint);
- Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, TCL_INDEX_NONE);
- path = TclGetStringFromObj(tmpPathPtr, &len);
+ Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1);
+ path = Tcl_GetStringFromObj(tmpPathPtr, &len);
Tcl_SetStringObj(pathPtr, path, len);
Tcl_DecrRefCount(tmpPathPtr);
} else {
@@ -2826,9 +2976,10 @@ TclpObjNormalizePath(
* End of string was reached above.
*/
- Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&ds), nextCheckpoint);
+ Tcl_SetStringObj(pathPtr, Tcl_DStringValue(&dsTemp),
+ nextCheckpoint);
}
- Tcl_DStringFree(&ds);
+ Tcl_DStringFree(&dsTemp);
}
Tcl_DStringFree(&dsNorm);
@@ -2840,7 +2991,6 @@ TclpObjNormalizePath(
if (temp != NULL) {
Tcl_DecrRefCount(temp);
}
-
return nextCheckpoint;
}
@@ -2887,10 +3037,10 @@ TclWinVolumeRelativeNormalize(
* current volume.
*/
- const char *drive = TclGetString(useThisCwd);
+ const char *drive = Tcl_GetString(useThisCwd);
absolutePath = Tcl_NewStringObj(drive,2);
- Tcl_AppendToObj(absolutePath, path, TCL_INDEX_NONE);
+ Tcl_AppendToObj(absolutePath, path, -1);
Tcl_IncrRefCount(absolutePath);
/*
@@ -2902,8 +3052,9 @@ TclWinVolumeRelativeNormalize(
* also on drive C.
*/
- Tcl_Size cwdLen;
- const char *drive = TclGetStringFromObj(useThisCwd, &cwdLen);
+ int cwdLen;
+ const char *drive =
+ Tcl_GetStringFromObj(useThisCwd, &cwdLen);
char drive_cur = path[0];
if (drive_cur >= 'a') {
@@ -2943,7 +3094,7 @@ TclWinVolumeRelativeNormalize(
Tcl_AppendToObj(absolutePath, "/", 1);
}
Tcl_IncrRefCount(absolutePath);
- Tcl_AppendToObj(absolutePath, path+2, TCL_INDEX_NONE);
+ Tcl_AppendToObj(absolutePath, path+2, -1);
}
*useThisCwdPtr = useThisCwd;
return absolutePath;
@@ -2972,15 +3123,14 @@ TclWinVolumeRelativeNormalize(
Tcl_Obj *
TclpNativeToNormalized(
- void *clientData)
+ ClientData clientData)
{
Tcl_DString ds;
Tcl_Obj *objPtr;
- Tcl_Size len;
+ int len;
char *copy, *p;
- Tcl_DStringInit(&ds);
- Tcl_WCharToUtfDString((const WCHAR *) clientData, TCL_INDEX_NONE, &ds);
+ Tcl_WinTCharToUtf((const char *) clientData, -1, &ds);
copy = Tcl_DStringValue(&ds);
len = Tcl_DStringLength(&ds);
@@ -3027,20 +3177,19 @@ TclpNativeToNormalized(
* The nativePath representation.
*
* Side effects:
- * Memory will be allocated. The path might be normalized.
+ * Memory will be allocated. The path may need to be normalized.
*
*---------------------------------------------------------------------------
*/
-void *
+ClientData
TclNativeCreateNativeRep(
Tcl_Obj *pathPtr)
{
- WCHAR *nativePathPtr = NULL;
- const char *str;
+ char *nativePathPtr, *str;
+ Tcl_DString ds;
Tcl_Obj *validPathPtr;
- Tcl_Size len;
- WCHAR *wp;
+ int len;
if (TclFSCwdIsNative()) {
/*
@@ -3053,11 +3202,6 @@ TclNativeCreateNativeRep(
if (validPathPtr == NULL) {
return NULL;
}
-
- /*
- * refCount of validPathPtr was already incremented in
- * Tcl_FSGetTranslatedPath
- */
} else {
/*
* Make sure the normalized path is set.
@@ -3067,113 +3211,87 @@ TclNativeCreateNativeRep(
if (validPathPtr == NULL) {
return NULL;
}
-
- /*
- * validPathPtr returned from Tcl_FSGetNormalizedPath is owned by Tcl,
- * so incr refCount here
- */
-
Tcl_IncrRefCount(validPathPtr);
}
- str = TclGetStringFromObj(validPathPtr, &len);
-
- if (strlen(str) != (size_t)len) {
+ str = Tcl_GetStringFromObj(validPathPtr, &len);
+ Tcl_WinUtfToTChar(str, len, &ds);
+ if (tclWinProcs->useWide) {
+ WCHAR *wp = (WCHAR *) Tcl_DStringValue(&ds);
+ /* For a reserved device, strip a possible postfix ':' */
+ len = WinIsReserved(str);
+ /* For normal devices */
+ if (len == 0) len = Tcl_DStringLength(&ds)>>1;
/*
- * String contains NUL-bytes. This is invalid.
- */
-
- goto done;
- }
-
- /*
- * For a reserved device, strip a possible postfix ':'
- */
-
- len = WinIsReserved(str);
- if (len == 0) {
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ wp[0] = wp[1] = wp[3] = '\\';
+ str += 4;
+ wp += 4;
+ len -= 4;
+ }
/*
- * Let MultiByteToWideChar check for other invalid sequences, like
- * 0xC0 0x80 (== overlong NUL). See bug [3118489]: NUL in filenames
- */
-
- len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, 0, 0);
- if (len==0) {
- goto done;
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ wp += 2;
+ len -= 2;
}
- }
-
- /*
- * Overallocate 6 chars, making some room for extended paths
- */
-
- wp = nativePathPtr = (WCHAR *)ckalloc((len + 6) * sizeof(WCHAR));
- if (nativePathPtr==0) {
- goto done;
- }
- MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, nativePathPtr,
- len + 2);
- nativePathPtr[len] = 0;
-
- /*
- * If path starts with "//?/" or "\\?\" (extended path), translate any
- * slashes to backslashes but leave the '?' intact
- */
-
- if ((str[0] == '\\' || str[0] == '/') && (str[1] == '\\' || str[1] == '/')
- && str[2] == '?' && (str[3] == '\\' || str[3] == '/')) {
- wp[0] = wp[1] = wp[3] = '\\';
- str += 4;
- wp += 4;
- }
-
- /*
- * If there is no "\\?\" prefix but there is a drive or UNC path prefix
- * and the path is larger than MAX_PATH chars, no Win32 API function can
- * handle that unless it is prefixed with the extended path prefix. See:
- * <https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maxpath>
- */
-
- if (((str[0] >= 'A' && str[0] <= 'Z') || (str[0] >= 'a' && str[0] <= 'z'))
- && str[1] == ':') {
- if (wp == nativePathPtr && len > MAX_PATH
- && (str[2] == '\\' || str[2] == '/')) {
- memmove(wp + 4, wp, len * sizeof(WCHAR));
- memcpy(wp, L"\\\\?\\", 4 * sizeof(WCHAR));
- wp += 4;
+ while (len-->0) {
+ if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*wp=='/') {
+ *wp = '\\';
+ }
+ ++wp;
}
-
+ len = Tcl_DStringLength(&ds) + sizeof(WCHAR);
+ } else {
+ char *p = Tcl_DStringValue(&ds);
+ len = Tcl_DStringLength(&ds);
/*
- * If (remainder of) path starts with "<drive>:", leave the ':'
- * intact.
- */
-
- wp += 2;
- } else if (wp == nativePathPtr && len > MAX_PATH
- && (str[0] == '\\' || str[0] == '/')
- && (str[1] == '\\' || str[1] == '/') && str[2] != '?') {
- memmove(wp + 6, wp, len * sizeof(WCHAR));
- memcpy(wp, L"\\\\?\\UNC", 7 * sizeof(WCHAR));
- wp += 7;
- }
-
- /*
- * In the remainder of the path, translate invalid characters to
- * characters in the Unicode private use area.
- */
-
- while (*wp != '\0') {
- if ((*wp < ' ') || wcschr(L"\"*:<>?|", *wp)) {
- *wp |= 0xF000;
- } else if (*wp == '/') {
- *wp = '\\';
+ ** If path starts with "//?/" or "\\?\" (extended path), translate
+ ** any slashes to backslashes but accept the '?' as being valid.
+ */
+ if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
+ && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
+ p[0] = p[1] = p[3] = '\\';
+ str += 4;
+ p += 4;
+ len -= 4;
+ }
+ /*
+ ** If there is a drive prefix, the ':' must be considered valid.
+ **/
+ if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
+ && str[1]==':') {
+ p += 2;
+ len -= 2;
+ }
+ while (len-->0) {
+ if ((*p < ' ') || strchr("\"*:<>?|", *p)) {
+ Tcl_DecrRefCount(validPathPtr);
+ Tcl_DStringFree(&ds);
+ return NULL;
+ } else if (*p=='/') {
+ *p = '\\';
+ }
+ ++p;
}
- ++wp;
+ len = Tcl_DStringLength(&ds) + sizeof(char);
}
+ Tcl_DecrRefCount(validPathPtr);
+ nativePathPtr = ckalloc((unsigned) len);
+ memcpy(nativePathPtr, Tcl_DStringValue(&ds), (size_t) len);
- done:
- TclDecrRefCount(validPathPtr);
- return nativePathPtr;
+ Tcl_DStringFree(&ds);
+ return (ClientData) nativePathPtr;
}
/*
@@ -3193,9 +3311,9 @@ TclNativeCreateNativeRep(
*---------------------------------------------------------------------------
*/
-void *
+ClientData
TclNativeDupInternalRep(
- void *clientData)
+ ClientData clientData)
{
char *copy;
size_t len;
@@ -3204,11 +3322,23 @@ TclNativeDupInternalRep(
return NULL;
}
- len = sizeof(WCHAR) * (wcslen((const WCHAR *) clientData) + 1);
+ 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.
+ */
- copy = (char *)ckalloc(len);
+ len = sizeof(char) * (strlen((const char *) clientData) + 1);
+ }
+
+ copy = (char *) ckalloc(len);
memcpy(copy, clientData, len);
- return copy;
+ return (ClientData) copy;
}
/*
@@ -3235,7 +3365,7 @@ TclpUtime(
{
int res = 0;
HANDLE fileHandle;
- const WCHAR *native;
+ const TCHAR *native;
DWORD attr = 0;
DWORD flags = FILE_ATTRIBUTE_NORMAL;
FILETIME lastAccessTime, lastModTime;
@@ -3243,9 +3373,9 @@ TclpUtime(
FromCTime(tval->actime, &lastAccessTime);
FromCTime(tval->modtime, &lastModTime);
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
+ native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
- attr = GetFileAttributesW(native);
+ attr = (*tclWinProcs->getFileAttributesProc)(native);
if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY) {
flags = FILE_FLAG_BACKUP_SEMANTICS;
@@ -3256,12 +3386,12 @@ TclpUtime(
* savings complications that utime gets wrong.
*/
- fileHandle = CreateFileW(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)) {
- Tcl_WinConvertError(GetLastError());
+ TclWinConvertError(GetLastError());
res = -1;
}
if (fileHandle != INVALID_HANDLE_VALUE) {
@@ -3271,80 +3401,6 @@ TclpUtime(
}
/*
- *---------------------------------------------------------------------------
- *
- * TclWinFileOwned --
- *
- * Returns 1 if the specified file exists and is owned by the current
- * user and 0 otherwise. Like the Unix case, the check is made using
- * the real process SID, not the effective (impersonation) one.
- *
- *---------------------------------------------------------------------------
- */
-
-int
-TclWinFileOwned(
- Tcl_Obj *pathPtr) /* File whose ownership is to be checked */
-{
- const WCHAR *native;
- PSID ownerSid = NULL;
- PSECURITY_DESCRIPTOR secd = NULL;
- HANDLE token;
- LPBYTE buf = NULL;
- DWORD bufsz;
- int owned = 0;
-
- native = (const WCHAR *)Tcl_FSGetNativePath(pathPtr);
-
- if (GetNamedSecurityInfoW((LPWSTR) native, SE_FILE_OBJECT,
- OWNER_SECURITY_INFORMATION, &ownerSid, NULL, NULL, NULL,
- &secd) != ERROR_SUCCESS) {
- /*
- * Either not a file, or we do not have access to it in which case we
- * are in all likelihood not the owner.
- */
-
- return 0;
- }
-
- /*
- * Getting the current process SID is a multi-step process. We make the
- * assumption that if a call fails, this process is so underprivileged it
- * could not possibly own anything. Normally a process can *always* look
- * up its own token.
- */
-
- if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) {
- /*
- * Find out how big the buffer needs to be.
- */
-
- bufsz = 0;
- GetTokenInformation(token, TokenUser, NULL, 0, &bufsz);
- if (bufsz) {
- buf = (LPBYTE)ckalloc(bufsz);
- if (GetTokenInformation(token, TokenUser, buf, bufsz, &bufsz)) {
- owned = EqualSid(ownerSid, ((PTOKEN_USER) buf)->User.Sid);
- }
- }
- CloseHandle(token);
- }
-
- /*
- * Free allocations and be done.
- */
-
- if (secd) {
- LocalFree(secd); /* Also frees ownerSid */
- }
- if (buf) {
- ckfree(buf);
- }
-
- return (owned != 0); /* Convert non-0 to 1 */
-}
-
-/*
* Local Variables:
* mode: c
* c-basic-offset: 4