mirror of
https://github.com/python/cpython.git
synced 2025-09-11 11:17:16 +00:00
gh-118507 : Refactor nt._path_is*
to improve applicability for other cases (GH-118755)
(cherry picked from commit b64182550f
)
Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com>
This commit is contained in:
parent
f371565169
commit
f15fbe9991
6 changed files with 528 additions and 440 deletions
|
@ -5088,384 +5088,363 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
|
|||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_isdir
|
||||
#define PY_IFREG 1 // Regular file
|
||||
#define PY_IFDIR 2 // Directory
|
||||
#define PY_IFLNK 4 // Symlink
|
||||
#define PY_IFMNT 8 // Mount Point (junction)
|
||||
#define PY_IFLRP 16 // Link Reparse Point (name-surrogate, symlink, junction)
|
||||
#define PY_IFRRP 32 // Regular Reparse Point
|
||||
|
||||
s: 'O'
|
||||
static inline BOOL
|
||||
_testInfo(DWORD attributes, DWORD reparseTag, BOOL diskDevice, int testedType)
|
||||
{
|
||||
switch (testedType) {
|
||||
case PY_IFREG:
|
||||
return diskDevice && attributes &&
|
||||
!(attributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
case PY_IFDIR:
|
||||
return attributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
case PY_IFLNK:
|
||||
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
reparseTag == IO_REPARSE_TAG_SYMLINK;
|
||||
case PY_IFMNT:
|
||||
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
reparseTag == IO_REPARSE_TAG_MOUNT_POINT;
|
||||
case PY_IFLRP:
|
||||
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
IsReparseTagNameSurrogate(reparseTag);
|
||||
case PY_IFRRP:
|
||||
return (attributes & FILE_ATTRIBUTE_REPARSE_POINT) &&
|
||||
reparseTag && !IsReparseTagNameSurrogate(reparseTag);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static BOOL
|
||||
_testFileTypeByHandle(HANDLE hfile, int testedType, BOOL diskOnly)
|
||||
{
|
||||
assert(testedType == PY_IFREG || testedType == PY_IFDIR ||
|
||||
testedType == PY_IFLNK || testedType == PY_IFMNT ||
|
||||
testedType == PY_IFLRP || testedType == PY_IFRRP);
|
||||
|
||||
BOOL diskDevice = GetFileType(hfile) == FILE_TYPE_DISK;
|
||||
if (diskOnly && !diskDevice) {
|
||||
return FALSE;
|
||||
}
|
||||
if (testedType != PY_IFREG && testedType != PY_IFDIR) {
|
||||
FILE_ATTRIBUTE_TAG_INFO info;
|
||||
return GetFileInformationByHandleEx(hfile, FileAttributeTagInfo, &info,
|
||||
sizeof(info)) &&
|
||||
_testInfo(info.FileAttributes, info.ReparseTag, diskDevice,
|
||||
testedType);
|
||||
}
|
||||
FILE_BASIC_INFO info;
|
||||
return GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
|
||||
sizeof(info)) &&
|
||||
_testInfo(info.FileAttributes, 0, diskDevice, testedType);
|
||||
}
|
||||
|
||||
static BOOL
|
||||
_testFileTypeByName(LPCWSTR path, int testedType)
|
||||
{
|
||||
assert(testedType == PY_IFREG || testedType == PY_IFDIR ||
|
||||
testedType == PY_IFLNK || testedType == PY_IFMNT ||
|
||||
testedType == PY_IFLRP || testedType == PY_IFRRP);
|
||||
|
||||
FILE_STAT_BASIC_INFORMATION info;
|
||||
if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo, &info,
|
||||
sizeof(info)))
|
||||
{
|
||||
BOOL diskDevice = info.DeviceType == FILE_DEVICE_DISK ||
|
||||
info.DeviceType == FILE_DEVICE_VIRTUAL_DISK ||
|
||||
info.DeviceType == FILE_DEVICE_CD_ROM;
|
||||
BOOL result = _testInfo(info.FileAttributes, info.ReparseTag,
|
||||
diskDevice, testedType);
|
||||
if (!result || (testedType != PY_IFREG && testedType != PY_IFDIR) ||
|
||||
!(info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(
|
||||
GetLastError()))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
if (testedType != PY_IFREG && testedType != PY_IFDIR) {
|
||||
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
}
|
||||
HANDLE hfile = CreateFileW(path, FILE_READ_ATTRIBUTES, 0, NULL,
|
||||
OPEN_EXISTING, flags, NULL);
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
BOOL result = _testFileTypeByHandle(hfile, testedType, FALSE);
|
||||
CloseHandle(hfile);
|
||||
return result;
|
||||
}
|
||||
|
||||
switch (GetLastError()) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_CANT_ACCESS_FILE:
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
int rc;
|
||||
STRUCT_STAT st;
|
||||
if (testedType == PY_IFREG || testedType == PY_IFDIR) {
|
||||
rc = STAT(path, &st);
|
||||
}
|
||||
else {
|
||||
// PY_IFRRP is not generally supported in this case, except for
|
||||
// unhandled reparse points such as IO_REPARSE_TAG_APPEXECLINK.
|
||||
rc = LSTAT(path, &st);
|
||||
}
|
||||
if (!rc) {
|
||||
return _testInfo(st.st_file_attributes, st.st_reparse_tag,
|
||||
st.st_mode & S_IFREG, testedType);
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static BOOL
|
||||
_testFileExistsByName(LPCWSTR path, BOOL followLinks)
|
||||
{
|
||||
FILE_STAT_BASIC_INFORMATION info;
|
||||
if (_Py_GetFileInformationByName(path, FileStatBasicByNameInfo, &info,
|
||||
sizeof(info)))
|
||||
{
|
||||
if (!(info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) ||
|
||||
!followLinks && IsReparseTagNameSurrogate(info.ReparseTag))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if (_Py_GetFileInformationByName_ErrorIsTrustworthy(
|
||||
GetLastError()))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DWORD flags = FILE_FLAG_BACKUP_SEMANTICS;
|
||||
if (!followLinks) {
|
||||
flags |= FILE_FLAG_OPEN_REPARSE_POINT;
|
||||
}
|
||||
HANDLE hfile = CreateFileW(path, FILE_READ_ATTRIBUTES, 0, NULL,
|
||||
OPEN_EXISTING, flags, NULL);
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
if (followLinks) {
|
||||
CloseHandle(hfile);
|
||||
return TRUE;
|
||||
}
|
||||
// Regular Reparse Points (PY_IFRRP) have to be traversed.
|
||||
BOOL result = _testFileTypeByHandle(hfile, PY_IFRRP, FALSE);
|
||||
CloseHandle(hfile);
|
||||
if (!result) {
|
||||
return TRUE;
|
||||
}
|
||||
hfile = CreateFileW(path, FILE_READ_ATTRIBUTES, 0, NULL, OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
CloseHandle(hfile);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
switch (GetLastError()) {
|
||||
case ERROR_ACCESS_DENIED:
|
||||
case ERROR_SHARING_VIOLATION:
|
||||
case ERROR_CANT_ACCESS_FILE:
|
||||
case ERROR_INVALID_PARAMETER:
|
||||
STRUCT_STAT _st;
|
||||
return followLinks ? !STAT(path, &_st): !LSTAT(path, &_st);
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_testFileExists(path_t *_path, PyObject *path, BOOL followLinks)
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
if (!path_converter(path, _path)) {
|
||||
path_cleanup(_path);
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) {
|
||||
PyErr_Clear();
|
||||
return FALSE;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
if (_path->fd != -1) {
|
||||
HANDLE hfile = _Py_get_osfhandle_noraise(_path->fd);
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
if (GetFileType(hfile) != FILE_TYPE_UNKNOWN || !GetLastError()) {
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (_path->wide) {
|
||||
result = _testFileExistsByName(_path->wide, followLinks);
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
path_cleanup(_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
_testFileType(path_t *_path, PyObject *path, int testedType)
|
||||
{
|
||||
BOOL result = FALSE;
|
||||
if (!path_converter(path, _path)) {
|
||||
path_cleanup(_path);
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) {
|
||||
PyErr_Clear();
|
||||
return FALSE;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
if (_path->fd != -1) {
|
||||
HANDLE hfile = _Py_get_osfhandle_noraise(_path->fd);
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
result = _testFileTypeByHandle(hfile, testedType, TRUE);
|
||||
}
|
||||
}
|
||||
else if (_path->wide) {
|
||||
result = _testFileTypeByName(_path->wide, testedType);
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
path_cleanup(_path);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_exists -> bool
|
||||
|
||||
path: object
|
||||
/
|
||||
|
||||
Test whether a path exists. Returns False for broken symbolic links.
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static int
|
||||
os__path_exists_impl(PyObject *module, PyObject *path)
|
||||
/*[clinic end generated code: output=8f784b3abf9f8588 input=2777da15bc4ba5a3]*/
|
||||
{
|
||||
path_t _path = PATH_T_INITIALIZE("_path_exists", "path", 0, 1);
|
||||
return _testFileExists(&_path, path, TRUE);
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_lexists -> bool
|
||||
|
||||
path: object
|
||||
/
|
||||
|
||||
Test whether a path exists. Returns True for broken symbolic links.
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static int
|
||||
os__path_lexists_impl(PyObject *module, PyObject *path)
|
||||
/*[clinic end generated code: output=fec4a91cf4ffccf1 input=8843d4d6d4e7c779]*/
|
||||
{
|
||||
path_t _path = PATH_T_INITIALIZE("_path_lexists", "path", 0, 1);
|
||||
return _testFileExists(&_path, path, FALSE);
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_isdir -> bool
|
||||
|
||||
s as path: object
|
||||
|
||||
Return true if the pathname refers to an existing directory.
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
os__path_isdir_impl(PyObject *module, PyObject *s)
|
||||
/*[clinic end generated code: output=9d87ab3c8b8a4e61 input=c17f7ef21d22d64e]*/
|
||||
static int
|
||||
os__path_isdir_impl(PyObject *module, PyObject *path)
|
||||
/*[clinic end generated code: output=0504fd403f369701 input=2cb54dd97eb970f7]*/
|
||||
{
|
||||
HANDLE hfile;
|
||||
BOOL close_file = TRUE;
|
||||
FILE_BASIC_INFO info;
|
||||
path_t _path = PATH_T_INITIALIZE("isdir", "s", 0, 1);
|
||||
int result;
|
||||
BOOL slow_path = TRUE;
|
||||
FILE_STAT_BASIC_INFORMATION statInfo;
|
||||
|
||||
if (!path_converter(s, &_path)) {
|
||||
path_cleanup(&_path);
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) {
|
||||
PyErr_Clear();
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else {
|
||||
hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
}
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
if (GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
|
||||
sizeof(info)))
|
||||
{
|
||||
result = info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY;
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
path_cleanup(&_path);
|
||||
if (result) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
path_t _path = PATH_T_INITIALIZE("_path_isdir", "s", 0, 1);
|
||||
return _testFileType(&_path, path, PY_IFDIR);
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_isfile
|
||||
os._path_isfile -> bool
|
||||
|
||||
path: 'O'
|
||||
path: object
|
||||
|
||||
Test whether a path is a regular file
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
static int
|
||||
os__path_isfile_impl(PyObject *module, PyObject *path)
|
||||
/*[clinic end generated code: output=2394ed7c4b5cfd85 input=de22d74960ade365]*/
|
||||
/*[clinic end generated code: output=b40d620efe5a896f input=54b428a310debaea]*/
|
||||
{
|
||||
HANDLE hfile;
|
||||
BOOL close_file = TRUE;
|
||||
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);
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) {
|
||||
PyErr_Clear();
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
else {
|
||||
hfile = CreateFileW(_path.wide, FILE_READ_ATTRIBUTES, 0, NULL,
|
||||
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||
}
|
||||
if (hfile != INVALID_HANDLE_VALUE) {
|
||||
if (GetFileInformationByHandleEx(hfile, FileBasicInfo, &info,
|
||||
sizeof(info)))
|
||||
{
|
||||
result = !(info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
path_cleanup(&_path);
|
||||
if (result) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
path_t _path = PATH_T_INITIALIZE("_path_isfile", "path", 0, 1);
|
||||
return _testFileType(&_path, path, PY_IFREG);
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_exists
|
||||
os._path_islink -> bool
|
||||
|
||||
path: 'O'
|
||||
|
||||
Test whether a path exists. Returns False for broken symbolic links
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
os__path_exists_impl(PyObject *module, PyObject *path)
|
||||
/*[clinic end generated code: output=f508c3b35e13a249 input=380f77cdfa0f7ae8]*/
|
||||
{
|
||||
HANDLE hfile;
|
||||
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);
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) {
|
||||
PyErr_Clear();
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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 {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
path_cleanup(&_path);
|
||||
if (result) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_islink
|
||||
|
||||
path: 'O'
|
||||
path: object
|
||||
|
||||
Test whether a path is a symbolic link
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
static int
|
||||
os__path_islink_impl(PyObject *module, PyObject *path)
|
||||
/*[clinic end generated code: output=6d8640b1a390c054 input=38a3cb937ccf59bf]*/
|
||||
/*[clinic end generated code: output=9d0cf8e4c640dfe6 input=b71fed60b9b2cd73]*/
|
||||
{
|
||||
HANDLE hfile;
|
||||
BOOL close_file = TRUE;
|
||||
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);
|
||||
if (PyErr_ExceptionMatches(PyExc_ValueError)) {
|
||||
PyErr_Clear();
|
||||
Py_RETURN_FALSE;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
path_cleanup(&_path);
|
||||
if (result) {
|
||||
Py_RETURN_TRUE;
|
||||
}
|
||||
Py_RETURN_FALSE;
|
||||
path_t _path = PATH_T_INITIALIZE("_path_islink", "path", 0, 1);
|
||||
return _testFileType(&_path, path, PY_IFLNK);
|
||||
}
|
||||
|
||||
|
||||
/*[clinic input]
|
||||
os._path_isjunction -> bool
|
||||
|
||||
path: object
|
||||
|
||||
Test whether a path is a junction
|
||||
|
||||
[clinic start generated code]*/
|
||||
|
||||
static int
|
||||
os__path_isjunction_impl(PyObject *module, PyObject *path)
|
||||
/*[clinic end generated code: output=f1d51682a077654d input=103ccedcdb714f11]*/
|
||||
{
|
||||
path_t _path = PATH_T_INITIALIZE("_path_isjunction", "path", 0, 1);
|
||||
return _testFileType(&_path, path, PY_IFMNT);
|
||||
}
|
||||
|
||||
#undef PY_IFREG
|
||||
#undef PY_IFDIR
|
||||
#undef PY_IFLNK
|
||||
#undef PY_IFMNT
|
||||
#undef PY_IFLRP
|
||||
#undef PY_IFRRP
|
||||
|
||||
#endif /* MS_WINDOWS */
|
||||
|
||||
|
||||
|
@ -16921,7 +16900,9 @@ static PyMethodDef posix_methods[] = {
|
|||
OS__PATH_ISDIR_METHODDEF
|
||||
OS__PATH_ISFILE_METHODDEF
|
||||
OS__PATH_ISLINK_METHODDEF
|
||||
OS__PATH_ISJUNCTION_METHODDEF
|
||||
OS__PATH_EXISTS_METHODDEF
|
||||
OS__PATH_LEXISTS_METHODDEF
|
||||
|
||||
OS__SUPPORTS_VIRTUAL_TERMINAL_METHODDEF
|
||||
{NULL, NULL} /* Sentinel */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue