diff options
author | dgp <dgp@users.sourceforge.net> | 2018-05-11 11:26:35 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2018-05-11 11:26:35 (GMT) |
commit | 2a340ce4c19c7e7ad149a1263f169a1749c3465c (patch) | |
tree | 93ca7493ebe94c66e12fc76c96a0ba80721d3905 /win/tclWinFile.c | |
parent | 4d9ba4a6528b96b85dd0037953e94a5f4aa623be (diff) | |
parent | 9cb3b15616e82cdd2edc695371adfeed5f4fb023 (diff) | |
download | tcl-2a340ce4c19c7e7ad149a1263f169a1749c3465c.zip tcl-2a340ce4c19c7e7ad149a1263f169a1749c3465c.tar.gz tcl-2a340ce4c19c7e7ad149a1263f169a1749c3465c.tar.bz2 |
merge 8.7
Diffstat (limited to 'win/tclWinFile.c')
-rwxr-xr-x | win/tclWinFile.c | 58 |
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; |