gh-102765: Update ntpath.isdir/isfile/islink/exists to use GetFileInformationByName when available (GH-103485)

This commit is contained in:
Finn Womack 2023-04-27 07:23:26 -07:00 committed by GitHub
parent 8a0c7f1e40
commit b701dce340
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 223 additions and 132 deletions

View File

@ -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

View File

@ -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,6 +4802,22 @@ os__path_isdir_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
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 (slow_path) {
if (_path.fd != -1) {
hfile = _Py_get_osfhandle_noraise(_path.fd);
close_file = FALSE;
@ -4839,6 +4857,7 @@ os__path_isdir_impl(PyObject *module, PyObject *path)
result = 0;
}
}
}
Py_END_ALLOW_THREADS
path_cleanup(&_path);
@ -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,6 +4899,22 @@ os__path_isfile_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
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 (slow_path) {
if (_path.fd != -1) {
hfile = _Py_get_osfhandle_noraise(_path.fd);
close_file = FALSE;
@ -4917,6 +4954,7 @@ os__path_isfile_impl(PyObject *module, PyObject *path)
result = 0;
}
}
}
Py_END_ALLOW_THREADS
path_cleanup(&_path);
@ -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,6 +4995,19 @@ os__path_exists_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
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;
}
}
if (slow_path) {
if (_path.fd != -1) {
hfile = _Py_get_osfhandle_noraise(_path.fd);
close_file = FALSE;
@ -4987,6 +5040,7 @@ os__path_exists_impl(PyObject *module, PyObject *path)
result = 0;
}
}
}
Py_END_ALLOW_THREADS
path_cleanup(&_path);
@ -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,6 +5082,22 @@ os__path_islink_impl(PyObject *module, PyObject *path)
}
Py_BEGIN_ALLOW_THREADS
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;
}
}
if (slow_path) {
if (_path.fd != -1) {
hfile = _Py_get_osfhandle_noraise(_path.fd);
close_file = FALSE;
@ -5067,6 +5139,7 @@ os__path_islink_impl(PyObject *module, PyObject *path)
result = 0;
}
}
}
Py_END_ALLOW_THREADS
path_cleanup(&_path);