19
19
Only one dependency: ctypes should be installed.
22
from __future__ import absolute_import
30
from breezy.i18n import gettext
34
from brzlib.i18n import gettext
32
has_ctypes_win32 = False
33
37
if sys.platform == 'win32':
37
has_ctypes_win32 = False
38
_major,_minor,_build,_platform,_text = sys.getwindowsversion()
41
# The operating system platform.
42
# This member can be one of the following values.
43
# ========================== ======================================
45
# -------------------------- --------------------------------------
46
# VER_PLATFORM_WIN32_NT The operating system is Windows Vista,
47
# 2 Windows Server "Longhorn",
48
# Windows Server 2003, Windows XP,
49
# Windows 2000, or Windows NT.
51
# VER_PLATFORM_WIN32_WINDOWS The operating system is Windows Me,
52
# 1 Windows 98, or Windows 95.
53
# ========================== ======================================
57
# don't care about real Windows name, just to force safe operations
63
# We can cope without it; use a separate variable to help pyflakes
70
if winver == 'Windows 98':
71
create_buffer = ctypes.create_string_buffer
72
def extract_buffer(buf):
73
return buf.value.decode("mbcs")
76
create_buffer = ctypes.create_unicode_buffer
77
extract_buffer = operator.attrgetter("value")
83
has_pywintypes = has_win32file = has_win32api = False
96
# pulling in win32com.shell is a bit of overhead, and normally we don't need
97
# it as ctypes is preferred and common. lazy_imports and "optional"
98
# modules don't work well, so we do our own lazy thing...
99
has_win32com_shell = None # Set to True or False once we know for sure...
40
101
# Special Win32 API constants
41
102
# Handles of std streams
76
136
('PagefileUsage', ctypes.c_size_t),
77
137
('PeakPagefileUsage', ctypes.c_size_t),
78
138
('PrivateUsage', ctypes.c_size_t),
80
140
cur_process = ctypes.windll.kernel32.GetCurrentProcess()
81
141
mem_struct = PROCESS_MEMORY_COUNTERS_EX()
82
ret = ctypes.windll.psapi.GetProcessMemoryInfo(
83
cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
142
ret = ctypes.windll.psapi.GetProcessMemoryInfo(cur_process,
143
ctypes.byref(mem_struct),
144
ctypes.sizeof(mem_struct))
85
146
trace.note(gettext('Failed to GetProcessMemoryInfo()'))
95
156
'PagefileUsage': mem_struct.PagefileUsage,
96
157
'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
97
158
'PrivateUsage': mem_struct.PrivateUsage,
162
# win32process does not return PrivateUsage, because it doesn't use
163
# PROCESS_MEMORY_COUNTERS_EX (it uses the one without _EX).
164
proc = win32process.GetCurrentProcess()
165
info = win32process.GetProcessMemoryInfo(proc)
100
167
trace.note(gettext('Cannot debug memory on win32 without ctypes'
104
171
# using base-2 units (see HACKING.txt).
105
172
trace.note(gettext('WorkingSize {0:>7}KiB'
106
'\tPeakWorking {1:>7}KiB\t{2}').format(
173
'\tPeakWorking {1:>7}KiB\t{2}').format(
107
174
info['WorkingSetSize'] / 1024,
108
175
info['PeakWorkingSetSize'] / 1024,
112
179
trace.note('%s', message)
113
trace.note(gettext('WorkingSize %8d KiB'),
114
info['WorkingSetSize'] / 1024)
115
trace.note(gettext('PeakWorking %8d KiB'),
116
info['PeakWorkingSetSize'] / 1024)
117
trace.note(gettext('PagefileUsage %8d KiB'),
118
info.get('PagefileUsage', 0) / 1024)
180
trace.note(gettext('WorkingSize %8d KiB'), info['WorkingSetSize'] / 1024)
181
trace.note(gettext('PeakWorking %8d KiB'), info['PeakWorkingSetSize'] / 1024)
182
trace.note(gettext('PagefileUsage %8d KiB'), info.get('PagefileUsage', 0) / 1024)
119
183
trace.note(gettext('PeakPagefileUsage %8d KiB'),
120
184
info.get('PeakPagefileUsage', 0) / 1024)
121
trace.note(gettext('PrivateUsage %8d KiB'),
122
info.get('PrivateUsage', 0) / 1024)
185
trace.note(gettext('PrivateUsage %8d KiB'), info.get('PrivateUsage', 0) / 1024)
123
186
trace.note(gettext('PageFaultCount %8d'), info.get('PageFaultCount', 0))
144
207
(bufx, bufy, curx, cury, wattr,
145
left, top, right, bottom, maxx, maxy) = struct.unpack(
208
left, top, right, bottom, maxx, maxy) = struct.unpack(
146
209
"hhhhHhhhhhh", csbi.raw)
147
210
sizex = right - left + 1
148
211
sizey = bottom - top + 1
166
229
buf = ctypes.create_unicode_buffer(MAX_PATH)
167
if SHGetSpecialFolderPath(None, buf, csidl, 0):
230
if SHGetSpecialFolderPath(None,buf,csidl,0):
233
global has_win32com_shell
234
if has_win32com_shell is None:
236
from win32com.shell import shell
237
has_win32com_shell = True
239
has_win32com_shell = False
240
if has_win32com_shell:
241
# still need to bind the name locally, but this is fast.
242
from win32com.shell import shell
244
return shell.SHGetSpecialFolderPath(0, csidl, 0)
246
# possibly E_NOTIMPL meaning we can't load the function pointer,
247
# or E_FAIL meaning the function failed - regardless, just ignore it
226
306
return os.path.splitdrive(windir)[0] + '/'
227
307
# otherwise C:\ is good enough for 98% users
308
return unicode('C:/')
231
311
def get_user_name():
232
312
"""Return user name as login name.
233
313
If name cannot be obtained return None.
237
317
advapi32 = ctypes.windll.advapi32
238
GetUserName = getattr(advapi32, 'GetUserNameW')
318
GetUserName = getattr(advapi32, 'GetUserName'+suffix)
239
319
except AttributeError:
242
buf = ctypes.create_unicode_buffer(UNLEN + 1)
243
n = ctypes.c_int(UNLEN + 1)
322
buf = create_buffer(UNLEN+1)
323
n = ctypes.c_int(UNLEN+1)
244
324
if GetUserName(buf, ctypes.byref(n)):
325
return extract_buffer(buf)
246
326
# otherwise try env variables
247
327
return get_environ_unicode('USERNAME')
251
331
# computer or the cluster associated with the local computer."
252
332
_WIN32_ComputerNameDnsHostname = 1
255
334
def get_host_name():
256
335
"""Return host machine name.
257
336
If name cannot be obtained return None.
259
338
:return: A unicode string representing the host name.
342
return win32api.GetComputerNameEx(_WIN32_ComputerNameDnsHostname)
343
except (NotImplementedError, win32api.error):
344
# NotImplemented will happen on win9x...
263
348
kernel32 = ctypes.windll.kernel32
264
349
except AttributeError:
265
pass # Missing the module we need
350
pass # Missing the module we need
267
buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
268
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
352
buf = create_buffer(MAX_COMPUTERNAME_LENGTH+1)
353
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
270
355
# Try GetComputerNameEx which gives a proper Unicode hostname
271
GetComputerNameEx = getattr(kernel32, 'GetComputerNameExW', None)
356
GetComputerNameEx = getattr(kernel32, 'GetComputerNameEx'+suffix,
272
358
if (GetComputerNameEx is not None
273
359
and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
274
360
buf, ctypes.byref(n))):
361
return extract_buffer(buf)
363
# Try GetComputerName in case GetComputerNameEx wasn't found
364
# It returns the NETBIOS name, which isn't as good, but still ok.
365
# The first GetComputerNameEx might have changed 'n', so reset it
366
n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH+1)
367
GetComputerName = getattr(kernel32, 'GetComputerName'+suffix,
369
if (GetComputerName is not None
370
and GetComputerName(buf, ctypes.byref(n))):
371
return extract_buffer(buf)
276
372
return get_environ_unicode('COMPUTERNAME')
375
@symbol_versioning.deprecated_function(
376
symbol_versioning.deprecated_in((2, 5, 0)))
377
def _ensure_unicode(s):
378
if s and type(s) != unicode:
379
from brzlib import osutils
380
s = s.decode(osutils.get_user_encoding())
384
get_appdata_location_unicode = symbol_versioning.deprecated_function(
385
symbol_versioning.deprecated_in((2, 5, 0)))(get_appdata_location)
387
get_home_location_unicode = symbol_versioning.deprecated_function(
388
symbol_versioning.deprecated_in((2, 5, 0)))(get_home_location)
390
get_user_name_unicode = symbol_versioning.deprecated_function(
391
symbol_versioning.deprecated_in((2, 5, 0)))(get_user_name)
393
get_host_name_unicode = symbol_versioning.deprecated_function(
394
symbol_versioning.deprecated_in((2, 5, 0)))(get_host_name)
279
397
def _ensure_with_dir(path):
280
398
if (not os.path.split(path)[0] or path.startswith(u'*')
281
or path.startswith(u'?')):
399
or path.startswith(u'?')):
282
400
return u'./' + path, True
284
402
return path, False
287
404
def _undo_ensure_with_dir(path, corrected):
374
491
def set_file_attr_hidden(path):
375
492
"""Set file attributes to hidden if possible"""
376
if not has_ctypes_win32:
378
from ctypes.wintypes import BOOL, DWORD, LPCWSTR
379
_kernel32 = ctypes.windll.kernel32
380
# <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
381
_SetFileAttributesW = ctypes.WINFUNCTYPE(BOOL, LPCWSTR, DWORD)(
382
("SetFileAttributesW", _kernel32))
383
FILE_ATTRIBUTE_HIDDEN = 2
384
if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
385
e = ctypes.WinError()
387
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
494
if winver != 'Windows 98':
495
SetFileAttributes = win32file.SetFileAttributesW
497
SetFileAttributes = win32file.SetFileAttributes
499
SetFileAttributes(path, win32file.FILE_ATTRIBUTE_HIDDEN)
500
except pywintypes.error, e:
501
from brzlib import trace
502
trace.mutter('Unable to set hidden attribute on %r: %s', path, e)
390
505
def _command_line_to_argv(command_line, argv, single_quotes_allowed=False):
401
516
:return: A list of unicode strings.
403
518
# First, split the command line
404
s = cmdline.Splitter(
405
command_line, single_quotes_allowed=single_quotes_allowed)
407
# Bug #587868 Now make sure that the length of s agrees with sys.argv
408
# we do this by simply counting the number of arguments in each. The counts should
409
# agree no matter what encoding sys.argv is in (AFAIK)
410
# len(arguments) < len(sys.argv) should be an impossibility since python gets
519
s = cmdline.Splitter(command_line, single_quotes_allowed=single_quotes_allowed)
521
# Bug #587868 Now make sure that the length of s agrees with sys.argv
522
# we do this by simply counting the number of arguments in each. The counts should
523
# agree no matter what encoding sys.argv is in (AFAIK)
524
# len(arguments) < len(sys.argv) should be an impossibility since python gets
411
525
# args from the very same PEB as does GetCommandLineW
412
526
arguments = list(s)
414
528
# Now shorten the command line we get from GetCommandLineW to match sys.argv
415
529
if len(arguments) < len(argv):
416
530
raise AssertionError("Split command line can't be shorter than argv")
417
531
arguments = arguments[len(arguments) - len(argv):]
419
533
# Carry on to process globs (metachars) in the command line
420
534
# expand globs if necessary
421
535
# TODO: Use 'globbing' instead of 'glob.glob', this gives us stuff like
458
575
cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
459
576
("GetEnvironmentVariableW", ctypes.windll.kernel32))
460
577
get_environ_unicode._c_function = cfunc
461
buffer_size = 256 # heuristic, 256 characters often enough
578
buffer_size = 256 # heuristic, 256 characters often enough
463
buf = ctypes.create_unicode_buffer(buffer_size)
464
length = cfunc(key, buf, buffer_size)
580
buffer = ctypes.create_unicode_buffer(buffer_size)
581
length = cfunc(key, buffer, buffer_size)
466
583
code = ctypes.GetLastError()
467
if code == 203: # ERROR_ENVVAR_NOT_FOUND
584
if code == 203: # ERROR_ENVVAR_NOT_FOUND
469
586
raise ctypes.WinError(code)
470
587
if buffer_size > length:
588
return buffer[:length]
472
589
buffer_size = length
591
get_unicode_argv = None
592
def get_environ_unicode(key, default=None):
593
"""Get `key` from environment as unicode or `default` if unset
595
Fallback version that should basically never be needed.
597
from brzlib import osutils
599
return os.environ[key].decode(osutils.get_user_encoding())
605
def _pywin32_is_local_pid_dead(pid):
606
"""True if pid doesn't correspond to live process on this machine"""
608
handle = win32api.OpenProcess(1, False, pid) # PROCESS_TERMINATE
609
except pywintypes.error, e:
610
if e[0] == 5: # ERROR_ACCESS_DENIED
611
# Probably something alive we're not allowed to kill
613
elif e[0] == 87: # ERROR_INVALID_PARAMETER
618
is_local_pid_dead = _pywin32_is_local_pid_dead
619
elif has_ctypes and sys.platform == 'win32':
476
620
from ctypes.wintypes import BOOL, DWORD, HANDLE
477
621
_kernel32 = ctypes.windll.kernel32
478
622
_CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
479
623
("CloseHandle", _kernel32))
480
624
_OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
481
625
("OpenProcess", _kernel32))
483
626
def _ctypes_is_local_pid_dead(pid):
484
627
"""True if pid doesn't correspond to live process on this machine"""
485
handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
628
handle = _OpenProcess(1, False, pid) # PROCESS_TERMINATE
487
630
errorcode = ctypes.GetLastError()
488
if errorcode == 5: # ERROR_ACCESS_DENIED
631
if errorcode == 5: # ERROR_ACCESS_DENIED
489
632
# Probably something alive we're not allowed to kill
491
elif errorcode == 87: # ERROR_INVALID_PARAMETER
634
elif errorcode == 87: # ERROR_INVALID_PARAMETER
493
636
raise ctypes.WinError(errorcode)
494
637
_CloseHandle(handle)
497
639
is_local_pid_dead = _ctypes_is_local_pid_dead
642
def _is_pywintypes_error(evalue):
643
"""True if exception instance is an error from pywin32"""
644
if has_pywintypes and isinstance(evalue, pywintypes.error):