3333#include "pycore_import.h" // _PyImport_ReInitLock()
3434#include "pycore_initconfig.h" // _PyStatus_EXCEPTION()
3535#include "pycore_pystate.h" // _PyInterpreterState_GET()
36+
37+ #ifdef MS_WINDOWS
38+ # include <aclapi.h> // SetEntriesInAcl
39+ # include <sddl.h> // SDDL_REVISION_1
40+ #endif
41+
3642#include "structmember.h" // PyMemberDef
3743#ifndef MS_WINDOWS
3844# include "posixmodule.h"
@@ -4465,7 +4471,6 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
44654471
44664472#endif /* MS_WINDOWS */
44674473
4468-
44694474/*[clinic input]
44704475os.mkdir
44714476
@@ -4495,6 +4500,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
44954500/*[clinic end generated code: output=a70446903abe821f input=a61722e1576fab03]*/
44964501{
44974502 int result ;
4503+ #ifdef MS_WINDOWS
4504+ int error = 0 ;
4505+ int pathError = 0 ;
4506+ SECURITY_ATTRIBUTES secAttr = { sizeof (secAttr ) };
4507+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
4508+ #endif
44984509#ifdef HAVE_MKDIRAT
44994510 int mkdirat_unavailable = 0 ;
45004511#endif
@@ -4506,11 +4517,38 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
45064517
45074518#ifdef MS_WINDOWS
45084519 Py_BEGIN_ALLOW_THREADS
4509- result = CreateDirectoryW (path -> wide , NULL );
4520+ if (mode == 0700 /* 0o700 */ ) {
4521+ ULONG sdSize ;
4522+ pSecAttr = & secAttr ;
4523+ // Set a discretionary ACL (D) that is protected (P) and includes
4524+ // inheritable (OICI) entries that allow (A) full control (FA) to
4525+ // SYSTEM (SY), Administrators (BA), and the owner (OW).
4526+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorW (
4527+ L"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)" ,
4528+ SDDL_REVISION_1 ,
4529+ & secAttr .lpSecurityDescriptor ,
4530+ & sdSize
4531+ )) {
4532+ error = GetLastError ();
4533+ }
4534+ }
4535+ if (!error ) {
4536+ result = CreateDirectoryW (path -> wide , pSecAttr );
4537+ if (secAttr .lpSecurityDescriptor &&
4538+ // uncommonly, LocalFree returns non-zero on error, but still uses
4539+ // GetLastError() to see what the error code is
4540+ LocalFree (secAttr .lpSecurityDescriptor )) {
4541+ error = GetLastError ();
4542+ }
4543+ }
45104544 Py_END_ALLOW_THREADS
45114545
4512- if (!result )
4546+ if (error ) {
4547+ return PyErr_SetFromWindowsErr (error );
4548+ }
4549+ if (!result ) {
45134550 return path_error (path );
4551+ }
45144552#else
45154553 Py_BEGIN_ALLOW_THREADS
45164554#if HAVE_MKDIRAT
0 commit comments