@@ -284,10 +284,7 @@ extern char *ctermid_r(char *);
284
284
#include <windows.h>
285
285
#include <shellapi.h> /* for ShellExecute() */
286
286
#include <lmcons.h> /* for UNLEN */
287
- #ifdef SE_CREATE_SYMBOLIC_LINK_NAME /* Available starting with Vista */
288
287
#define HAVE_SYMLINK
289
- static int win32_can_symlink = 0 ;
290
- #endif
291
288
#endif /* _MSC_VER */
292
289
293
290
#ifndef MAXPATHLEN
@@ -7755,26 +7752,6 @@ os_readlink_impl(PyObject *module, path_t *path, int dir_fd)
7755
7752
7756
7753
#if defined(MS_WINDOWS )
7757
7754
7758
- /* Grab CreateSymbolicLinkW dynamically from kernel32 */
7759
- static BOOLEAN (CALLBACK * Py_CreateSymbolicLinkW )(LPCWSTR , LPCWSTR , DWORD ) = NULL ;
7760
-
7761
- static int
7762
- check_CreateSymbolicLink (void )
7763
- {
7764
- HINSTANCE hKernel32 ;
7765
- /* only recheck */
7766
- if (Py_CreateSymbolicLinkW )
7767
- return 1 ;
7768
-
7769
- Py_BEGIN_ALLOW_THREADS
7770
- hKernel32 = GetModuleHandleW (L"KERNEL32" );
7771
- * (FARPROC * )& Py_CreateSymbolicLinkW = GetProcAddress (hKernel32 ,
7772
- "CreateSymbolicLinkW" );
7773
- Py_END_ALLOW_THREADS
7774
-
7775
- return Py_CreateSymbolicLinkW != NULL ;
7776
- }
7777
-
7778
7755
/* Remove the last portion of the path - return 0 on success */
7779
7756
static int
7780
7757
_dirnameW (WCHAR * path )
@@ -7878,33 +7855,57 @@ os_symlink_impl(PyObject *module, path_t *src, path_t *dst,
7878
7855
{
7879
7856
#ifdef MS_WINDOWS
7880
7857
DWORD result ;
7858
+ DWORD flags = 0 ;
7859
+
7860
+ /* Assumed true, set to false if detected to not be available. */
7861
+ static int windows_has_symlink_unprivileged_flag = TRUE;
7881
7862
#else
7882
7863
int result ;
7883
7864
#endif
7884
7865
7885
7866
#ifdef MS_WINDOWS
7886
- if (!check_CreateSymbolicLink ()) {
7887
- PyErr_SetString (PyExc_NotImplementedError ,
7888
- "CreateSymbolicLink functions not found" );
7889
- return NULL ;
7890
- }
7891
- if (!win32_can_symlink ) {
7892
- PyErr_SetString (PyExc_OSError , "symbolic link privilege not held" );
7893
- return NULL ;
7894
- }
7895
- #endif
7896
7867
7897
- #ifdef MS_WINDOWS
7868
+ if (windows_has_symlink_unprivileged_flag ) {
7869
+ /* Allow non-admin symlinks if system allows it. */
7870
+ flags |= SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE ;
7871
+ }
7898
7872
7899
7873
Py_BEGIN_ALLOW_THREADS
7900
7874
_Py_BEGIN_SUPPRESS_IPH
7901
- /* if src is a directory, ensure target_is_directory==1 */
7902
- target_is_directory |= _check_dirW (src -> wide , dst -> wide );
7903
- result = Py_CreateSymbolicLinkW (dst -> wide , src -> wide ,
7904
- target_is_directory );
7875
+ /* if src is a directory, ensure flags==1 (target_is_directory bit) */
7876
+ if (target_is_directory || _check_dirW (src -> wide , dst -> wide )) {
7877
+ flags |= SYMBOLIC_LINK_FLAG_DIRECTORY ;
7878
+ }
7879
+
7880
+ result = CreateSymbolicLinkW (dst -> wide , src -> wide , flags );
7905
7881
_Py_END_SUPPRESS_IPH
7906
7882
Py_END_ALLOW_THREADS
7907
7883
7884
+ if (windows_has_symlink_unprivileged_flag && !result &&
7885
+ ERROR_INVALID_PARAMETER == GetLastError ()) {
7886
+
7887
+ Py_BEGIN_ALLOW_THREADS
7888
+ _Py_BEGIN_SUPPRESS_IPH
7889
+ /* This error might be caused by
7890
+ SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE not being supported.
7891
+ Try again, and update windows_has_symlink_unprivileged_flag if we
7892
+ are successful this time.
7893
+
7894
+ NOTE: There is a risk of a race condition here if there are other
7895
+ conditions than the flag causing ERROR_INVALID_PARAMETER, and
7896
+ another process (or thread) changes that condition in between our
7897
+ calls to CreateSymbolicLink.
7898
+ */
7899
+ flags &= ~(SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE );
7900
+ result = CreateSymbolicLinkW (dst -> wide , src -> wide , flags );
7901
+ _Py_END_SUPPRESS_IPH
7902
+ Py_END_ALLOW_THREADS
7903
+
7904
+ if (result || ERROR_INVALID_PARAMETER != GetLastError ()) {
7905
+ windows_has_symlink_unprivileged_flag = FALSE;
7906
+ }
7907
+ }
7908
+
7908
7909
if (!result )
7909
7910
return path_error2 (src , dst );
7910
7911
@@ -13469,35 +13470,6 @@ static PyMethodDef posix_methods[] = {
13469
13470
{NULL , NULL } /* Sentinel */
13470
13471
};
13471
13472
13472
-
13473
- #if defined(HAVE_SYMLINK ) && defined(MS_WINDOWS )
13474
- static int
13475
- enable_symlink ()
13476
- {
13477
- HANDLE tok ;
13478
- TOKEN_PRIVILEGES tok_priv ;
13479
- LUID luid ;
13480
-
13481
- if (!OpenProcessToken (GetCurrentProcess (), TOKEN_ALL_ACCESS , & tok ))
13482
- return 0 ;
13483
-
13484
- if (!LookupPrivilegeValue (NULL , SE_CREATE_SYMBOLIC_LINK_NAME , & luid ))
13485
- return 0 ;
13486
-
13487
- tok_priv .PrivilegeCount = 1 ;
13488
- tok_priv .Privileges [0 ].Luid = luid ;
13489
- tok_priv .Privileges [0 ].Attributes = SE_PRIVILEGE_ENABLED ;
13490
-
13491
- if (!AdjustTokenPrivileges (tok , FALSE, & tok_priv ,
13492
- sizeof (TOKEN_PRIVILEGES ),
13493
- (PTOKEN_PRIVILEGES ) NULL , (PDWORD ) NULL ))
13494
- return 0 ;
13495
-
13496
- /* ERROR_NOT_ALL_ASSIGNED returned when the privilege can't be assigned. */
13497
- return GetLastError () == ERROR_NOT_ALL_ASSIGNED ? 0 : 1 ;
13498
- }
13499
- #endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */
13500
-
13501
13473
static int
13502
13474
all_ins (PyObject * m )
13503
13475
{
@@ -14105,10 +14077,6 @@ INITFUNC(void)
14105
14077
PyObject * list ;
14106
14078
const char * const * trace ;
14107
14079
14108
- #if defined(HAVE_SYMLINK ) && defined(MS_WINDOWS )
14109
- win32_can_symlink = enable_symlink ();
14110
- #endif
14111
-
14112
14080
m = PyModule_Create (& posixmodule );
14113
14081
if (m == NULL )
14114
14082
return NULL ;
0 commit comments