这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion conda/cli/main_init.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,5 @@ def execute(args, parser):
for_user = False

anaconda_prompt = on_win and args.anaconda_prompt
anaconda_prompt = on_win # TODO: probably remove and leave --anaconda-prompt as a flag
Copy link
Contributor

@kalefranz kalefranz Jul 3, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must have put that in just for debug or something 😳

return initialize(context.conda_prefix, selected_shells, for_user, args.system,
anaconda_prompt)
172 changes: 156 additions & 16 deletions conda/common/os/windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,178 @@
# SPDX-License-Identifier: BSD-3-Clause
from __future__ import absolute_import, division, print_function, unicode_literals

from ctypes import c_ulong, c_char_p, c_int, c_void_p
from enum import IntEnum
from logging import getLogger
import ctypes as ctypes

from ..compat import on_win
from ..compat import ensure_binary, on_win, string_types

log = getLogger(__name__)

_ctypes = None
if on_win:
import ctypes as _ctypes
from ctypes.wintypes import HANDLE, BOOL, DWORD, HWND, HINSTANCE, HKEY
PHANDLE = ctypes.POINTER(HANDLE)
PDWORD = ctypes.POINTER(DWORD)
SEE_MASK_NOCLOSEPROCESS = 0x00000040
INFINITE = -1

WaitForSingleObject = ctypes.windll.kernel32.WaitForSingleObject
WaitForSingleObject.argtypes = (HANDLE, DWORD)
WaitForSingleObject.restype = DWORD

log = getLogger(__name__)
CloseHandle = ctypes.windll.kernel32.CloseHandle
CloseHandle.argtypes = (HANDLE, )
CloseHandle.restype = BOOL

class ShellExecuteInfo(ctypes.Structure):
"""
https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/nf-shellapi-shellexecuteexa
https://docs.microsoft.com/en-us/windows/desktop/api/shellapi/ns-shellapi-_shellexecuteinfoa
"""

_fields_ = [
('cbSize', DWORD),
('fMask', c_ulong),
('hwnd', HWND),
('lpVerb', c_char_p),
('lpFile', c_char_p),
('lpParameters', c_char_p),
('lpDirectory', c_char_p),
('nShow', c_int),
('hInstApp', HINSTANCE),
('lpIDList', c_void_p),
('lpClass', c_char_p),
('hKeyClass', HKEY),
('dwHotKey', DWORD),
('hIcon', HANDLE),
('hProcess', HANDLE)
]

def __init__(self, **kwargs):
ctypes.Structure.__init__(self)
self.cbSize = ctypes.sizeof(self)
for field_name, field_value in kwargs.items():
if isinstance(field_value, string_types):
field_value = ensure_binary(field_value)
setattr(self, field_name, field_value)

PShellExecuteInfo = ctypes.POINTER(ShellExecuteInfo)
ShellExecuteEx = ctypes.windll.Shell32.ShellExecuteExA
ShellExecuteEx.argtypes = (PShellExecuteInfo, )
ShellExecuteEx.restype = BOOL


class SW(IntEnum):
HIDE = 0
MAXIMIZE = 3
MINIMIZE = 6
RESTORE = 9
SHOW = 5
SHOWDEFAULT = 10
SHOWMAXIMIZED = 3
SHOWMINIMIZED = 2
SHOWMINNOACTIVE = 7
SHOWNA = 8
SHOWNOACTIVATE = 4
SHOWNORMAL = 1


class ERROR(IntEnum):
ZERO = 0
FILE_NOT_FOUND = 2
PATH_NOT_FOUND = 3
BAD_FORMAT = 11
ACCESS_DENIED = 5
ASSOC_INCOMPLETE = 27
DDE_BUSY = 30
DDE_FAIL = 29
DDE_TIMEOUT = 28
DLL_NOT_FOUND = 32
NO_ASSOC = 31
OOM = 8
SHARE = 26


def get_free_space_on_windows(dir_name):
result = None
if _ctypes:
free_bytes = _ctypes.c_ulonglong(0)
_ctypes.windll.kernel32.GetDiskFreeSpaceExW(_ctypes.c_wchar_p(dir_name), None,
None, _ctypes.pointer(free_bytes))
free_bytes = ctypes.c_ulonglong(0)
try:
ctypes.windll.kernel32.GetDiskFreeSpaceExW(
ctypes.c_wchar_p(dir_name),
None,
None,
ctypes.pointer(free_bytes),
)
result = free_bytes.value

except Exception as e:
log.info('%r', e)
return result


def is_admin_on_windows(): # pragma: unix no cover
# http://stackoverflow.com/a/1026626/2127762
result = False
if _ctypes:
try:
result = _ctypes.windll.shell32.IsUserAnAdmin() != 0
except Exception as e: # pragma: no cover
log.info('%r', e)
result = 'unknown'

try:
result = ctypes.windll.shell32.IsUserAnAdmin() != 0
except Exception as e: # pragma: no cover
log.info('%r', e)
# result = 'unknown'
return result


def _wait_and_close_handle(process_handle):
"""Waits until spawned process finishes and closes the handle for it."""
try:
WaitForSingleObject(process_handle, INFINITE)
CloseHandle(process_handle)
except Exception as e:
log.info('%r', e)


def run_as_admin(args, wait=True):
"""
Run command line argument list (`args`) with elevated privileges.

If `wait` is True, the process will block until completion.

NOTES:
- no stdin / stdout / stderr pipe support
- does not automatically quote arguments (i.e. for paths that may contain spaces)
See:
- http://stackoverflow.com/a/19719292/1170370 on 20160407 MCS.
- msdn.microsoft.com/en-us/library/windows/desktop/bb762153(v=vs.85).aspx
- https://github.com/ContinuumIO/menuinst/blob/master/menuinst/windows/win_elevate.py
- https://github.com/saltstack/salt-windows-install/blob/master/deps/salt/python/App/Lib/site-packages/win32/Demos/pipes/runproc.py # NOQA
- https://github.com/twonds/twisted/blob/master/twisted/internet/_dumbwin32proc.py
- https://stackoverflow.com/a/19982092/2127762
- https://www.codeproject.com/Articles/19165/Vista-UAC-The-Definitive-Guide
- https://github.com/JustAMan/pyWinClobber/blob/master/win32elevate.py
"""
arg0 = args[0]
param_str = ' '.join(args[1:] if len(args) > 1 else ())
hprocess = None
error_code = None
try:
execute_info = ShellExecuteInfo(
fMask=SEE_MASK_NOCLOSEPROCESS,
hwnd=None,
lpVerb='runas',
lpFile=arg0,
lpParameters=param_str,
lpDirectory=None,
nShow=SW.HIDE,
)
successful = ShellExecuteEx(ctypes.byref(execute_info))
hprocess = execute_info.hProcess
except Exception as e:
successful = False
error_code = e
log.info('%r', e)

if not successful:
error_code = ctypes.WinError()
elif wait:
_wait_and_close_handle(execute_info.hProcess)

return hprocess, error_code
27 changes: 14 additions & 13 deletions conda/core/initialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -509,24 +509,19 @@ def run_plan_elevated(plan):

if any(step['result'] == Result.NEEDS_SUDO for step in plan):
if on_win:
from menuinst.win_elevate import runAsAdmin
# https://github.com/ContinuumIO/menuinst/blob/master/menuinst/windows/win_elevate.py # no stdin / stdout / stderr pipe support # NOQA
# https://github.com/saltstack/salt-windows-install/blob/master/deps/salt/python/App/Lib/site-packages/win32/Demos/pipes/runproc.py # NOQA
# https://github.com/twonds/twisted/blob/master/twisted/internet/_dumbwin32proc.py
# https://stackoverflow.com/a/19982092/2127762
# https://www.codeproject.com/Articles/19165/Vista-UAC-The-Definitive-Guide

# from menuinst.win_elevate import isUserAdmin, runAsAdmin
# I do think we can pipe to stdin, so we're going to have to write to a temp file and read in the elevated process # NOQA

from ..common.os.windows import run_as_admin
temp_path = None
try:
with NamedTemporaryFile('w+b', suffix='.json', delete=False) as tf:
# the default mode is 'w+b', and universal new lines don't work in that mode
tf.write(ensure_binary(json.dumps(plan, ensure_ascii=False)))
temp_path = tf.name
rc = runAsAdmin((sys.executable, '-m', 'conda.initialize', '"%s"' % temp_path))
assert rc == 0
python_exe = '"%s"' % abspath(sys.executable)
hinstance, error_code = run_as_admin((python_exe, '-m', 'conda.core.initialize',
'"%s"' % temp_path))
if error_code is not None:
print("ERROR during elevated execution.\n rc: %s" % error_code,
file=sys.stderr)

with open(temp_path) as fh:
_plan = json.loads(ensure_unicode(fh.read()))
Expand All @@ -537,7 +532,7 @@ def run_plan_elevated(plan):
else:
stdin = json.dumps(plan)
result = subprocess_call(
'sudo %s -m conda.initialize' % sys.executable,
'sudo %s -m conda.core.initialize' % sys.executable,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No wonder it wasn't working!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep I told you it was a silly bug 🤣

env={},
path=os.getcwd(),
stdin=stdin
Expand Down Expand Up @@ -1033,17 +1028,23 @@ def _read_windows_registry(target_path): # pragma: no cover
main_key, the_rest = target_path.split('\\', 1)
subkey_str, value_name = the_rest.rsplit('\\', 1)
main_key = getattr(winreg, main_key)

try:
key = winreg.OpenKey(main_key, subkey_str, 0, winreg.KEY_READ)
except EnvironmentError as e:
if e.errno != ENOENT:
raise
return None, None

try:
value_tuple = winreg.QueryValueEx(key, value_name)
value_value = value_tuple[0].strip()
value_type = value_tuple[1]
return value_value, value_type
except Exception:
# [WinError 2] The system cannot find the file specified
winreg.CloseKey(key)
return None, None
finally:
winreg.CloseKey(key)

Expand Down