diff options
Diffstat (limited to 'win/tclWinFile.c')
| -rwxr-xr-x[-rw-r--r--] | win/tclWinFile.c | 467 |
1 files changed, 280 insertions, 187 deletions
diff --git a/win/tclWinFile.c b/win/tclWinFile.c index 6582ee1..fa5f28e 100644..100755 --- a/win/tclWinFile.c +++ b/win/tclWinFile.c @@ -156,27 +156,27 @@ static void FromCTime(time_t posixTime, FILETIME *fileTime); * 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 WCHAR *path, int mode); +static int NativeDev(const WCHAR *path); +static int NativeStat(const WCHAR *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, +static int NativeIsExec(const WCHAR *path); +static int NativeReadReparse(const WCHAR *LinkDirectory, REPARSE_DATA_BUFFER *buffer, DWORD desiredAccess); -static int NativeWriteReparse(const TCHAR *LinkDirectory, +static int NativeWriteReparse(const WCHAR *LinkDirectory, REPARSE_DATA_BUFFER *buffer); static int NativeMatchType(int isDrive, DWORD attr, - const TCHAR *nativeName, Tcl_GlobTypeData *types); + const WCHAR *nativeName, Tcl_GlobTypeData *types); static int WinIsDrive(const char *name, size_t nameLen); static int WinIsReserved(const char *path); -static Tcl_Obj * WinReadLink(const TCHAR *LinkSource); -static Tcl_Obj * WinReadLinkDirectory(const TCHAR *LinkDirectory); -static int WinLink(const TCHAR *LinkSource, - const TCHAR *LinkTarget, int linkAction); -static int WinSymLinkDirectory(const TCHAR *LinkDirectory, - const TCHAR *LinkTarget); +static Tcl_Obj * WinReadLink(const WCHAR *LinkSource); +static Tcl_Obj * WinReadLinkDirectory(const WCHAR *LinkDirectory); +static int WinLink(const WCHAR *LinkSource, + const WCHAR *LinkTarget, int linkAction); +static int WinSymLinkDirectory(const WCHAR *LinkDirectory, + const WCHAR *LinkTarget); MODULE_SCOPE TCL_NORETURN void tclWinDebugPanic(const char *format, ...); /* @@ -191,12 +191,12 @@ MODULE_SCOPE TCL_NORETURN void tclWinDebugPanic(const char *format, ...); static int WinLink( - const TCHAR *linkSourcePath, - const TCHAR *linkTargetPath, + const WCHAR *linkSourcePath, + const WCHAR *linkTargetPath, int linkAction) { - TCHAR tempFileName[MAX_PATH]; - TCHAR *tempFilePart; + WCHAR tempFileName[MAX_PATH]; + WCHAR *tempFilePart; DWORD attr; /* @@ -306,10 +306,10 @@ WinLink( static Tcl_Obj * WinReadLink( - const TCHAR *linkSourcePath) + const WCHAR *linkSourcePath) { - TCHAR tempFileName[MAX_PATH]; - TCHAR *tempFilePart; + WCHAR tempFileName[MAX_PATH]; + WCHAR *tempFilePart; DWORD attr; /* @@ -370,8 +370,8 @@ WinReadLink( static int WinSymLinkDirectory( - const TCHAR *linkDirPath, - const TCHAR *linkTargetPath) + const WCHAR *linkDirPath, + const WCHAR *linkTargetPath) { DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy; @@ -442,8 +442,8 @@ WinSymLinkDirectory( int TclWinSymLinkCopyDirectory( - const TCHAR *linkOrigPath, /* Existing junction - reparse point */ - const TCHAR *linkCopyPath) /* Will become a duplicate junction */ + const WCHAR *linkOrigPath, /* Existing junction - reparse point */ + const WCHAR *linkCopyPath) /* Will become a duplicate junction */ { DUMMY_REPARSE_BUFFER dummy; REPARSE_DATA_BUFFER *reparseBuffer = (REPARSE_DATA_BUFFER *) &dummy; @@ -473,7 +473,7 @@ TclWinSymLinkCopyDirectory( int TclWinSymLinkDelete( - const TCHAR *linkOrigPath, + const WCHAR *linkOrigPath, int linkOnly) { /* @@ -538,7 +538,7 @@ TclWinSymLinkDelete( static Tcl_Obj * WinReadLinkDirectory( - const TCHAR *linkDirPath) + const WCHAR *linkDirPath) { int attr, len, offset; DUMMY_REPARSE_BUFFER dummy; @@ -634,9 +634,9 @@ WinReadLinkDirectory( } } - Tcl_WinTCharToUtf((const TCHAR *) + Tcl_WinTCharToUtf( reparseBuffer->MountPointReparseBuffer.PathBuffer, - (int) reparseBuffer->MountPointReparseBuffer + reparseBuffer->MountPointReparseBuffer .SubstituteNameLength, &ds); copy = Tcl_DStringValue(&ds)+offset; @@ -673,14 +673,15 @@ WinReadLinkDirectory( static int NativeReadReparse( - const TCHAR *linkDirPath, /* The junction to read */ + const WCHAR *linkDirPath, /* The junction to read */ REPARSE_DATA_BUFFER *buffer,/* Pointer to buffer. Cannot be NULL */ DWORD desiredAccess) { HANDLE hFile; DWORD returnedLength; - hFile = CreateFile(linkDirPath, desiredAccess, FILE_SHARE_READ, NULL, OPEN_EXISTING, + hFile = CreateFile(linkDirPath, desiredAccess, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL); if (hFile == INVALID_HANDLE_VALUE) { @@ -729,7 +730,7 @@ NativeReadReparse( static int NativeWriteReparse( - const TCHAR *linkDirPath, + const WCHAR *linkDirPath, REPARSE_DATA_BUFFER *buffer) { HANDLE hFile; @@ -842,7 +843,7 @@ tclWinDebugPanic( #endif abort(); } - + /* *--------------------------------------------------------------------------- * @@ -913,7 +914,7 @@ TclpMatchInDirectory( * May be NULL. In particular the directory * flag is very important. */ { - const TCHAR *native; + const WCHAR *native; if (types != NULL && types->type == TCL_GLOB_TYPE_MOUNT) { /* @@ -931,9 +932,10 @@ TclpMatchInDirectory( * Match a single file directly. */ + int len; DWORD attr; WIN32_FILE_ATTRIBUTE_DATA data; - const char *str = TclGetString(norm); + const char *str = TclGetStringFromObj(norm, &len); native = Tcl_FSGetNativePath(pathPtr); @@ -943,7 +945,7 @@ TclpMatchInDirectory( } attr = data.dwFileAttributes; - if (NativeMatchType(WinIsDrive(str,norm->length), attr, native, types)) { + if (NativeMatchType(WinIsDrive(str,len), attr, native, types)) { Tcl_ListObjAppendElement(interp, resultPtr, pathPtr); } } @@ -954,7 +956,7 @@ TclpMatchInDirectory( WIN32_FIND_DATA data; const char *dirName; /* UTF-8 dir name, later with pattern * appended. */ - size_t dirLength; + int dirLength; int matchSpecialDots; Tcl_DString ds; /* Native encoding of dir, also used * temporarily for other things. */ @@ -993,8 +995,7 @@ TclpMatchInDirectory( */ Tcl_DStringInit(&dsOrig); - dirName = TclGetString(fileNamePtr); - dirLength = fileNamePtr->length; + dirName = TclGetStringFromObj(fileNamePtr, &dirLength); Tcl_DStringAppend(&dsOrig, dirName, dirLength); lastChar = dirName[dirLength -1]; @@ -1313,7 +1314,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 WCHAR *nativeName, /* Native path to check. */ Tcl_GlobTypeData *types) /* Type description to match against. */ { /* @@ -1450,11 +1451,16 @@ TclpGetUserHome( if (domain == NULL) { const char *ptr; - /* no domain - firstly check it's the current user */ - if ( (ptr = TclpGetUserName(&ds)) != NULL - && strcasecmp(name, ptr) == 0 - ) { - /* try safest and fastest way to get current user home */ + /* + * No domain. Firstly check it's the current user + */ + + ptr = TclpGetUserName(&ds); + if (ptr != NULL && strcasecmp(name, ptr) == 0) { + /* + * Try safest and fastest way to get current user home + */ + ptr = TclGetEnv("HOME", &ds); if (ptr != NULL) { Tcl_JoinPath(1, &ptr, bufferPtr); @@ -1465,46 +1471,63 @@ TclpGetUserHome( Tcl_DStringFree(&ds); } else { Tcl_DStringInit(&ds); - wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds); + wName = TclUtfToWCharDString(domain + 1, -1, &ds); rc = NetGetDCName(NULL, wName, (LPBYTE *) &wDomain); Tcl_DStringFree(&ds); nameLen = domain - name; } if (rc == 0) { Tcl_DStringInit(&ds); - wName = Tcl_UtfToUniCharDString(name, nameLen, &ds); + wName = TclUtfToWCharDString(name, nameLen, &ds); while (NetUserGetInfo(wDomain, wName, 1, (LPBYTE *) &uiPtr) != 0) { /* - * user does not exists - if domain was not specified, - * try again using current domain. + * User does not exist; if domain was not specified, try again + * using current domain. */ + rc = 1; - if (domain != NULL) break; - /* get current domain */ + if (domain != NULL) { + break; + } + + /* + * Get current domain + */ + rc = NetGetDCName(NULL, NULL, (LPBYTE *) &wDomain); - if (rc != 0) break; + if (rc != 0) { + break; + } domain = INT2PTR(-1); /* repeat once */ } if (rc == 0) { DWORD i, size = MAX_PATH; + wHomeDir = uiPtr->usri1_home_dir; if ((wHomeDir != NULL) && (wHomeDir[0] != L'\0')) { size = lstrlenW(wHomeDir); - Tcl_UniCharToUtfDString(wHomeDir, size, bufferPtr); + TclWCharToUtfDString(wHomeDir, size, bufferPtr); } else { /* * User exists but has no home dir. Return * "{GetProfilesDirectory}/<user>". */ + GetProfilesDirectoryW(buf, &size); - Tcl_UniCharToUtfDString(buf, size-1, bufferPtr); + TclWCharToUtfDString(buf, size-1, bufferPtr); Tcl_DStringAppend(bufferPtr, "/", 1); Tcl_DStringAppend(bufferPtr, name, nameLen); } result = Tcl_DStringValue(bufferPtr); - /* be sure we returns normalized path */ - for (i = 0; i < size; ++i){ - if (result[i] == '\\') result[i] = '/'; + + /* + * Be sure we return normalized path + */ + + for (i = 0; i < size; ++i) { + if (result[i] == '\\') { + result[i] = '/'; + } } NetApiBufferFree((void *) uiPtr); } @@ -1562,7 +1585,7 @@ TclpGetUserHome( static int NativeAccess( - const TCHAR *nativePath, /* Path of file to access, native encoding. */ + const WCHAR *nativePath, /* Path of file to access, native encoding. */ int mode) /* Permission setting. */ { DWORD attr; @@ -1592,48 +1615,72 @@ NativeAccess( /* * If it's not a directory (assume file), do several fast checks: */ + if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) { /* * If the attributes say this is not writable at all. The file is a * regular file (i.e., not a directory), then the file is not - * writable, full stop. For directories, the read-only bit is + * writable, full stop. For directories, the read-only bit is * (mostly) ignored by Windows, so we can't ascertain anything about * directory access from the attrib data. However, if we have the - * advanced 'getFileSecurityProc', then more robust ACL checks - * will be done below. + * advanced 'getFileSecurityProc', then more robust ACL checks will be + * done below. */ + if ((mode & W_OK) && (attr & FILE_ATTRIBUTE_READONLY)) { Tcl_SetErrno(EACCES); return -1; } - /* If doesn't have the correct extension, it can't be executable */ + /* + * If doesn't have the correct extension, it can't be executable + */ + if ((mode & X_OK) && !NativeIsExec(nativePath)) { Tcl_SetErrno(EACCES); return -1; } - /* Special case for read/write/executable check on file */ + + /* + * Special case for read/write/executable check on file + */ + if ((mode & (R_OK|W_OK|X_OK)) && !(mode & ~(R_OK|W_OK|X_OK))) { DWORD mask = 0; HANDLE hFile; - if (mode & R_OK) { mask |= GENERIC_READ; } - if (mode & W_OK) { mask |= GENERIC_WRITE; } - if (mode & X_OK) { mask |= GENERIC_EXECUTE; } + + if (mode & R_OK) { + mask |= GENERIC_READ; + } + if (mode & W_OK) { + mask |= GENERIC_WRITE; + } + if (mode & X_OK) { + mask |= GENERIC_EXECUTE; + } hFile = CreateFile(nativePath, mask, - FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, - OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING, NULL); if (hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); return 0; } - /* fast exit if access was denied */ + + /* + * Fast exit if access was denied + */ + if (GetLastError() == ERROR_ACCESS_DENIED) { Tcl_SetErrno(EACCES); return -1; } } - /* We cannnot verify the access fast, check it below using security info. */ + + /* + * We cannnot verify the access fast, check it below using security + * info. + */ } /* @@ -1824,9 +1871,9 @@ NativeAccess( static int NativeIsExec( - const TCHAR *path) + const WCHAR *path) { - int len = _tcslen(path); + int len = wcslen(path); if (len < 5) { return 0; @@ -1837,11 +1884,11 @@ NativeIsExec( } path += len-3; - if ((_tcsicmp(path, TEXT("exe")) == 0) - || (_tcsicmp(path, TEXT("com")) == 0) - || (_tcsicmp(path, TEXT("cmd")) == 0) - || (_tcsicmp(path, TEXT("cmd")) == 0) - || (_tcsicmp(path, TEXT("bat")) == 0)) { + if ((wcsicmp(path, L"exe") == 0) + || (wcsicmp(path, L"com") == 0) + || (wcsicmp(path, L"cmd") == 0) + || (wcsicmp(path, L"cmd") == 0) + || (wcsicmp(path, L"bat") == 0)) { return 1; } return 0; @@ -1868,7 +1915,7 @@ TclpObjChdir( Tcl_Obj *pathPtr) /* Path to new working directory. */ { int result; - const TCHAR *nativePath; + const WCHAR *nativePath; nativePath = Tcl_FSGetNativePath(pathPtr); @@ -1912,7 +1959,7 @@ 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; @@ -1935,7 +1982,7 @@ TclpGetCwd( && (native[2] == '\\') && (native[3] == '\\')) { native += 2; } - Tcl_WinTCharToUtf((TCHAR *) native, -1, bufferPtr); + Tcl_WinTCharToUtf(native, -1, bufferPtr); /* * Convert to forward slashes for easier use in scripts. @@ -1990,7 +2037,7 @@ TclpObjStat( static int NativeStat( - const TCHAR *nativePath, /* Path of file to stat */ + const WCHAR *nativePath, /* Path of file to stat */ Tcl_StatBuf *statPtr, /* Filled with results of stat call. */ int checkLinks) /* If non-zero, behave like 'lstat' */ { @@ -2008,13 +2055,12 @@ NativeStat( * 'getFileAttributesExProc', and if that isn't available, then on even * simpler routines. * - * Special consideration must be given to Windows hardcoded names - * like CON, NULL, COM1, LPT1 etc. For these, we still need to - * do the CreateFile as some may not exist (e.g. there is no CON - * in wish by default). However the subsequent GetFileInformationByHandle - * will fail. We do a WinIsReserved to see if it is one of the special - * names, and if successful, mock up a BY_HANDLE_FILE_INFORMATION - * structure. + * Special consideration must be given to Windows hardcoded names like + * CON, NULL, COM1, LPT1 etc. For these, we still need to do the + * CreateFile as some may not exist (e.g. there is no CON in wish by + * default). However the subsequent GetFileInformationByHandle will + * fail. We do a WinIsReserved to see if it is one of the special names, + * and if successful, mock up a BY_HANDLE_FILE_INFORMATION structure. */ fileHandle = CreateFile(nativePath, GENERIC_READ, @@ -2032,7 +2078,11 @@ NativeStat( Tcl_SetErrno(ENOENT); return -1; } - /* Mock up the expected structure */ + + /* + * Mock up the expected structure + */ + memset(&data, 0, sizeof(data)); statPtr->st_atime = 0; statPtr->st_mtime = 0; @@ -2131,12 +2181,12 @@ NativeStat( static int NativeDev( - const TCHAR *nativePath) /* Full path of file to stat */ + const WCHAR *nativePath) /* Full path of file to stat */ { int dev; Tcl_DString ds; - TCHAR nativeFullPath[MAX_PATH]; - TCHAR *nativePart; + WCHAR nativeFullPath[MAX_PATH]; + WCHAR *nativePart; const char *fullPath; GetFullPathName(nativePath, MAX_PATH, nativeFullPath, &nativePart); @@ -2145,7 +2195,7 @@ NativeDev( if ((fullPath[0] == '\\') && (fullPath[1] == '\\')) { const char *p; DWORD dw; - const TCHAR *nativeVol; + const WCHAR *nativeVol; Tcl_DString volString; p = strchr(fullPath + 2, '\\'); @@ -2307,7 +2357,7 @@ ClientData TclpGetNativeCwd( ClientData clientData) { - TCHAR buffer[MAX_PATH]; + WCHAR buffer[MAX_PATH]; if (GetCurrentDirectory(MAX_PATH, buffer) == 0) { TclWinConvertError(GetLastError()); @@ -2315,7 +2365,7 @@ TclpGetNativeCwd( } if (clientData != NULL) { - if (_tcscmp((const TCHAR*)clientData, buffer) == 0) { + if (wcscmp((const WCHAR *) clientData, buffer) == 0) { return clientData; } } @@ -2356,8 +2406,8 @@ TclpObjLink( { if (toPtr != NULL) { int res; - const TCHAR *LinkTarget; - const TCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr); + const WCHAR *LinkTarget; + const WCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr); Tcl_Obj *normalizedToPtr = Tcl_FSGetNormalizedPath(NULL, toPtr); if (normalizedToPtr == NULL) { @@ -2376,7 +2426,7 @@ TclpObjLink( return NULL; } } else { - const TCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr); + const WCHAR *LinkSource = Tcl_FSGetNativePath(pathPtr); if (LinkSource == NULL) { return NULL; @@ -2410,7 +2460,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); @@ -2511,7 +2561,7 @@ TclpObjNormalizePath( */ WIN32_FILE_ATTRIBUTE_DATA data; - const TCHAR *nativePath = Tcl_WinUtfToTChar(path, + const WCHAR *nativePath = Tcl_WinUtfToTChar(path, currentPathEndPosition - path, &ds); if (GetFileAttributesEx(nativePath, @@ -2543,10 +2593,12 @@ TclpObjNormalizePath( (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] */ + /* + * 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++; } } @@ -2561,11 +2613,10 @@ TclpObjNormalizePath( */ /* - * 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. + * Check for symlinks, except at last component of path (we don't + * follow final symlinks). Also a drive (C:/) for example, may + * sometimes have the reparse flag set for some reason I don't + * understand. We therefore don't perform this check for drives. */ if (cur != 0 && !isDrive && @@ -2574,8 +2625,8 @@ TclpObjNormalizePath( if (to != NULL) { /* - * Read the reparse point ok. Now, reparse points need - * not be normalized, otherwise we could use: + * Read the reparse point ok. Now, reparse points need not + * be normalized, otherwise we could use: * * Tcl_GetStringFromObj(to, &pathLen); * nextCheckpoint = pathLen; @@ -2615,9 +2666,9 @@ TclpObjNormalizePath( #ifndef TclNORM_LONG_PATH /* - * Now we convert the tail of the current path to its 'long - * form', and append it to 'dsNorm' which holds the current - * normalized path + * Now we convert the tail of the current path to its 'long form', + * and append it to 'dsNorm' which holds the current normalized + * path */ if (isDrive) { @@ -2646,16 +2697,16 @@ TclpObjNormalizePath( int dotLen = currentPathEndPosition-lastValidPathEnd; /* - * Path is just dots. We shouldn't really ever see a - * path like that. However, to be nice we at least - * don't mangle the path - we just add the dots as a - * path segment and continue. + * Path is just dots. We shouldn't really ever see a path + * like that. However, to be nice we at least don't mangle + * the path - we just add the dots as a path segment and + * continue. */ Tcl_DStringAppend(&dsNorm, ((const char *)nativePath) + Tcl_DStringLength(&ds) - - (dotLen * sizeof(TCHAR)), - (int)(dotLen * sizeof(TCHAR))); + - (dotLen * sizeof(WCHAR)), + dotLen * sizeof(WCHAR)); } else { /* * Normal path. @@ -2667,8 +2718,7 @@ TclpObjNormalizePath( handle = FindFirstFileW((WCHAR *) nativePath, &fData); if (handle == INVALID_HANDLE_VALUE) { /* - * This is usually the '/' in 'c:/' at end of - * string. + * This is usually the '/' in 'c:/' at end of string. */ Tcl_DStringAppend(&dsNorm, (const char *) L"/", @@ -2698,8 +2748,8 @@ TclpObjNormalizePath( } /* - * 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; @@ -2713,10 +2763,10 @@ TclpObjNormalizePath( if (1) { WCHAR wpath[MAX_PATH]; - const TCHAR *nativePath = + const WCHAR *nativePath = Tcl_WinUtfToTChar(path, lastValidPathEnd - path, &ds); DWORD wpathlen = GetLongPathNameProc(nativePath, - (TCHAR *) wpath, MAX_PATH); + (WCHAR *) wpath, MAX_PATH); /* * We have to make the drive letter uppercase. @@ -2744,7 +2794,7 @@ TclpObjNormalizePath( * native encoding, so we have to convert it to Utf. */ - Tcl_WinTCharToUtf((const TCHAR *) Tcl_DStringValue(&dsNorm), + Tcl_WinTCharToUtf((const WCHAR *) Tcl_DStringValue(&dsNorm), Tcl_DStringLength(&dsNorm), &ds); nextCheckpoint = Tcl_DStringLength(&ds); if (*lastValidPathEnd != 0) { @@ -2752,14 +2802,15 @@ TclpObjNormalizePath( * Not the end of the string. */ + int len; char *path; Tcl_Obj *tmpPathPtr; tmpPathPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), nextCheckpoint); Tcl_AppendToObj(tmpPathPtr, lastValidPathEnd, -1); - path = TclGetString(tmpPathPtr); - Tcl_SetStringObj(pathPtr, path, tmpPathPtr->length); + path = TclGetStringFromObj(tmpPathPtr, &len); + Tcl_SetStringObj(pathPtr, path, len); Tcl_DecrRefCount(tmpPathPtr); } else { /* @@ -2842,8 +2893,8 @@ TclWinVolumeRelativeNormalize( * also on drive C. */ - const char *drive = TclGetString(useThisCwd); - size_t cwdLen = useThisCwd->length; + int cwdLen; + const char *drive = TclGetStringFromObj(useThisCwd, &cwdLen); char drive_cur = path[0]; if (drive_cur >= 'a') { @@ -2919,7 +2970,7 @@ TclpNativeToNormalized( int len; char *copy, *p; - Tcl_WinTCharToUtf((const TCHAR *) clientData, -1, &ds); + Tcl_WinTCharToUtf((const WCHAR *) clientData, -1, &ds); copy = Tcl_DStringValue(&ds); len = Tcl_DStringLength(&ds); @@ -2978,7 +3029,7 @@ TclNativeCreateNativeRep( WCHAR *nativePathPtr = NULL; const char *str; Tcl_Obj *validPathPtr; - size_t len; + int len; WCHAR *wp; if (TclFSCwdIsNative()) { @@ -2992,7 +3043,11 @@ TclNativeCreateNativeRep( if (validPathPtr == NULL) { return NULL; } - /* refCount of validPathPtr was already incremented in Tcl_FSGetTranslatedPath */ + + /* + * refCount of validPathPtr was already incremented in + * Tcl_FSGetTranslatedPath + */ } else { /* * Make sure the normalized path is set. @@ -3002,73 +3057,100 @@ TclNativeCreateNativeRep( if (validPathPtr == NULL) { return NULL; } - /* validPathPtr returned from Tcl_FSGetNormalizedPath is owned by Tcl, so incr refCount here */ + + /* + * validPathPtr returned from Tcl_FSGetNormalizedPath is owned by Tcl, + * so incr refCount here + */ + Tcl_IncrRefCount(validPathPtr); } - str = Tcl_GetString(validPathPtr); - len = validPathPtr->length; + str = Tcl_GetStringFromObj(validPathPtr, &len); + + if (strlen(str) != (size_t) len) { + /* + * String contains NUL-bytes. This is invalid. + */ - if (strlen(str)!=(unsigned int)len) { - /* String contains NUL-bytes. This is invalid. */ goto done; } - /* For a reserved device, strip a possible postfix ':' */ + + /* + * 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 */ + /* + * 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) ); + + /* + * 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); + 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]=='/')) { + * 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)); + * 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)); wp += 4; } + /* - ** If (remainder of) path starts with "<drive>:", - ** leave the ':' intact. + * 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)); + } 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. - */ + * 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; @@ -3079,7 +3161,6 @@ TclNativeCreateNativeRep( } done: - TclDecrRefCount(validPathPtr); return nativePathPtr; } @@ -3112,7 +3193,7 @@ TclNativeDupInternalRep( return NULL; } - len = sizeof(TCHAR) * (_tcslen((const TCHAR *) clientData) + 1); + len = sizeof(WCHAR) * (wcslen((const WCHAR *) clientData) + 1); copy = ckalloc(len); memcpy(copy, clientData, len); @@ -3143,7 +3224,7 @@ TclpUtime( { int res = 0; HANDLE fileHandle; - const TCHAR *native; + const WCHAR *native; DWORD attr = 0; DWORD flags = FILE_ATTRIBUTE_NORMAL; FILETIME lastAccessTime, lastModTime; @@ -3194,7 +3275,7 @@ int TclWinFileOwned( Tcl_Obj *pathPtr) /* File whose ownership is to be checked */ { - const TCHAR *native; + const WCHAR *native; PSID ownerSid = NULL; PSECURITY_DESCRIPTOR secd = NULL; HANDLE token; @@ -3205,21 +3286,28 @@ TclWinFileOwned( native = Tcl_FSGetNativePath(pathPtr); if (GetNamedSecurityInfo((LPTSTR) native, SE_FILE_OBJECT, - OWNER_SECURITY_INFORMATION, &ownerSid, - NULL, NULL, NULL, &secd) != ERROR_SUCCESS) { - /* Either not a file, or we do not have access to it in which - case we are in all likelihood not the owner */ + OWNER_SECURITY_INFORMATION, &ownerSid, NULL, NULL, NULL, + &secd) != ERROR_SUCCESS) { + /* + * Either not a file, or we do not have access to it in which case we + * are in all likelihood not the owner. + */ + return 0; } /* - * Getting the current process SID is a multi-step process. - * We make the assumption that if a call fails, this process is - * so underprivileged it could not possibly own anything. Normally - * a process can *always* look up its own token. + * Getting the current process SID is a multi-step process. We make the + * assumption that if a call fails, this process is so underprivileged it + * could not possibly own anything. Normally a process can *always* look + * up its own token. */ + if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &token)) { - /* Find out how big the buffer needs to be */ + /* + * Find out how big the buffer needs to be. + */ + bufsz = 0; GetTokenInformation(token, TokenUser, NULL, 0, &bufsz); if (bufsz) { @@ -3231,15 +3319,20 @@ TclWinFileOwned( CloseHandle(token); } - /* Free allocations and be done */ - if (secd) + /* + * Free allocations and be done. + */ + + if (secd) { LocalFree(secd); /* Also frees ownerSid */ - if (buf) + } + if (buf) { ckfree(buf); + } return (owned != 0); /* Convert non-0 to 1 */ } - + /* * Local Variables: * mode: c |
