summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsebres <sebres@users.sourceforge.net>2018-05-28 12:05:15 (GMT)
committersebres <sebres@users.sourceforge.net>2018-05-28 12:05:15 (GMT)
commit89a84af271178d64a75a68b44f8434452fcba03e (patch)
tree67e81891ed43cbfe3ccc68548890666ec0d0fd1e
parenta410c0d8d504868b1dbdcaf70a521859e32327fd (diff)
parent5e7a1545a61ab4e66c1796ad19343e15cd2cc2ba (diff)
downloadtcl-89a84af271178d64a75a68b44f8434452fcba03e.zip
tcl-89a84af271178d64a75a68b44f8434452fcba03e.tar.gz
tcl-89a84af271178d64a75a68b44f8434452fcba03e.tar.bz2
merge-integrate sebres-bug-9e6b569963-8-5-branch to 8.5
-rw-r--r--tests/fileSystem.test6
-rwxr-xr-xwin/tclWinFile.c179
-rw-r--r--win/tclWinInit.c34
-rw-r--r--win/tclWinInt.h2
4 files changed, 142 insertions, 79 deletions
diff --git a/tests/fileSystem.test b/tests/fileSystem.test
index 1c507e1..36a10cf 100644
--- a/tests/fileSystem.test
+++ b/tests/fileSystem.test
@@ -268,6 +268,12 @@ removeDirectory dir.dir
test filesystem-1.30 {normalisation of nonexistent user} {
list [catch {file normalize ~noonewiththisname} err] $err
} {1 {user "noonewiththisname" doesn't exist}}
+test filesystem-1.30.1 {normalisation of existing user} -body {
+ catch {file normalize ~$::tcl_platform(user)}
+} -result {0}
+test filesystem-1.30.2 {normalisation of nonexistent user specified as user@domain} -body {
+ file normalize ~nonexistentuser@nonexistentdomain
+} -returnCodes error -result {user "nonexistentuser@nonexistentdomain" doesn't exist}
test filesystem-1.31 {link normalisation: link near filesystem root} {testsetplatform} {
testsetplatform unix
file normalize /foo/../bar
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index 1acc225..0bed39e 100755
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -1422,84 +1422,127 @@ TclpGetUserHome(
* name of user's home directory. */
{
char *result;
- HINSTANCE netapiInst;
- HINSTANCE userenvInst;
+
+ static NETAPIBUFFERFREEPROC *netApiBufferFreeProc;
+ static NETGETDCNAMEPROC *netGetDCNameProc;
+ static NETUSERGETINFOPROC *netUserGetInfoProc;
+ static GETPROFILESDIRECTORYPROC *getProfilesDirectoryProc;
+ static int apistubs = 0;
result = NULL;
Tcl_DStringInit(bufferPtr);
- netapiInst = LoadLibraryA("netapi32.dll");
- userenvInst = LoadLibraryA("userenv.dll");
- if (netapiInst != NULL && userenvInst != NULL) {
- NETAPIBUFFERFREEPROC *netApiBufferFreeProc;
- NETGETDCNAMEPROC *netGetDCNameProc;
- NETUSERGETINFOPROC *netUserGetInfoProc;
- GETPROFILESDIRECTORYPROC *getProfilesDirectoryProc;
-
- netApiBufferFreeProc = (NETAPIBUFFERFREEPROC *)
- GetProcAddress(netapiInst, "NetApiBufferFree");
- netGetDCNameProc = (NETGETDCNAMEPROC *)
- GetProcAddress(netapiInst, "NetGetDCName");
- netUserGetInfoProc = (NETUSERGETINFOPROC *)
- GetProcAddress(netapiInst, "NetUserGetInfo");
- getProfilesDirectoryProc = (GETPROFILESDIRECTORYPROC *)
- GetProcAddress(userenvInst, "GetProfilesDirectoryW");
- if ((netUserGetInfoProc != NULL) && (netGetDCNameProc != NULL)
- && (netApiBufferFreeProc != NULL) && (getProfilesDirectoryProc != NULL)) {
- USER_INFO_1 *uiPtr, **uiPtrPtr = &uiPtr;
- Tcl_DString ds;
- int nameLen, badDomain;
- char *domain;
- WCHAR *wName, *wHomeDir, *wDomain;
- 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 (!apistubs) {
+ HINSTANCE handle;
+ TCL_DECLARE_MUTEX(initializeMutex)
+ Tcl_MutexLock(&initializeMutex);
+ if (!apistubs) {
+ handle = LoadLibraryA("netapi32.dll");
+ if (handle) {
+ netApiBufferFreeProc = (NETAPIBUFFERFREEPROC *)
+ GetProcAddress(handle, "NetApiBufferFree");
+ netGetDCNameProc = (NETGETDCNAMEPROC *)
+ GetProcAddress(handle, "NetGetDCName");
+ netUserGetInfoProc = (NETUSERGETINFOPROC *)
+ GetProcAddress(handle, "NetUserGetInfo");
+ Tcl_CreateExitHandler(TclpUnloadFile, handle);
}
- if (badDomain == 0) {
- Tcl_DStringInit(&ds);
- wName = Tcl_UtfToUniCharDString(name, nameLen, &ds);
- if ((netUserGetInfoProc)(wDomain, wName, 1,
- (LPBYTE *) uiPtrPtr) == 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);
- } else {
- /*
- * User exists but has no home dir. Return
- * "{GetProfilesDirectory}/<user>".
- */
- getProfilesDirectoryProc(buf, &size);
- Tcl_UniCharToUtfDString(buf, size-1, bufferPtr);
- Tcl_DStringAppend(bufferPtr, "/", 1);
- Tcl_DStringAppend(bufferPtr, name, nameLen);
- }
+ handle = LoadLibraryA("userenv.dll");
+ if (handle) {
+ getProfilesDirectoryProc = (GETPROFILESDIRECTORYPROC *)
+ GetProcAddress(handle, "GetProfilesDirectoryW");
+ Tcl_CreateExitHandler(TclpUnloadFile, handle);
+ }
+
+ apistubs = -1;
+ if ( (netUserGetInfoProc != NULL) && (netGetDCNameProc != NULL)
+ && (netApiBufferFreeProc != NULL) && (getProfilesDirectoryProc != NULL)
+ ) {
+ apistubs = 1;
+ }
+ }
+ Tcl_MutexUnlock(&initializeMutex);
+ }
+
+ if (apistubs == 1) {
+ USER_INFO_1 *uiPtr;
+ Tcl_DString ds;
+ int nameLen, rc;
+ char *domain;
+ WCHAR *wName, *wHomeDir, *wDomain;
+ WCHAR buf[MAX_PATH];
+
+ rc = 0;
+ nameLen = -1;
+ wDomain = NULL;
+ domain = strchr(name, '@');
+ 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 */
+ ptr = TclGetEnv("HOME", &ds);
+ if (ptr != NULL) {
+ Tcl_JoinPath(1, &ptr, bufferPtr);
+ rc = 1;
result = Tcl_DStringValue(bufferPtr);
- /* be sure we returns normalized path */
- for (i = 0; i < size; ++i){
- if (result[i] == '\\') result[i] = '/';
- }
- (*netApiBufferFreeProc)((void *) uiPtr);
}
- Tcl_DStringFree(&ds);
}
- if (wDomain != NULL) {
- (*netApiBufferFreeProc)((void *) wDomain);
+ Tcl_DStringFree(&ds);
+ } else {
+ Tcl_DStringInit(&ds);
+ wName = Tcl_UtfToUniCharDString(domain + 1, -1, &ds);
+ rc = (netGetDCNameProc)(NULL, wName, (LPBYTE *) &wDomain);
+ Tcl_DStringFree(&ds);
+ nameLen = domain - name;
+ }
+ if (rc == 0) {
+ Tcl_DStringInit(&ds);
+ wName = Tcl_UtfToUniCharDString(name, nameLen, &ds);
+ while ((netUserGetInfoProc)(wDomain, wName, 1,
+ (LPBYTE *) &uiPtr) != 0) {
+ /*
+ * user does not exists - if domain was not specified,
+ * try again using current domain.
+ */
+ rc = 1;
+ if (domain != NULL) break;
+ /* get current domain */
+ rc = (netGetDCNameProc)(NULL, NULL, (LPBYTE *) &wDomain);
+ 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);
+ } else {
+ /*
+ * User exists but has no home dir. Return
+ * "{GetProfilesDirectory}/<user>".
+ */
+ getProfilesDirectoryProc(buf, &size);
+ Tcl_UniCharToUtfDString(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] = '/';
+ }
+ (*netApiBufferFreeProc)((void *) uiPtr);
+ }
+ Tcl_DStringFree(&ds);
+ }
+ if (wDomain != NULL) {
+ (*netApiBufferFreeProc)((void *) wDomain);
}
- FreeLibrary(userenvInst);
- FreeLibrary(netapiInst);
}
if (result == NULL) {
/*
diff --git a/win/tclWinInit.c b/win/tclWinInit.c
index 1ba7a31..7fa2b7a 100644
--- a/win/tclWinInit.c
+++ b/win/tclWinInit.c
@@ -532,6 +532,27 @@ Tcl_GetEncodingNameFromEnvironment(
return Tcl_DStringValue(bufPtr);
}
+const char *
+TclpGetUserName(
+ Tcl_DString *bufferPtr) /* Uninitialized or free DString filled with
+ * the name of user. */
+{
+ Tcl_DStringInit(bufferPtr);
+
+ if (TclGetEnv("USERNAME", bufferPtr) == NULL) {
+ WCHAR szUserName[UNLEN+1];
+ DWORD cchUserNameLen = UNLEN;
+
+ if (!tclWinProcs->getUserName((LPTSTR)szUserName, &cchUserNameLen)) {
+ return NULL;
+ }
+ cchUserNameLen--;
+ if (tclWinProcs->useWide) cchUserNameLen *= sizeof(WCHAR);
+ Tcl_WinTCharToUtf((LPTSTR)szUserName, cchUserNameLen, bufferPtr);
+ }
+ return Tcl_DStringValue(bufferPtr);
+}
+
/*
*---------------------------------------------------------------------------
*
@@ -562,8 +583,6 @@ TclpSetVariables(
static OSVERSIONINFOW osInfo;
static int osInfoInitialized = 0;
Tcl_DString ds;
- WCHAR szUserName[UNLEN+1];
- DWORD cchUserNameLen = UNLEN;
Tcl_SetVar2Ex(interp, "tclDefaultLibrary", NULL,
TclGetProcessGlobalValue(&defaultLibraryDir), TCL_GLOBAL_ONLY);
@@ -641,15 +660,8 @@ TclpSetVariables(
* Note: cchUserNameLen is number of characters including nul terminator.
*/
- Tcl_DStringInit(&ds);
- if (TclGetEnv("USERNAME", &ds) == NULL) {
- if (tclWinProcs->getUserName((LPTSTR)szUserName, &cchUserNameLen) != 0) {
- int cbUserNameLen = cchUserNameLen - 1;
- if (tclWinProcs->useWide) cbUserNameLen *= sizeof(WCHAR);
- Tcl_WinTCharToUtf((LPTSTR)szUserName, cbUserNameLen, &ds);
- }
- }
- Tcl_SetVar2(interp, "tcl_platform", "user", Tcl_DStringValue(&ds),
+ ptr = TclpGetUserName(&ds);
+ Tcl_SetVar2(interp, "tcl_platform", "user", ptr ? ptr : "",
TCL_GLOBAL_ONLY);
Tcl_DStringFree(&ds);
}
diff --git a/win/tclWinInt.h b/win/tclWinInt.h
index ccf48bb..af6619f 100644
--- a/win/tclWinInt.h
+++ b/win/tclWinInt.h
@@ -201,6 +201,8 @@ MODULE_SCOPE void * TclpGetAllocCache(void);
MODULE_SCOPE void TclpSetAllocCache(void *);
#endif /* TCL_THREADS */
+MODULE_SCOPE const char*TclpGetUserName(Tcl_DString *bufferPtr);
+
/* Needed by tclWinFile.c and tclWinFCmd.c */
#ifndef FILE_ATTRIBUTE_REPARSE_POINT
#define FILE_ATTRIBUTE_REPARSE_POINT 0x00000400