40
40
#include "pycore_pystate.h" /* _PyRuntime */
41
41
#include "pythread.h"
42
42
#include "structmember.h"
43
+
44
+ #ifdef MS_WINDOWS
45
+ # include <aclapi.h> // SetEntriesInAcl
46
+ # include <sddl.h> // SDDL_REVISION_1
47
+ #endif
48
+
43
49
#ifndef MS_WINDOWS
44
50
# include "posixmodule.h"
45
51
#else
@@ -4122,7 +4128,6 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
4122
4128
4123
4129
#endif /* MS_WINDOWS */
4124
4130
4125
-
4126
4131
/*[clinic input]
4127
4132
os.mkdir
4128
4133
@@ -4151,6 +4156,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4151
4156
/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
4152
4157
{
4153
4158
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
4154
4165
4155
4166
if (PySys_Audit ("os.mkdir" , "Oii" , path -> object , mode ,
4156
4167
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)
4159
4170
4160
4171
#ifdef MS_WINDOWS
4161
4172
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
+ }
4163
4197
Py_END_ALLOW_THREADS
4164
4198
4165
- if (!result )
4199
+ if (error ) {
4200
+ return PyErr_SetFromWindowsErr (error );
4201
+ }
4202
+ if (!result ) {
4166
4203
return path_error (path );
4204
+ }
4167
4205
#else
4168
4206
Py_BEGIN_ALLOW_THREADS
4169
4207
#if HAVE_MKDIRAT
0 commit comments