2424#include "pycore_ceval.h" // _PyEval_ReInitThreads()
2525#include "pycore_import.h" // _PyImport_ReInitLock()
2626#include "pycore_pystate.h" // _PyInterpreterState_GET()
27+
28+ #ifdef MS_WINDOWS
29+ # include <aclapi.h> // SetEntriesInAcl
30+ # include <sddl.h> // SDDL_REVISION_1
31+ #endif
32+
2733#include "structmember.h" // PyMemberDef
2834#ifndef MS_WINDOWS
2935# include "posixmodule.h"
@@ -4425,7 +4431,6 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
44254431
44264432#endif /* MS_WINDOWS */
44274433
4428-
44294434/*[clinic input]
44304435os.mkdir
44314436
@@ -4454,6 +4459,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
44544459/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
44554460{
44564461 int result ;
4462+ #ifdef MS_WINDOWS
4463+ int error = 0 ;
4464+ int pathError = 0 ;
4465+ SECURITY_ATTRIBUTES secAttr = { sizeof (secAttr ) };
4466+ SECURITY_ATTRIBUTES * pSecAttr = NULL ;
4467+ #endif
44574468#ifdef HAVE_MKDIRAT
44584469 int mkdirat_unavailable = 0 ;
44594470#endif
@@ -4465,11 +4476,38 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
44654476
44664477#ifdef MS_WINDOWS
44674478 Py_BEGIN_ALLOW_THREADS
4468- result = CreateDirectoryW (path -> wide , NULL );
4479+ if (mode == 0700 /* 0o700 */ ) {
4480+ ULONG sdSize ;
4481+ pSecAttr = & secAttr ;
4482+ // Set a discretionary ACL (D) that is protected (P) and includes
4483+ // inheritable (OICI) entries that allow (A) full control (FA) to
4484+ // SYSTEM (SY), Administrators (BA), and the owner (OW).
4485+ if (!ConvertStringSecurityDescriptorToSecurityDescriptorW (
4486+ L"D:P(A;OICI;FA;;;SY)(A;OICI;FA;;;BA)(A;OICI;FA;;;OW)" ,
4487+ SDDL_REVISION_1 ,
4488+ & secAttr .lpSecurityDescriptor ,
4489+ & sdSize
4490+ )) {
4491+ error = GetLastError ();
4492+ }
4493+ }
4494+ if (!error ) {
4495+ result = CreateDirectoryW (path -> wide , pSecAttr );
4496+ if (secAttr .lpSecurityDescriptor &&
4497+ // uncommonly, LocalFree returns non-zero on error, but still uses
4498+ // GetLastError() to see what the error code is
4499+ LocalFree (secAttr .lpSecurityDescriptor )) {
4500+ error = GetLastError ();
4501+ }
4502+ }
44694503 Py_END_ALLOW_THREADS
44704504
4471- if (!result )
4505+ if (error ) {
4506+ return PyErr_SetFromWindowsErr (error );
4507+ }
4508+ if (!result ) {
44724509 return path_error (path );
4510+ }
44734511#else
44744512 Py_BEGIN_ALLOW_THREADS
44754513#if HAVE_MKDIRAT
0 commit comments