24
24
#include "pycore_ceval.h" // _PyEval_ReInitThreads()
25
25
#include "pycore_import.h" // _PyImport_ReInitLock()
26
26
#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
+
27
33
#include "structmember.h" // PyMemberDef
28
34
#ifndef MS_WINDOWS
29
35
# include "posixmodule.h"
@@ -4425,7 +4431,6 @@ os__path_splitroot_impl(PyObject *module, path_t *path)
4425
4431
4426
4432
#endif /* MS_WINDOWS */
4427
4433
4428
-
4429
4434
/*[clinic input]
4430
4435
os.mkdir
4431
4436
@@ -4454,6 +4459,12 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4454
4459
/*[clinic end generated code: output=a70446903abe821f input=e965f68377e9b1ce]*/
4455
4460
{
4456
4461
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
4457
4468
#ifdef HAVE_MKDIRAT
4458
4469
int mkdirat_unavailable = 0 ;
4459
4470
#endif
@@ -4465,11 +4476,38 @@ os_mkdir_impl(PyObject *module, path_t *path, int mode, int dir_fd)
4465
4476
4466
4477
#ifdef MS_WINDOWS
4467
4478
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
+ }
4469
4503
Py_END_ALLOW_THREADS
4470
4504
4471
- if (!result )
4505
+ if (error ) {
4506
+ return PyErr_SetFromWindowsErr (error );
4507
+ }
4508
+ if (!result ) {
4472
4509
return path_error (path );
4510
+ }
4473
4511
#else
4474
4512
Py_BEGIN_ALLOW_THREADS
4475
4513
#if HAVE_MKDIRAT
0 commit comments