[3.9] gh-118486: Support mkdir(mode=0o700) on Windows (GH-118488) (GH-118741)

Co-authored-by: Łukasz Langa <lukasz@langa.pl>
This commit is contained in:
Steve Dower 2024-05-24 18:27:01 +01:00 committed by GitHub
parent b228655c22
commit 5130731c9e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 107 additions and 3 deletions

View file

@ -24,6 +24,12 @@
#include "pycore_ceval.h" // _PyEval_ReInitThreads()
#include "pycore_import.h" // _PyImport_ReInitLock()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#ifdef MS_WINDOWS
# include <aclapi.h> // SetEntriesInAcl
# include <sddl.h> // SDDL_REVISION_1
#endif
#include "structmember.h" // PyMemberDef
#ifndef MS_WINDOWS
# include "posixmodule.h"
@ -4425,7 +4431,6 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
#endif /* MS_WINDOWS */
/*[clinic input]
os.mkdir
@ -4454,6 +4459,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
{
int result;
#ifdef MS_WINDOWS
int error = 0;
int pathError = 0;
SECURITY_ATTRIBUTES secAttr = { sizeof(secAttr) };
SECURITY_ATTRIBUTES *pSecAttr = NULL;
#endif
#ifdef HAVE_MKDIRAT
int mkdirat_unavailable = 0;
#endif
@ -4465,11 +4476,38 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
#ifdef MS_WINDOWS
Py_BEGIN_ALLOW_THREADS
result = CreateDirectoryW(path->wide, NULL);
if (mode == 0700 /* 0o700 */) {
ULONG sdSize;
pSecAttr = &secAttr;
// Set a discretionary ACL (D) that is protected (P) and includes
// inheritable (OICI) entries that allow (A) full control (FA) to
// SYSTEM (SY), Administrators (BA), and the owner (OW).
if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(
L"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)",
SDDL_REVISION_1,
&secAttr.lpSecurityDescriptor,
&sdSize
)) {
error = GetLastError();
}
}
if (!error) {
result = CreateDirectoryW(path->wide, pSecAttr);
if (secAttr.lpSecurityDescriptor &&
// uncommonly, LocalFree returns non-zero on error, but still uses
// GetLastError() to see what the error code is
LocalFree(secAttr.lpSecurityDescriptor)) {
error = GetLastError();
}
}
Py_END_ALLOW_THREADS
if (!result)
if (error) {
return PyErr_SetFromWindowsErr(error);
}
if (!result) {
return path_error(path);
}
#else
Py_BEGIN_ALLOW_THREADS
#if HAVE_MKDIRAT