4040#include "pycore_pystate.h" /* _PyRuntime */
4141#include "pythread.h"
4242#include "structmember.h"
43+
44+ #ifdef MS_WINDOWS
45+ # include <aclapi.h> // SetEntriesInAcl
46+ # include <sddl.h> // SDDL_REVISION_1
47+ #endif
48+
4349#ifndef MS_WINDOWS
4450# include "posixmodule.h"
4551#else
@@ -4122,7 +4128,6 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
41224128
41234129#endif /* MS_WINDOWS */
41244130
4125-
41264131/*[clinic input]
41274132os.mkdir
41284133
@@ -4151,6 +4156,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
41514156/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
41524157{
41534158 int result ;
4159+ #ifdef MS_WINDOWS
4160+ int error = 0 ;
4161+ int pathError = 0 ;
4162+ SECURITY_ATTRIBUTES secAttr = { sizeof (secAttr ) };
4163+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
4164+ #endif
41544165
41554166 if (PySys_Audit ("os.mkdir" , "Oii" , path -> object , mode ,
41564167 dir_fd == DEFAULT_DIR_FD ? -1 : dir_fd ) < 0 ) {
@@ -4159,11 +4170,38 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
41594170
41604171#ifdef MS_WINDOWS
41614172 Py_BEGIN_ALLOW_THREADS
4162- result = CreateDirectoryW (path -> wide , NULL );
4173+ if (mode == 0700 /* 0o700 */ ) {
4174+ ULONG sdSize ;
4175+ pSecAttr = & secAttr ;
4176+ // Set a discretionary ACL (D) that is protected (P) and includes
4177+ // inheritable (OICI) entries that allow (A) full control (FA) to
4178+ // SYSTEM (SY), Administrators (BA), and the owner (OW).
4179+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorW (
4180+ L"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)" ,
4181+ SDDL_REVISION_1 ,
4182+ & secAttr .lpSecurityDescriptor ,
4183+ & sdSize
4184+ )) {
4185+ error = GetLastError ();
4186+ }
4187+ }
4188+ if (!error ) {
4189+ result = CreateDirectoryW (path -> wide , pSecAttr );
4190+ if (secAttr .lpSecurityDescriptor &&
4191+ // uncommonly, LocalFree returns non-zero on error, but still uses
4192+ // GetLastError() to see what the error code is
4193+ LocalFree (secAttr .lpSecurityDescriptor )) {
4194+ error = GetLastError ();
4195+ }
4196+ }
41634197 Py_END_ALLOW_THREADS
41644198
4165- if (!result )
4199+ if (error ) {
4200+ return PyErr_SetFromWindowsErr (error );
4201+ }
4202+ if (!result ) {
41664203 return path_error (path );
4204+ }
41674205#else
41684206 Py_BEGIN_ALLOW_THREADS
41694207#if HAVE_MKDIRAT
0 commit comments