Message411804
Here's an implementation of _Py_CreateFile2() and win32_xstat_impl():
typedef struct {
DWORD type;
DWORD attributes;
DWORD reparseTag;
} _PY_CREATE_FILE_INFO;
static HANDLE
_Py_CreateFile2(LPCWSTR lpFileName,
DWORD dwDesiredAccess,
DWORD dwShareMode,
DWORD dwCreationDisposition,
LPCREATEFILE2_EXTENDED_PARAMETERS pCreateExParams,
BOOL traverse,
_PY_CREATE_FILE_INFO *pCreateInfo)
{
HANDLE hFile;
DWORD error;
FILE_BASIC_INFO fbi;
FILE_ATTRIBUTE_TAG_INFO fati;
BOOL openReparsePoint = FALSE;
BOOL traverseFailed = FALSE;
_PY_CREATE_FILE_INFO cfi = {0};
CREATEFILE2_EXTENDED_PARAMETERS createExParams = {
sizeof(CREATEFILE2_EXTENDED_PARAMETERS)};
if (!pCreateExParams) {
pCreateExParams = &createExParams;
}
pCreateExParams->dwFileFlags |= FILE_FLAG_BACKUP_SEMANTICS;
if (pCreateExParams->dwFileFlags & FILE_FLAG_OPEN_REPARSE_POINT) {
openReparsePoint = TRUE;
} else if (!traverse) {
pCreateExParams->dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
}
// Share read access if write access isn't requested because
// CreateFile2 uses the NT I/O flag FILE_DISALLOW_EXCLUSIVE.
if (!(dwDesiredAccess & (GENERIC_ALL | GENERIC_WRITE |
FILE_WRITE_DATA | FILE_APPEND_DATA))) {
dwShareMode |= FILE_SHARE_READ;
}
call_createfile:
hFile = CreateFile2(lpFileName, dwDesiredAccess, dwShareMode,
dwCreationDisposition, pCreateExParams);
error = GetLastError(); // success: 0 or ERROR_ALREADY_EXISTS
if (hFile == INVALID_HANDLE_VALUE) {
// bpo-37834: open an unhandled reparse point if traverse fails.
traverseFailed = (error == ERROR_CANT_ACCESS_FILE);
if (openReparsePoint || !(traverse && traverseFailed)) {
return INVALID_HANDLE_VALUE;
}
pCreateExParams->dwFileFlags |= FILE_FLAG_OPEN_REPARSE_POINT;
hFile = CreateFile2(lpFileName, dwDesiredAccess, dwShareMode,
dwCreationDisposition, pCreateExParams);
if (hFile == INVALID_HANDLE_VALUE) {
SetLastError(error);
return INVALID_HANDLE_VALUE;
}
error = GetLastError(); // 0 or ERROR_ALREADY_EXISTS
}
if (!pCreateInfo && (openReparsePoint || (traverse && !traverseFailed)))
{
return hFile;
}
cfi.type = GetFileType(hFile);
if (cfi.type == FILE_TYPE_UNKNOWN && GetLastError() != 0) {
error = GetLastError();
goto cleanup;
}
if (GetFileInformationByHandleEx(
hFile, FileAttributeTagInfo, &fati, sizeof(fati))) {
cfi.attributes = fati.FileAttributes;
cfi.reparseTag = fati.ReparseTag;
} else if (GetFileInformationByHandleEx(
hFile, FileBasicInfo, &fbi, sizeof(fbi))) {
cfi.attributes = fbi.FileAttributes;
} else {
switch (GetLastError()) {
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_FUNCTION:
case ERROR_NOT_SUPPORTED:
// The file is not in a filesystem.
break;
default:
error = GetLastError();
}
goto cleanup;
}
if (cfi.attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
if (IsReparseTagNameSurrogate(cfi.reparseTag)) {
if (traverseFailed) {
error = ERROR_CANT_ACCESS_FILE;
goto cleanup;
}
} else if (!openReparsePoint && !traverseFailed) {
// Always try to reparse if it's not a name surrogate.
CloseHandle(hFile);
traverse = TRUE;
pCreateExParams->dwFileFlags &= ~FILE_FLAG_OPEN_REPARSE_POINT;
goto call_createfile;
}
}
cleanup:
if (error && error != ERROR_ALREADY_EXISTS) {
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
} else if (pCreateInfo) {
*pCreateInfo = cfi;
}
SetLastError(error);
return hFile;
}
static int
win32_xstat_impl(const wchar_t *path, struct _Py_stat_struct *result,
BOOL traverse)
{
DWORD error;
BY_HANDLE_FILE_INFORMATION fileInfo;
_PY_CREATE_FILE_INFO cfi;
int retval = 0;
HANDLE hFile = _Py_CreateFile2(path, FILE_READ_ATTRIBUTES, 0,
OPEN_EXISTING, NULL, traverse, &cfi);
if (hFile == INVALID_HANDLE_VALUE) {
// Either the path doesn't exist, or the caller lacks access.
error = GetLastError();
switch (error) {
case ERROR_INVALID_PARAMETER:
// The "con" DOS device requires read or write access.
hFile = _Py_CreateFile2(path, GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_WRITE | FILE_SHARE_DELETE, OPEN_EXISTING,
NULL, traverse, &cfi);
if (hFile == INVALID_HANDLE_VALUE) {
SetLastError(error);
return -1;
}
break;
case ERROR_ACCESS_DENIED: // Cannot sync or read attributes.
case ERROR_SHARING_VIOLATION: // It's a paging file.
// Try reading the parent directory.
if (!attributes_from_dir(path, &fileInfo, &cfi.reparseTag)) {
// Cannot read the parent directory.
SetLastError(error);
return -1;
}
if (fileInfo.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
if (traverse || !IsReparseTagNameSurrogate(cfi.reparseTag)) {
// Can't traverse, so fail.
SetLastError(error);
return -1;
}
}
break;
default:
return -1;
}
}
if (hFile != INVALID_HANDLE_VALUE) {
if (cfi.type != FILE_TYPE_DISK) {
memset(result, 0, sizeof(*result));
if (cfi.attributes != INVALID_FILE_ATTRIBUTES &&
cfi.attributes & FILE_ATTRIBUTE_DIRECTORY) {
// e.g. "//./pipe/" or "//./mailslot/"
result->st_mode = _S_IFDIR;
} else if (cfi.type == FILE_TYPE_CHAR) {
// e.g. "//./nul"
result->st_mode = _S_IFCHR;
} else if (cfi.type == FILE_TYPE_PIPE) {
// e.g. "//./pipe/spam"
result->st_mode = _S_IFIFO;
}
// FILE_TYPE_UNKNOWN
// e.g. "//./mailslot/waitfor.exe/spam"
goto cleanup;
}
if (!GetFileInformationByHandle(hFile, &fileInfo)) {
switch (GetLastError()) {
case ERROR_INVALID_PARAMETER:
case ERROR_INVALID_FUNCTION:
case ERROR_NOT_SUPPORTED:
// Volumes and physical disks are block devices,
// e.g. "//./C:" or "//./PhysicalDrive0"
memset(result, 0, sizeof(*result));
result->st_mode = 0x6000; // S_IFBLK
goto cleanup;
}
retval = -1;
goto cleanup;
}
}
_Py_attribute_data_to_stat(&fileInfo, cfi.reparseTag, result);
if (!(fileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
// Set S_IEXEC if the filename has an extension that is
// commonly used by files that CreateProcessW can execute.
// A real implementation would call GetSecurityInfo,
// OpenThreadToken / OpenProcessToken, and AccessCheck to
// check for read, write, and execute access.
const wchar_t *fileExtension = wcsrchr(path, '.');
if (fileExtension) {
if (_wcsicmp(fileExtension, L".com") == 0 ||
_wcsicmp(fileExtension, L".exe") == 0 ||
_wcsicmp(fileExtension, L".bat") == 0 ||
_wcsicmp(fileExtension, L".cmd") == 0)
{
result->st_mode |= 0111;
}
}
}
cleanup:
if (hFile != INVALID_HANDLE_VALUE) {
// Preserve the last error when failing.
error = retval ? GetLastError() : 0;
if (CloseHandle(hFile)) {
SetLastError(error);
} else {
retval = -1;
}
}
return retval;
} |
|
Date |
User |
Action |
Args |
2022-01-26 23:15:08 | eryksun | set | recipients:
+ eryksun, paul.moore, tim.golden, zach.ware, steve.dower |
2022-01-26 23:15:08 | eryksun | set | messageid: <1643238908.3.0.343560469617.issue46506@roundup.psfhosted.org> |
2022-01-26 23:15:08 | eryksun | link | issue46506 messages |
2022-01-26 23:15:08 | eryksun | create | |
|