summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFinn Womack <flan313@gmail.com>2023-04-27 14:23:26 (GMT)
committerGitHub <noreply@github.com>2023-04-27 14:23:26 (GMT)
commitb701dce340352e1a20c1776feaa368d4bba91128 (patch)
tree2151d55bb20e86e77b5d5776f050cf4cb5d06257
parent8a0c7f1e402768c7e806e2472e0a493c1800851f (diff)
downloadcpython-b701dce340352e1a20c1776feaa368d4bba91128.zip
cpython-b701dce340352e1a20c1776feaa368d4bba91128.tar.gz
cpython-b701dce340352e1a20c1776feaa368d4bba91128.tar.bz2
gh-102765: Update ntpath.isdir/isfile/islink/exists to use GetFileInformationByName when available (GH-103485)
-rw-r--r--Include/internal/pycore_fileutils_windows.h18
-rw-r--r--Modules/posixmodule.c309
2 files changed, 209 insertions, 118 deletions
diff --git a/Include/internal/pycore_fileutils_windows.h b/Include/internal/pycore_fileutils_windows.h
index 9bc7feb..e804d38 100644
--- a/Include/internal/pycore_fileutils_windows.h
+++ b/Include/internal/pycore_fileutils_windows.h
@@ -75,6 +75,24 @@ static inline BOOL _Py_GetFileInformationByName(
return GetFileInformationByName(FileName, FileInformationClass, FileInfoBuffer, FileInfoBufferSize);
}
+static inline BOOL _Py_GetFileInformationByName_ErrorIsTrustworthy(int error)
+{
+ switch(error) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_NOT_READY:
+ case ERROR_BAD_NET_NAME:
+ case ERROR_BAD_NETPATH:
+ case ERROR_BAD_PATHNAME:
+ case ERROR_INVALID_NAME:
+ case ERROR_FILENAME_EXCED_RANGE:
+ return TRUE;
+ case ERROR_NOT_SUPPORTED:
+ return FALSE;
+ }
+ return FALSE;
+}
+
#endif
#endif
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index dd15010..dcb5e7a 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -4789,6 +4789,8 @@ os__path_isdir_impl(PyObject *module, PyObject *path)
FILE_BASIC_INFO info;
path_t _path = PATH_T_INITIALIZE("isdir", "path", 0, 1);
int result;
+ BOOL slow_path = TRUE;
+ FILE_STAT_BASIC_INFORMATION statInfo;
if (!path_converter(path, &_path)) {
path_cleanup(&_path);
@@ -4800,43 +4802,60 @@ os__path_isdir_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
- if (_path.fd != -1) {
- hfile = _Py_get_osfhandle_noraise(_path.fd);
- close_file = FALSE;
- }
- else {
- hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (_path.wide) {
+ if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo,
+ &statInfo, sizeof(statInfo))) {
+ if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ slow_path = FALSE;
+ result = statInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ } else if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ slow_path = FALSE;
+ result = 0;
+ }
+ } else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(GetLastError())) {
+ slow_path = FALSE;
+ result = 0;
+ }
}
- if (hfile != INVALID_HANDLE_VALUE) {
- if (GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
- sizeof(info)))
- {
- result = info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+ if (slow_path) {
+ if (_path.fd != -1) {
+ hfile = _Py_get_osfhandle_noraise(_path.fd);
+ close_file = FALSE;
}
else {
- result = 0;
+ hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
}
- if (close_file) {
- CloseHandle(hfile);
- }
- }
- else {
- STRUCT_STAT st;
- switch (GetLastError()) {
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- case ERROR_CANT_ACCESS_FILE:
- case ERROR_INVALID_PARAMETER:
- if (STAT(_path.wide, &st)) {
- result = 0;
+ if (hfile != INVALID_HANDLE_VALUE) {
+ if (GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
+ sizeof(info)))
+ {
+ result = info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY;
}
else {
- result = S_ISDIR(st.st_mode);
+ result = 0;
+ }
+ if (close_file) {
+ CloseHandle(hfile);
+ }
+ }
+ else {
+ STRUCT_STAT st;
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_CANT_ACCESS_FILE:
+ case ERROR_INVALID_PARAMETER:
+ if (STAT(_path.wide, &st)) {
+ result = 0;
+ }
+ else {
+ result = S_ISDIR(st.st_mode);
+ }
+ break;
+ default:
+ result = 0;
}
- break;
- default:
- result = 0;
}
}
Py_END_ALLOW_THREADS
@@ -4867,6 +4886,8 @@ os__path_isfile_impl(PyObject *module, PyObject *path)
FILE_BASIC_INFO info;
path_t _path = PATH_T_INITIALIZE("isfile", "path", 0, 1);
int result;
+ BOOL slow_path = TRUE;
+ FILE_STAT_BASIC_INFORMATION statInfo;
if (!path_converter(path, &_path)) {
path_cleanup(&_path);
@@ -4878,43 +4899,60 @@ os__path_isfile_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
- if (_path.fd != -1) {
- hfile = _Py_get_osfhandle_noraise(_path.fd);
- close_file = FALSE;
- }
- else {
- hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (_path.wide) {
+ if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo,
+ &statInfo, sizeof(statInfo))) {
+ if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ slow_path = FALSE;
+ result = !(statInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+ } else if (statInfo.FileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+ slow_path = FALSE;
+ result = 0;
+ }
+ } else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(GetLastError())) {
+ slow_path = FALSE;
+ result = 0;
+ }
}
- if (hfile != INVALID_HANDLE_VALUE) {
- if (GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
- sizeof(info)))
- {
- result = !(info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+ if (slow_path) {
+ if (_path.fd != -1) {
+ hfile = _Py_get_osfhandle_noraise(_path.fd);
+ close_file = FALSE;
}
else {
- result = 0;
- }
- if (close_file) {
- CloseHandle(hfile);
+ hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
}
- }
- else {
- STRUCT_STAT st;
- switch (GetLastError()) {
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- case ERROR_CANT_ACCESS_FILE:
- case ERROR_INVALID_PARAMETER:
- if (STAT(_path.wide, &st)) {
- result = 0;
+ if (hfile != INVALID_HANDLE_VALUE) {
+ if (GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
+ sizeof(info)))
+ {
+ result = !(info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY);
}
else {
- result = S_ISREG(st.st_mode);
+ result = 0;
+ }
+ if (close_file) {
+ CloseHandle(hfile);
+ }
+ }
+ else {
+ STRUCT_STAT st;
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_CANT_ACCESS_FILE:
+ case ERROR_INVALID_PARAMETER:
+ if (STAT(_path.wide, &st)) {
+ result = 0;
+ }
+ else {
+ result = S_ISREG(st.st_mode);
+ }
+ break;
+ default:
+ result = 0;
}
- break;
- default:
- result = 0;
}
}
Py_END_ALLOW_THREADS
@@ -4944,6 +4982,8 @@ os__path_exists_impl(PyObject *module, PyObject *path)
BOOL close_file = TRUE;
path_t _path = PATH_T_INITIALIZE("exists", "path", 0, 1);
int result;
+ BOOL slow_path = TRUE;
+ FILE_STAT_BASIC_INFORMATION statInfo;
if (!path_converter(path, &_path)) {
path_cleanup(&_path);
@@ -4955,36 +4995,50 @@ os__path_exists_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
- if (_path.fd != -1) {
- hfile = _Py_get_osfhandle_noraise(_path.fd);
- close_file = FALSE;
- }
- else {
- hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
- OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- }
- if (hfile != INVALID_HANDLE_VALUE) {
- result = 1;
- if (close_file) {
- CloseHandle(hfile);
+ if (_path.wide) {
+ if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo,
+ &statInfo, sizeof(statInfo))) {
+ if (!(statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)) {
+ slow_path = FALSE;
+ result = 1;
+ }
+ } else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(GetLastError())) {
+ slow_path = FALSE;
+ result = 0;
}
}
- else {
- STRUCT_STAT st;
- switch (GetLastError()) {
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- case ERROR_CANT_ACCESS_FILE:
- case ERROR_INVALID_PARAMETER:
- if (STAT(_path.wide, &st)) {
- result = 0;
+ if (slow_path) {
+ if (_path.fd != -1) {
+ hfile = _Py_get_osfhandle_noraise(_path.fd);
+ close_file = FALSE;
+ }
+ else {
+ hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
+ OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+ if (hfile != INVALID_HANDLE_VALUE) {
+ result = 1;
+ if (close_file) {
+ CloseHandle(hfile);
}
- else {
- result = 1;
+ }
+ else {
+ STRUCT_STAT st;
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_CANT_ACCESS_FILE:
+ case ERROR_INVALID_PARAMETER:
+ if (STAT(_path.wide, &st)) {
+ result = 0;
+ }
+ else {
+ result = 1;
+ }
+ break;
+ default:
+ result = 0;
}
- break;
- default:
- result = 0;
}
}
Py_END_ALLOW_THREADS
@@ -5015,6 +5069,8 @@ os__path_islink_impl(PyObject *module, PyObject *path)
FILE_ATTRIBUTE_TAG_INFO info;
path_t _path = PATH_T_INITIALIZE("islink", "path", 0, 1);
int result;
+ BOOL slow_path = TRUE;
+ FILE_STAT_BASIC_INFORMATION statInfo;
if (!path_converter(path, &_path)) {
path_cleanup(&_path);
@@ -5026,45 +5082,62 @@ os__path_islink_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
- if (_path.fd != -1) {
- hfile = _Py_get_osfhandle_noraise(_path.fd);
- close_file = FALSE;
+ if (_path.wide) {
+ if (_Py_GetFileInformationByName(_path.wide, FileStatBasicByNameInfo,
+ &statInfo, sizeof(statInfo))) {
+ slow_path = FALSE;
+ if (statInfo.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ result = (statInfo.ReparseTag == IO_REPARSE_TAG_SYMLINK);
+ }
+ else {
+ result = 0;
+ }
+ } else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(GetLastError())) {
+ slow_path = FALSE;
+ result = 0;
+ }
}
- else {
- hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
- NULL);
- }
- if (hfile != INVALID_HANDLE_VALUE) {
- if (GetFileInformationByHandleEx(hfile, FileAttributeTagInfo, &info,
- sizeof(info)))
- {
- result = (info.ReparseTag == IO_REPARSE_TAG_SYMLINK);
+ if (slow_path) {
+ if (_path.fd != -1) {
+ hfile = _Py_get_osfhandle_noraise(_path.fd);
+ close_file = FALSE;
}
else {
- result = 0;
+ hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
}
- if (close_file) {
- CloseHandle(hfile);
- }
- }
- else {
- STRUCT_STAT st;
- switch (GetLastError()) {
- case ERROR_ACCESS_DENIED:
- case ERROR_SHARING_VIOLATION:
- case ERROR_CANT_ACCESS_FILE:
- case ERROR_INVALID_PARAMETER:
- if (LSTAT(_path.wide, &st)) {
- result = 0;
+ if (hfile != INVALID_HANDLE_VALUE) {
+ if (GetFileInformationByHandleEx(hfile, FileAttributeTagInfo, &info,
+ sizeof(info)))
+ {
+ result = (info.ReparseTag == IO_REPARSE_TAG_SYMLINK);
}
else {
- result = S_ISLNK(st.st_mode);
+ result = 0;
+ }
+ if (close_file) {
+ CloseHandle(hfile);
+ }
+ }
+ else {
+ STRUCT_STAT st;
+ switch (GetLastError()) {
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_CANT_ACCESS_FILE:
+ case ERROR_INVALID_PARAMETER:
+ if (LSTAT(_path.wide, &st)) {
+ result = 0;
+ }
+ else {
+ result = S_ISLNK(st.st_mode);
+ }
+ break;
+ default:
+ result = 0;
}
- break;
- default:
- result = 0;
}
}
Py_END_ALLOW_THREADS