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