summaryrefslogtreecommitdiffstats
path: root/win/tclWinFile.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinFile.c')
-rwxr-xr-xwin/tclWinFile.c1414
1 files changed, 853 insertions, 561 deletions
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index 25c6ea4..41de4a8 100755
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -16,12 +16,9 @@
#include "tclFileSystem.h"
#include <winioctl.h>
#include <shlobj.h>
-#include <lm.h> /* For TclpGetUserHome(). */
+#include <lmaccess.h> /* For TclpGetUserHome(). */
#include <userenv.h> /* For TclpGetUserHome(). */
-#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).
@@ -144,6 +141,28 @@ 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.
*/
@@ -151,6 +170,18 @@ typedef struct {
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:
*/
@@ -176,7 +207,6 @@ static int WinLink(const TCHAR *LinkSource,
const TCHAR *LinkTarget, int linkAction);
static int WinSymLinkDirectory(const TCHAR *LinkDirectory,
const TCHAR *LinkTarget);
-MODULE_SCOPE TCL_NORETURN void tclWinDebugPanic(const char *format, ...);
/*
*--------------------------------------------------------------------
@@ -194,7 +224,7 @@ WinLink(
const TCHAR *linkTargetPath,
int linkAction)
{
- TCHAR tempFileName[MAX_PATH];
+ WCHAR tempFileName[MAX_PATH];
TCHAR *tempFilePart;
DWORD attr;
@@ -202,8 +232,8 @@ WinLink(
* Get the full path referenced by the target.
*/
- if (!GetFullPathName(linkTargetPath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkTargetPath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
@@ -216,7 +246,7 @@ WinLink(
* Make sure source file doesn't exist.
*/
- attr = GetFileAttributes(linkSourcePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
if (attr != INVALID_FILE_ATTRIBUTES) {
Tcl_SetErrno(EEXIST);
return -1;
@@ -226,8 +256,8 @@ WinLink(
* Get the full path referenced by the source file/directory.
*/
- if (!GetFullPathName(linkSourcePath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
@@ -240,36 +270,43 @@ WinLink(
* Check the target.
*/
- attr = GetFileAttributes(linkTargetPath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkTargetPath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The target doesn't exist.
*/
TclWinConvertError(GetLastError());
+ return -1;
+
} else if ((attr & FILE_ATTRIBUTE_DIRECTORY) == 0) {
/*
* It is a file.
*/
- if (linkAction & TCL_CREATE_HARD_LINK) {
- if (CreateHardLink(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;
- TclWinConvertError(GetLastError());
} else if (linkAction & TCL_CREATE_SYMBOLIC_LINK) {
/*
* Can't symlink files.
*/
Tcl_SetErrno(ENOTDIR);
+ return -1;
} else {
Tcl_SetErrno(ENODEV);
+ return -1;
}
} else {
/*
@@ -286,11 +323,12 @@ WinLink(
*/
Tcl_SetErrno(EISDIR);
+ return -1;
} else {
Tcl_SetErrno(ENODEV);
+ return -1;
}
}
- return -1;
}
/*
@@ -307,7 +345,7 @@ static Tcl_Obj *
WinReadLink(
const TCHAR *linkSourcePath)
{
- TCHAR tempFileName[MAX_PATH];
+ WCHAR tempFileName[MAX_PATH];
TCHAR *tempFilePart;
DWORD attr;
@@ -315,8 +353,8 @@ WinReadLink(
* Get the full path referenced by the target.
*/
- if (!GetFullPathName(linkSourcePath, MAX_PATH, tempFileName,
- &tempFilePart)) {
+ if (!(*tclWinProcs->getFullPathNameProc)(linkSourcePath, MAX_PATH,
+ tempFileName, &tempFilePart)) {
/*
* Invalid file.
*/
@@ -329,7 +367,7 @@ WinReadLink(
* Make sure source file does exist.
*/
- attr = GetFileAttributes(linkSourcePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkSourcePath);
if (attr == INVALID_FILE_ATTRIBUTES) {
/*
* The source doesn't exist.
@@ -345,9 +383,9 @@ WinReadLink(
Tcl_SetErrno(ENOTDIR);
return NULL;
+ } else {
+ return WinReadLinkDirectory(linkSourcePath);
}
-
- return WinReadLinkDirectory(linkSourcePath);
}
/*
@@ -486,8 +524,9 @@ TclWinSymLinkDelete(
memset(reparseBuffer, 0, sizeof(DUMMY_REPARSE_BUFFER));
reparseBuffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
- hFile = CreateFile(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,
@@ -501,7 +540,7 @@ TclWinSymLinkDelete(
} else {
CloseHandle(hFile);
if (!linkOnly) {
- RemoveDirectory(linkOrigPath);
+ (*tclWinProcs->removeDirectoryProc)(linkOrigPath);
}
return 0;
}
@@ -541,7 +580,7 @@ WinReadLinkDirectory(
Tcl_DString ds;
const char *copy;
- attr = GetFileAttributes(linkDirPath);
+ attr = (*tclWinProcs->getFileAttributesProc)(linkDirPath);
if (!(attr & FILE_ATTRIBUTE_REPARSE_POINT)) {
goto invalidError;
}
@@ -566,7 +605,6 @@ WinReadLinkDirectory(
*/
offset = 0;
-#ifdef UNICODE
if (reparseBuffer->MountPointReparseBuffer.PathBuffer[0] == L'\\') {
/*
* Check whether this is a mounted volume.
@@ -628,9 +666,8 @@ WinReadLinkDirectory(
offset = 4;
}
}
-#endif /* UNICODE */
- Tcl_WinTCharToUtf((const TCHAR *)
+ Tcl_WinTCharToUtf((const char *)
reparseBuffer->MountPointReparseBuffer.PathBuffer,
(int) reparseBuffer->MountPointReparseBuffer
.SubstituteNameLength, &ds);
@@ -672,8 +709,9 @@ NativeReadReparse(
HANDLE hFile;
DWORD returnedLength;
- hFile = CreateFile(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) {
/*
@@ -731,7 +769,7 @@ NativeWriteReparse(
* Create the directory - it must not already exist.
*/
- if (CreateDirectory(linkDirPath, NULL) == 0) {
+ if ((*tclWinProcs->createDirectoryProc)(linkDirPath, NULL) == 0) {
/*
* Error creating directory.
*/
@@ -739,9 +777,9 @@ NativeWriteReparse(
TclWinConvertError(GetLastError());
return -1;
}
- hFile = CreateFile(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.
@@ -764,7 +802,7 @@ NativeWriteReparse(
TclWinConvertError(GetLastError());
CloseHandle(hFile);
- RemoveDirectory(linkDirPath);
+ (*tclWinProcs->removeDirectoryProc)(linkDirPath);
return -1;
}
CloseHandle(hFile);
@@ -777,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 * TCL_UTF_MAX];
- WCHAR msgString[TCL_MAX_WARN_LEN];
-
- va_start(argList, format);
- vsnprintf(buf, sizeof(buf), format, argList);
-
- msgString[TCL_MAX_WARN_LEN-1] = L'\0';
- MultiByteToWideChar(CP_UTF8, 0, buf, -1, msgString, TCL_MAX_WARN_LEN);
-
- /*
- * Truncate MessageBox string if it is too long to not overflow the screen
- * and cause possible oversized window error.
- */
-
- if (msgString[TCL_MAX_WARN_LEN-1] != L'\0') {
- memcpy(msgString + (TCL_MAX_WARN_LEN - 5), L" ...", 5 * sizeof(WCHAR));
- }
- if (IsDebuggerPresent()) {
- OutputDebugStringW(msgString);
- } else {
- MessageBeep(MB_ICONEXCLAMATION);
- MessageBoxW(NULL, msgString, L"Fatal Error",
- MB_ICONSTOP | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
- }
-#if defined(__GNUC__)
- __builtin_trap();
-#elif defined(_WIN64)
- __debugbreak();
-#elif defined(_MSC_VER)
- _asm {int 3}
-#else
- DebugBreak();
-#endif
- abort();
-}
-
-/*
*---------------------------------------------------------------------------
*
* TclpFindExecutable --
@@ -854,33 +833,28 @@ 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 * 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) {
- Tcl_SetPanicProc(tclWinDebugPanic);
- }
+ if (GetModuleFileNameW(NULL, wName, MAX_PATH) == 0) {
+ GetModuleFileNameA(NULL, name, sizeof(name));
-#ifdef UNICODE
- GetModuleFileNameW(NULL, wName, MAX_PATH);
-#else
- GetModuleFileNameA(NULL, name, sizeof(name));
+ /*
+ * Convert to WCHAR to get out of ANSI codepage
+ */
- /*
- * Convert to WCHAR to get out of ANSI codepage
- */
+ MultiByteToWideChar(CP_ACP, 0, name, -1, wName, MAX_PATH);
+ }
- MultiByteToWideChar(CP_ACP, 0, name, -1, wName, MAX_PATH);
-#endif
- 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);
}
@@ -926,7 +900,6 @@ TclpMatchInDirectory(
if (pattern == NULL || (*pattern == '\0')) {
Tcl_Obj *norm = Tcl_FSGetNormalizedPath(NULL, pathPtr);
-
if (norm != NULL) {
/*
* Match a single file directly.
@@ -934,16 +907,23 @@ TclpMatchInDirectory(
int len;
DWORD attr;
- WIN32_FILE_ATTRIBUTE_DATA data;
const char *str = Tcl_GetStringFromObj(norm,&len);
- native = Tcl_FSGetNativePath(pathPtr);
+ native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
- if (GetFileAttributesEx(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)) {
Tcl_ListObjAppendElement(interp, resultPtr, pathPtr);
@@ -953,7 +933,7 @@ TclpMatchInDirectory(
} else {
DWORD attr;
HANDLE handle;
- WIN32_FIND_DATA data;
+ WIN32_FIND_DATAT data;
const char *dirName; /* UTF-8 dir name, later with pattern
* appended. */
int dirLength;
@@ -982,10 +962,9 @@ TclpMatchInDirectory(
if (native == NULL) {
return TCL_OK;
}
- attr = GetFileAttributes(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;
}
@@ -1000,7 +979,7 @@ TclpMatchInDirectory(
lastChar = dirName[dirLength -1];
if ((lastChar != '\\') && (lastChar != '/') && (lastChar != ':')) {
- TclDStringAppendLiteral(&dsOrig, "/");
+ Tcl_DStringAppend(&dsOrig, "/", 1);
dirLength++;
}
dirName = Tcl_DStringValue(&dsOrig);
@@ -1020,25 +999,25 @@ TclpMatchInDirectory(
dirName = Tcl_DStringAppend(&dsOrig, pattern, -1);
} else {
- dirName = TclDStringAppendLiteral(&dsOrig, "*.*");
+ dirName = Tcl_DStringAppend(&dsOrig, "*.*", 3);
}
native = Tcl_WinUtfToTChar(dirName, -1, &ds);
- if ((types == NULL) || (types->type != TCL_GLOB_TYPE_DIR)) {
- handle = FindFirstFile(native, &data);
+ 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 = FindFirstFileEx(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) {
/*
@@ -1052,9 +1031,10 @@ TclpMatchInDirectory(
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;
@@ -1094,8 +1074,14 @@ TclpMatchInDirectory(
int checkDrive = 0, isDrive;
DWORD attr;
- native = data.cFileName;
- attr = data.dwFileAttributes;
+ if (tclWinProcs->useWide) {
+ native = (const TCHAR *) data.w.cFileName;
+ attr = data.w.dwFileAttributes;
+ } else {
+ native = (const TCHAR *) data.a.cFileName;
+ attr = data.a.dwFileAttributes;
+ }
+
utfname = Tcl_WinTCharToUtf(native, -1, &ds);
if (!matchSpecialDots) {
@@ -1138,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 {
@@ -1156,7 +1141,7 @@ TclpMatchInDirectory(
*/
Tcl_DStringFree(&ds);
- } while (FindNextFile(handle, &data) == TRUE);
+ } while ((*tclWinProcs->findNextFileProc)(handle, &data) == TRUE);
FindClose(handle);
Tcl_DStringFree(&dsOrig);
@@ -1329,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;
@@ -1429,60 +1415,90 @@ 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. */
{
- const char *result = NULL;
- USER_INFO_1 *uiPtr, **uiPtrPtr = &uiPtr;
- Tcl_DString ds;
- int nameLen = -1;
- int badDomain = 0;
- char *domain;
- WCHAR *wName, *wHomeDir, *wDomain, **wDomainPtr = &wDomain;
- WCHAR buf[MAX_PATH];
+ char *result;
+ HINSTANCE netapiInst;
+ HINSTANCE userenvInst;
+ result = NULL;
Tcl_DStringInit(bufferPtr);
- wDomain = NULL;
- domain = strchr(name, '@');
- if (domain != NULL) {
- Tcl_DStringInit(&ds);
- wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds);
- badDomain = NetGetDCName(NULL, wName, (LPBYTE *) wDomainPtr);
- Tcl_DStringFree(&ds);
- nameLen = domain - name;
- }
- if (badDomain == 0) {
- Tcl_DStringInit(&ds);
- wName = Tcl_UtfToUniCharDString(name, nameLen, &ds);
- if (NetUserGetInfo(wDomain, wName, 1, (LPBYTE *) uiPtrPtr) == 0) {
- wHomeDir = uiPtr->usri1_home_dir;
- if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) {
- Tcl_UniCharToUtfDString(wHomeDir, lstrlenW(wHomeDir),
- bufferPtr);
- } else {
- /*
- * User exists but has no home dir. Return
- * "{GetProfilesDirectory}/<user>".
- */
- DWORD i, size = MAX_PATH;
- GetProfilesDirectoryW(buf, &size);
- for (i = 0; i < size; ++i){
- if (buf[i] == '\\') buf[i] = '/';
+
+ 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];
+
+ 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);
+ }
+ result = Tcl_DStringValue(bufferPtr);
+ (*netApiBufferFreeProc)((void *) uiPtr);
}
- Tcl_UniCharToUtfDString(buf, size-1, bufferPtr);
- Tcl_DStringAppend(bufferPtr, "/", -1);
- Tcl_DStringAppend(bufferPtr, name, -1);
+ Tcl_DStringFree(&ds);
+ }
+ if (wDomain != NULL) {
+ (*netApiBufferFreeProc)((void *) wDomain);
}
- result = Tcl_DStringValue(bufferPtr);
- NetApiBufferFree((void *) uiPtr);
}
- Tcl_DStringFree(&ds);
- }
- if (wDomain != NULL) {
- NetApiBufferFree((void *) wDomain);
+ FreeLibrary(userenvInst);
+ FreeLibrary(netapiInst);
}
if (result == NULL) {
/*
@@ -1538,9 +1554,9 @@ NativeAccess(
{
DWORD attr;
- attr = GetFileAttributes(nativePath);
+ attr = (*tclWinProcs->getFileAttributesProc)(nativePath);
- if (attr == INVALID_FILE_ATTRIBUTES) {
+ if (attr == 0xffffffff) {
/*
* File might not exist.
*/
@@ -1596,8 +1612,7 @@ NativeAccess(
* what permissions the OS has set for a file.
*/
-#ifdef UNICODE
- {
+ if (tclWinProcs->getFileSecurityProc != NULL) {
SECURITY_DESCRIPTOR *sdPtr = NULL;
unsigned long size;
PSID pSid = 0;
@@ -1612,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;
- GetFileSecurity(nativePath,
+ (*tclWinProcs->getFileSecurityProc)(nativePath,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
0, 0, &size);
@@ -1650,7 +1665,7 @@ NativeAccess(
* Call GetFileSecurity() for real.
*/
- if (!GetFileSecurity(nativePath,
+ if (!(*tclWinProcs->getFileSecurityProc)(nativePath,
OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
sdPtr, size, &size)) {
@@ -1686,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.
@@ -1702,7 +1717,7 @@ NativeAccess(
goto accessError;
}
- RevertToSelf();
+ (*tclWinProcs->revertToSelfProc)();
/*
* Setup desiredAccess according to the access priveleges we are
@@ -1729,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)) {
/*
@@ -1759,7 +1774,6 @@ NativeAccess(
}
}
-#endif /* !UNICODE */
return 0;
}
@@ -1779,22 +1793,55 @@ NativeAccess(
static int
NativeIsExec(
- const TCHAR *path)
+ const TCHAR *nativePath)
{
- int len = _tcslen(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.
+ */
+
+ if ((strcasecmp(p, "exe") == 0)
+ || (strcasecmp(p, "com") == 0)
+ || (strcasecmp(p, "bat") == 0)) {
+ /*
+ * File that ends with .exe, .com, or .bat is executable.
+ */
- if ((_tcsicmp(path+len-3, TEXT("exe")) == 0)
- || (_tcsicmp(path+len-3, TEXT("com")) == 0)
- || (_tcsicmp(path+len-3, TEXT("bat")) == 0)) {
- return 1;
+ return 1;
+ }
+ }
}
return 0;
}
@@ -1822,12 +1869,12 @@ TclpObjChdir(
int result;
const TCHAR *nativePath;
- nativePath = Tcl_FSGetNativePath(pathPtr);
+ nativePath = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
if (!nativePath) {
return -1;
}
- result = SetCurrentDirectory(nativePath);
+ result = (*tclWinProcs->setCurrentDirectoryProc)(nativePath);
if (result == 0) {
TclWinConvertError(GetLastError());
@@ -1864,16 +1911,14 @@ TclpGetCwd(
Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
* name of current directory. */
{
- TCHAR buffer[MAX_PATH];
+ WCHAR buffer[MAX_PATH];
char *p;
- WCHAR *native;
- if (GetCurrentDirectory(MAX_PATH, buffer) == 0) {
+ 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;
}
@@ -1882,12 +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_WinTCharToUtf((TCHAR *) native, -1, bufferPtr);
/*
* Convert to forward slashes for easier use in scripts.
@@ -1914,7 +1972,8 @@ TclpObjStat(
TclWinFlushDirtyChannels();
- return NativeStat(Tcl_FSGetNativePath(pathPtr), statPtr, 0);
+ return NativeStat((const TCHAR *) Tcl_FSGetNativePath(pathPtr),
+ statPtr, 0);
}
/*
@@ -1960,7 +2019,7 @@ NativeStat(
* simpler routines.
*/
- fileHandle = CreateFile(nativePath, GENERIC_READ,
+ 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);
@@ -1999,24 +2058,24 @@ 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 (GetFileAttributesEx(nativePath,
+ if ((*tclWinProcs->getFileAttributesExProc)(nativePath,
GetFileExInfoStandard, &data) != TRUE) {
HANDLE hFind;
- WIN32_FIND_DATA ffd;
+ WIN32_FIND_DATAT ffd;
DWORD lasterror = GetLastError();
if (lasterror != ERROR_SHARING_VIOLATION) {
TclWinConvertError(lasterror);
return -1;
}
- hFind = FindFirstFile(nativePath, &ffd);
+ hFind = (*tclWinProcs->findFirstFileProc)(nativePath, &ffd);
if (hFind == INVALID_HANDLE_VALUE) {
TclWinConvertError(GetLastError());
return -1;
@@ -2032,6 +2091,46 @@ NativeStat(
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);
@@ -2063,12 +2162,14 @@ NativeDev(
{
int dev;
Tcl_DString ds;
- TCHAR nativeFullPath[MAX_PATH];
+ WCHAR nativeFullPath[MAX_PATH];
TCHAR *nativePart;
const char *fullPath;
- GetFullPathName(nativePath, MAX_PATH, nativeFullPath, &nativePart);
- fullPath = Tcl_WinTCharToUtf(nativeFullPath, -1, &ds);
+ (*tclWinProcs->getFullPathNameProc)(nativePath, MAX_PATH,
+ nativeFullPath, &nativePart);
+
+ fullPath = Tcl_WinTCharToUtf((TCHAR *) nativeFullPath, -1, &ds);
if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) {
const char *p;
@@ -2084,14 +2185,15 @@ NativeDev(
* won't work.
*/
- fullPath = TclDStringAppendLiteral(&ds, "\\");
+ fullPath = Tcl_DStringAppend(&ds, "\\", 1);
p = fullPath + Tcl_DStringLength(&ds);
} else {
p++;
}
nativeVol = Tcl_WinUtfToTChar(fullPath, p - fullPath, &volString);
dw = (DWORD) -1;
- GetVolumeInformation(nativeVol, NULL, 0, &dw, NULL, NULL, NULL, 0);
+ (*tclWinProcs->getVolumeInformationProc)(nativeVol, NULL, 0, &dw,
+ NULL, NULL, NULL, 0);
/*
* GetFullPathName() turns special devices like "NUL" into "\\.\NUL",
@@ -2203,9 +2305,8 @@ FromCTime(
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;
}
@@ -2235,20 +2336,34 @@ ClientData
TclpGetNativeCwd(
ClientData clientData)
{
- TCHAR buffer[MAX_PATH];
+ WCHAR buffer[MAX_PATH];
- if (GetCurrentDirectory(MAX_PATH, buffer) == 0) {
+ if ((*tclWinProcs->getCurrentDirectoryProc)(MAX_PATH, buffer) == 0) {
TclWinConvertError(GetLastError());
return NULL;
}
if (clientData != NULL) {
- if (_tcscmp((const TCHAR*)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
@@ -2256,7 +2371,7 @@ TclpObjAccess(
Tcl_Obj *pathPtr,
int mode)
{
- return NativeAccess(Tcl_FSGetNativePath(pathPtr), mode);
+ return NativeAccess((const TCHAR *) Tcl_FSGetNativePath(pathPtr), mode);
}
int
@@ -2272,7 +2387,8 @@ TclpObjLstat(
TclWinFlushDirtyChannels();
- return NativeStat(Tcl_FSGetNativePath(pathPtr), statPtr, 1);
+ return NativeStat((const TCHAR *) Tcl_FSGetNativePath(pathPtr),
+ statPtr, 1);
}
#ifdef S_IFLNK
@@ -2284,15 +2400,15 @@ TclpObjLink(
{
if (toPtr != NULL) {
int res;
- const TCHAR *LinkTarget;
- const TCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr);
+ TCHAR *LinkTarget;
+ TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
Tcl_Obj *normalizedToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr);
if (normalizedToPtr == NULL) {
return NULL;
}
- LinkTarget = Tcl_FSGetNativePath(normalizedToPtr);
+ LinkTarget = (TCHAR *) Tcl_FSGetNativePath(normalizedToPtr);
if (LinkSource == NULL || LinkTarget == NULL) {
return NULL;
@@ -2304,7 +2420,7 @@ TclpObjLink(
return NULL;
}
} else {
- const TCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr);
+ TCHAR *LinkSource = (TCHAR *) Tcl_FSGetNativePath(pathPtr);
if (LinkSource == NULL) {
return NULL;
@@ -2312,7 +2428,7 @@ TclpObjLink(
return WinReadLink(LinkSource);
}
}
-#endif /* S_IFLNK */
+#endif
/*
*---------------------------------------------------------------------------
@@ -2338,7 +2454,7 @@ TclpFilesystemPathType(
{
#define VOL_BUF_SIZE 32
int found;
- TCHAR volType[VOL_BUF_SIZE];
+ WCHAR volType[VOL_BUF_SIZE];
char *firstSeparator;
const char *path;
Tcl_Obj *normPath = Tcl_FSGetNormalizedPath(NULL, pathPtr);
@@ -2353,14 +2469,16 @@ TclpFilesystemPathType(
firstSeparator = strchr(path, '/');
if (firstSeparator == NULL) {
- found = GetVolumeInformation(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 = GetVolumeInformation(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);
}
@@ -2368,9 +2486,13 @@ TclpFilesystemPathType(
return NULL;
} else {
Tcl_DString ds;
+ Tcl_Obj *objPtr;
- Tcl_WinTCharToUtf(volType, -1, &ds);
- return TclDStringToObj(&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
}
@@ -2420,219 +2542,377 @@ TclpObjNormalizePath(
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 = 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;
+
+ currentPathEndPosition = path + nextCheckpoint;
+ if (*currentPathEndPosition == '/') {
+ currentPathEndPosition++;
+ }
+
+ while (1) {
+ char cur = *currentPathEndPosition;
+
+ if ((cur=='/' || cur==0) && (path != currentPathEndPosition)) {
+ /*
+ * Reached directory separator, or end of string.
+ */
- WIN32_FILE_ATTRIBUTE_DATA data;
- const TCHAR *nativePath = Tcl_WinUtfToTChar(path,
- currentPathEndPosition - path, &ds);
+ const char *nativePath = Tcl_UtfToExternalDString(NULL, path,
+ currentPathEndPosition - path, &ds);
- if (GetFileAttributesEx(nativePath,
- GetFileExInfoStandard, &data) != TRUE) {
/*
- * File doesn't exist.
+ * 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) {
- int len = WinIsReserved(path);
+ if (GetFileAttributesA(nativePath)
+ == INVALID_FILE_ATTRIBUTES) {
+ /*
+ * File doesn't exist.
+ */
- if (len > 0) {
+ 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++;
+ }
+ }
+ 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 {
/*
- * Actually it does exist - COM1, etc.
+ * Normal path.
*/
- int i;
+ WIN32_FIND_DATA fData;
+ HANDLE handle;
- for (i=0 ; i<len ; i++) {
- WCHAR wc = ((WCHAR *) nativePath)[i];
+ handle = FindFirstFileA(nativePath, &fData);
+ if (handle == INVALID_HANDLE_VALUE) {
+ if (GetFileAttributesA(nativePath)
+ == INVALID_FILE_ATTRIBUTES) {
+ /*
+ * File doesn't exist.
+ */
- if (wc >= L'a') {
- wc -= (L'a' - L'A');
- ((WCHAR *) nativePath)[i] = wc;
+ 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_DStringAppend(&dsNorm,
- (const char *)nativePath,
- (int)(sizeof(WCHAR) * len));
- lastValidPathEnd = currentPathEndPosition;
- } else if (nextCheckpoint == 0) {
- /* Path starts with a drive designation
- * that's not actually on the system.
- * We still must normalize up past the
- * first separator. [Bug 3603434] */
- currentPathEndPosition++;
}
}
Tcl_DStringFree(&ds);
- 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=='/' || cur==0) && (path != currentPathEndPosition)) {
+ /*
+ * Reached directory separator, or end of string.
+ */
- if (cur != 0 && !isDrive &&
- data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT){
- Tcl_Obj *to = WinReadLinkDirectory(nativePath);
+ WIN32_FILE_ATTRIBUTE_DATA data;
+ const char *nativePath = Tcl_WinUtfToTChar(path,
+ currentPathEndPosition - path, &ds);
- if (to != NULL) {
+ 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, -1);
+ if (isDrive) {
+ int len = WinIsReserved(path);
- /*
- * Convert link to forward slashes.
- */
+ if (len > 0) {
+ /*
+ * Actually it does exist - COM1, etc.
+ */
- for (path = Tcl_GetString(to); *path != 0; path++) {
- if (*path == '\\') {
- *path = '/';
- }
- }
- path = Tcl_GetString(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 >= L'a') {
- drive -= (L'a' - L'A');
- ((WCHAR *) nativePath)[0] = drive;
- }
- Tcl_DStringAppend(&dsNorm, (const char *)nativePath,
- Tcl_DStringLength(&ds));
- } else {
- char *checkDots = NULL;
-
- if (lastValidPathEnd[1] == '.') {
- checkDots = lastValidPathEnd + 1;
- while (checkDots < currentPathEndPosition) {
- if (*checkDots != '.') {
- checkDots = NULL;
- break;
+ 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 = '/';
+ }
+ }
+ path = Tcl_GetString(to);
+ currentPathEndPosition = path + nextCheckpoint;
+ if (temp != NULL) {
+ Tcl_DecrRefCount(temp);
}
- checkDots++;
+ 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(TCHAR)),
- (int)(dotLen * sizeof(TCHAR)));
+ 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.
+ */
+
+ WIN32_FIND_DATAW fData;
+ HANDLE handle;
- if (fData.cFileName[0] != '\0') {
- nativeName = fData.cFileName;
+ 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,
- (int) (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
/*
@@ -2641,10 +2921,10 @@ TclpObjNormalizePath(
if (1) {
WCHAR wpath[MAX_PATH];
- const TCHAR *nativePath =
+ const char *nativePath =
Tcl_WinUtfToTChar(path, lastValidPathEnd - path, &ds);
- DWORD wpathlen = GetLongPathNameProc(nativePath,
- (TCHAR *) wpath, MAX_PATH);
+ DWORD wpathlen = (*tclWinProcs->getLongPathNameProc)(
+ nativePath, (TCHAR *) wpath, MAX_PATH);
/*
* We have to make the drive letter uppercase.
@@ -2653,11 +2933,10 @@ TclpObjNormalizePath(
if (wpath[0] >= L'a') {
wpath[0] -= (L'a' - L'A');
}
- Tcl_DStringAppend(&dsNorm, (const char *) wpath,
- wpathlen * sizeof(WCHAR));
+ Tcl_DStringAppend(&dsNorm, (TCHAR*)wpath, wpathlen*sizeof(WCHAR));
Tcl_DStringFree(&ds);
}
-#endif /* TclNORM_LONG_PATH */
+#endif
}
/*
@@ -2672,9 +2951,11 @@ TclpObjNormalizePath(
* native encoding, so we have to convert it to Utf.
*/
- Tcl_WinTCharToUtf((const TCHAR *) Tcl_DStringValue(&dsNorm),
- Tcl_DStringLength(&dsNorm), &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.
@@ -2684,7 +2965,7 @@ TclpObjNormalizePath(
char *path;
Tcl_Obj *tmpPathPtr;
- tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds),
+ tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&dsTemp),
nextCheckpoint);
Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1);
path = Tcl_GetStringFromObj(tmpPathPtr, &len);
@@ -2695,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);
@@ -2709,7 +2991,6 @@ TclpObjNormalizePath(
if (temp != NULL) {
Tcl_DecrRefCount(temp);
}
-
return nextCheckpoint;
}
@@ -2849,7 +3130,7 @@ TclpNativeToNormalized(
int len;
char *copy, *p;
- Tcl_WinTCharToUtf((const TCHAR *) clientData, -1, &ds);
+ Tcl_WinTCharToUtf((const char *) clientData, -1, &ds);
copy = Tcl_DStringValue(&ds);
len = Tcl_DStringLength(&ds);
@@ -2905,11 +3186,10 @@ ClientData
TclNativeCreateNativeRep(
Tcl_Obj *pathPtr)
{
- WCHAR *nativePathPtr = NULL;
- const char *str;
+ char *nativePathPtr, *str;
+ Tcl_DString ds;
Tcl_Obj *validPathPtr;
- size_t len;
- WCHAR *wp;
+ int len;
if (TclFSCwdIsNative()) {
/*
@@ -2922,7 +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.
@@ -2932,86 +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 = Tcl_GetString(validPathPtr);
- len = validPathPtr->length;
-
- if (strlen(str)!=(unsigned int)len) {
- /* String contains NUL-bytes. This is invalid. */
- goto done;
- }
- /* For a reserved device, strip a possible postfix ':' */
- len = WinIsReserved(str);
- if (len == 0) {
- /* Let MultiByteToWideChar check for other invalid sequences, like
- * 0xC0 0x80 (== overlong NUL). See bug [3118489]: NUL in filenames */
- len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, 0, 0);
- if (len==0) {
- goto done;
- }
- }
- /* Overallocate 6 chars, making some room for extended paths */
- wp = nativePathPtr = ckalloc( (len+6) * sizeof(WCHAR) );
- if (nativePathPtr==0) {
- goto done;
- }
- MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, str, -1, nativePathPtr, len+1);
- /*
- ** If path starts with "//?/" or "\\?\" (extended path), translate
- ** any slashes to backslashes but leave the '?' intact
- */
- if ((str[0]=='\\' || str[0]=='/') && (str[1]=='\\' || str[1]=='/')
- && str[2]=='?' && (str[3]=='\\' || str[3]=='/')) {
- wp[0] = wp[1] = wp[3] = '\\';
- str += 4;
- wp += 4;
- }
- /*
- ** If there is no "\\?\" prefix but there is a drive or UNC
- ** path prefix and the path is larger than MAX_PATH chars,
- ** no Win32 API function can handle that unless it is
- ** prefixed with the extended path prefix. See:
- ** <http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx#maxpath>
- **/
- if (((str[0]>='A'&&str[0]<='Z') || (str[0]>='a'&&str[0]<='z'))
- && str[1]==':') {
- if (wp==nativePathPtr && len>MAX_PATH && (str[2]=='\\' || str[2]=='/')) {
- memmove(wp+4, wp, len*sizeof(WCHAR));
- memcpy(wp, L"\\\\?\\", 4*sizeof(WCHAR));
+ 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;
+ /*
+ ** 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;
}
/*
- ** 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 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;
}
- ++wp;
+ 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 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;
+ }
+ 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;
}
/*
@@ -3042,11 +3322,23 @@ TclNativeDupInternalRep(
return NULL;
}
- len = sizeof(TCHAR) * (_tcslen((const TCHAR *) 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.
+ */
+
+ len = sizeof(char) * (strlen((const char *) clientData) + 1);
+ }
- copy = ckalloc(len);
+ copy = (char *) ckalloc(len);
memcpy(copy, clientData, len);
- return copy;
+ return (ClientData) copy;
}
/*
@@ -3081,9 +3373,9 @@ TclpUtime(
FromCTime(tval->actime, &lastAccessTime);
FromCTime(tval->modtime, &lastModTime);
- native = Tcl_FSGetNativePath(pathPtr);
+ native = (const TCHAR *) Tcl_FSGetNativePath(pathPtr);
- attr = GetFileAttributes(native);
+ attr = (*tclWinProcs->getFileAttributesProc)(native);
if (attr != INVALID_FILE_ATTRIBUTES && attr & FILE_ATTRIBUTE_DIRECTORY) {
flags = FILE_FLAG_BACKUP_SEMANTICS;
@@ -3094,8 +3386,8 @@ TclpUtime(
* savings complications that utime gets wrong.
*/
- fileHandle = CreateFile(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)) {