summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorapnadkarni <apnmbx-wits@yahoo.com>2023-03-05 09:57:29 (GMT)
committerapnadkarni <apnmbx-wits@yahoo.com>2023-03-05 09:57:29 (GMT)
commit1f7d2aae34515de9d6d64ab799f670a1ce5141fc (patch)
tree70b43a73aac6cd2c756bf315e7abee22f77ce22d
parente13edcba869deda8b613854d533c106c9855b61d (diff)
parentc862e5709590a9330c9b814109a0fbfd70f027cb (diff)
downloadtcl-1f7d2aae34515de9d6d64ab799f670a1ce5141fc.zip
tcl-1f7d2aae34515de9d6d64ab799f670a1ce5141fc.tar.gz
tcl-1f7d2aae34515de9d6d64ab799f670a1ce5141fc.tar.bz2
Bug [9c5a00c69d]. Fix ~user on Windows
-rw-r--r--tests/fileSystem.test10
-rw-r--r--win/tclWinFile.c73
2 files changed, 45 insertions, 38 deletions
diff --git a/tests/fileSystem.test b/tests/fileSystem.test
index f363d86..2de778a 100644
--- a/tests/fileSystem.test
+++ b/tests/fileSystem.test
@@ -277,6 +277,16 @@ test filesystem-1.30.1 {normalisation of existing user} -body {
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.30.3 {file normalization should distinguish between ~ and ~user} -setup {
+ set oldhome $::env(HOME)
+ set olduserhome [file normalize ~$::tcl_platform(user)]
+ set ::env(HOME) [file join $oldhome temp]
+} -cleanup {
+ set env(HOME) $oldhome
+} -body {
+ list [string equal [file normalize ~] $::env(HOME)] \
+ [string equal $olduserhome [file normalize ~$::tcl_platform(user)]]
+} -result {1 1}
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 9a6c5f1..639cd72 100644
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -1458,22 +1458,43 @@ TclpGetUserHome(
if (domain == NULL) {
const char *ptr;
- /*
- * No domain. Firstly check it's the current user
- */
-
+ /*
+ * Treat the current user as a special case because the general case
+ * below does not properly retrieve the path. The NetUserGetInfo
+ * call returns an empty path and the code defaults to the user's
+ * name in the profiles directory. On modern Windows systems, this
+ * is generally wrong as when the account is a Microsoft account,
+ * for example abcdefghi@outlook.com, the directory name is
+ * abcde and not abcdefghi.
+ *
+ * Note we could have just used env(USERPROFILE) here but
+ * the intent is to retrieve (as on Unix) the system's view
+ * of the home irrespective of environment settings of HOME
+ * and USERPROFILE.
+ *
+ * Fixing this for the general user needs more investigating but
+ * at least for the current user we can use a direct call.
+ */
ptr = TclpGetUserName(&ds);
if (ptr != NULL && strcasecmp(name, ptr) == 0) {
- /*
- * 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);
- }
+ HANDLE hProcess;
+ WCHAR buf[MAX_PATH];
+ DWORD nChars = sizeof(buf) / sizeof(buf[0]);
+ /* Sadly GetCurrentProcessToken not in Win 7 so slightly longer */
+ hProcess = GetCurrentProcess(); /* Need not be closed */
+ if (hProcess) {
+ HANDLE hToken;
+ if (OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
+ if (GetUserProfileDirectoryW(hToken, buf, &nChars)) {
+ Tcl_WinTCharToUtf((TCHAR *)buf,
+ (nChars-1)*sizeof(WCHAR),
+ bufferPtr);
+ result = Tcl_DStringValue(bufferPtr);
+ rc = 1;
+ }
+ CloseHandle(hToken);
+ }
+ }
}
Tcl_DStringFree(&ds);
} else {
@@ -1542,30 +1563,6 @@ TclpGetUserHome(
if (wDomain != NULL) {
NetApiBufferFree((void *) wDomain);
}
- if (result == NULL) {
- /*
- * Look in the "Password Lists" section of system.ini for the local
- * user. There are also entries in that section that begin with a "*"
- * character that are used by Windows for other purposes; ignore user
- * names beginning with a "*".
- */
-
- char buf[MAX_PATH];
-
- if (name[0] != '*') {
- if (GetPrivateProfileStringA("Password Lists", name, "", buf,
- MAX_PATH, "system.ini") > 0) {
- /*
- * User exists, but there is no such thing as a home directory
- * in system.ini. Return "{Windows drive}:/".
- */
-
- GetWindowsDirectoryA(buf, MAX_PATH);
- Tcl_DStringAppend(bufferPtr, buf, 3);
- result = Tcl_DStringValue(bufferPtr);
- }
- }
- }
return result;
}