summaryrefslogtreecommitdiffstats
path: root/win/tclWinFile.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2018-05-11 11:26:35 (GMT)
committerdgp <dgp@users.sourceforge.net>2018-05-11 11:26:35 (GMT)
commit2a340ce4c19c7e7ad149a1263f169a1749c3465c (patch)
tree93ca7493ebe94c66e12fc76c96a0ba80721d3905 /win/tclWinFile.c
parent4d9ba4a6528b96b85dd0037953e94a5f4aa623be (diff)
parent9cb3b15616e82cdd2edc695371adfeed5f4fb023 (diff)
downloadtcl-2a340ce4c19c7e7ad149a1263f169a1749c3465c.zip
tcl-2a340ce4c19c7e7ad149a1263f169a1749c3465c.tar.gz
tcl-2a340ce4c19c7e7ad149a1263f169a1749c3465c.tar.bz2
merge 8.7
Diffstat (limited to 'win/tclWinFile.c')
-rwxr-xr-xwin/tclWinFile.c58
1 files changed, 39 insertions, 19 deletions
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index 700e3c8..7693f06 100755
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -1561,11 +1561,12 @@ NativeAccess(
return 0;
}
- if ((mode & W_OK)
- && (attr & FILE_ATTRIBUTE_READONLY)
- && !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ /*
+ * If it's not a directory (assume file), do several fast checks:
+ */
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) {
/*
- * The attributes say the file is not writable. If the file is a
+ * 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
* (mostly) ignored by Windows, so we can't ascertain anything about
@@ -1573,21 +1574,38 @@ NativeAccess(
* advanced 'getFileSecurityProc', then more robust ACL checks
* will be done below.
*/
+ if ((mode & W_OK) && (attr & FILE_ATTRIBUTE_READONLY)) {
+ Tcl_SetErrno(EACCES);
+ return -1;
+ }
- Tcl_SetErrno(EACCES);
- return -1;
- }
-
- if (mode & X_OK) {
- if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) {
- /*
- * It's not a directory and doesn't have the correct extension.
- * Therefore 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 */
+ 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; }
+
+ hFile = CreateFile(nativePath, mask,
+ 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 */
+ if (GetLastError() == ERROR_ACCESS_DENIED) {
+ Tcl_SetErrno(EACCES);
+ return -1;
+ }
+ }
+ /* We cannnot verify the access fast, check it below using security info. */
}
/*
@@ -1792,10 +1810,12 @@ NativeIsExec(
return 0;
}
- if ((_tcsicmp(path+len-3, TEXT("exe")) == 0)
- || (_tcsicmp(path+len-3, TEXT("com")) == 0)
- || (_tcsicmp(path+len-3, TEXT("cmd")) == 0)
- || (_tcsicmp(path+len-3, TEXT("bat")) == 0)) {
+ 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)) {
return 1;
}
return 0;