/brz/remove-bazaar

To get this branch, use:
bzr branch http://gegoxaren.bato24.eu/bzr/brz/remove-bazaar

« back to all changes in this revision

Viewing changes to breezy/win32utils.py

  • Committer: Jelmer Vernooij
  • Date: 2020-04-05 19:11:34 UTC
  • mto: (7490.7.16 work)
  • mto: This revision was merged to the branch mainline in revision 7501.
  • Revision ID: jelmer@jelmer.uk-20200405191134-0aebh8ikiwygxma5
Populate the .gitignore file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
Only one dependency: ctypes should be installed.
20
20
"""
21
21
 
 
22
from __future__ import absolute_import
 
23
 
22
24
import glob
23
25
import os
24
26
import struct
29
31
    )
30
32
from breezy.i18n import gettext
31
33
 
 
34
has_ctypes_win32 = False
 
35
if sys.platform == 'win32':
 
36
    try:
 
37
        import ctypes
 
38
    except ImportError:
 
39
        has_ctypes_win32 = False
 
40
 
32
41
 
33
42
# Special Win32 API constants
34
43
# Handles of std streams
54
63
 
55
64
def debug_memory_win32api(message='', short=True):
56
65
    """Use trace.note() to dump the running memory info."""
57
 
    import ctypes
58
66
    from breezy import trace
59
 
    class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
60
 
        """Used by GetProcessMemoryInfo"""
61
 
        _fields_ = [('cb', ctypes.c_ulong),
62
 
                    ('PageFaultCount', ctypes.c_ulong),
63
 
                    ('PeakWorkingSetSize', ctypes.c_size_t),
64
 
                    ('WorkingSetSize', ctypes.c_size_t),
65
 
                    ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
66
 
                    ('QuotaPagedPoolUsage', ctypes.c_size_t),
67
 
                    ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
68
 
                    ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
69
 
                    ('PagefileUsage', ctypes.c_size_t),
70
 
                    ('PeakPagefileUsage', ctypes.c_size_t),
71
 
                    ('PrivateUsage', ctypes.c_size_t),
72
 
                    ]
73
 
    cur_process = ctypes.windll.kernel32.GetCurrentProcess()
74
 
    mem_struct = PROCESS_MEMORY_COUNTERS_EX()
75
 
    ret = ctypes.windll.psapi.GetProcessMemoryInfo(
76
 
        cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
77
 
    if not ret:
78
 
        trace.note(gettext('Failed to GetProcessMemoryInfo()'))
 
67
    if has_ctypes_win32:
 
68
        class PROCESS_MEMORY_COUNTERS_EX(ctypes.Structure):
 
69
            """Used by GetProcessMemoryInfo"""
 
70
            _fields_ = [('cb', ctypes.c_ulong),
 
71
                        ('PageFaultCount', ctypes.c_ulong),
 
72
                        ('PeakWorkingSetSize', ctypes.c_size_t),
 
73
                        ('WorkingSetSize', ctypes.c_size_t),
 
74
                        ('QuotaPeakPagedPoolUsage', ctypes.c_size_t),
 
75
                        ('QuotaPagedPoolUsage', ctypes.c_size_t),
 
76
                        ('QuotaPeakNonPagedPoolUsage', ctypes.c_size_t),
 
77
                        ('QuotaNonPagedPoolUsage', ctypes.c_size_t),
 
78
                        ('PagefileUsage', ctypes.c_size_t),
 
79
                        ('PeakPagefileUsage', ctypes.c_size_t),
 
80
                        ('PrivateUsage', ctypes.c_size_t),
 
81
                        ]
 
82
        cur_process = ctypes.windll.kernel32.GetCurrentProcess()
 
83
        mem_struct = PROCESS_MEMORY_COUNTERS_EX()
 
84
        ret = ctypes.windll.psapi.GetProcessMemoryInfo(
 
85
            cur_process, ctypes.byref(mem_struct), ctypes.sizeof(mem_struct))
 
86
        if not ret:
 
87
            trace.note(gettext('Failed to GetProcessMemoryInfo()'))
 
88
            return
 
89
        info = {'PageFaultCount': mem_struct.PageFaultCount,
 
90
                'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
 
91
                'WorkingSetSize': mem_struct.WorkingSetSize,
 
92
                'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
 
93
                'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
 
94
                'QuotaPeakNonPagedPoolUsage':
 
95
                    mem_struct.QuotaPeakNonPagedPoolUsage,
 
96
                'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
 
97
                'PagefileUsage': mem_struct.PagefileUsage,
 
98
                'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
 
99
                'PrivateUsage': mem_struct.PrivateUsage,
 
100
                }
 
101
    else:
 
102
        trace.note(gettext('Cannot debug memory on win32 without ctypes'
 
103
                           ' or win32process'))
79
104
        return
80
 
    info = {'PageFaultCount': mem_struct.PageFaultCount,
81
 
            'PeakWorkingSetSize': mem_struct.PeakWorkingSetSize,
82
 
            'WorkingSetSize': mem_struct.WorkingSetSize,
83
 
            'QuotaPeakPagedPoolUsage': mem_struct.QuotaPeakPagedPoolUsage,
84
 
            'QuotaPagedPoolUsage': mem_struct.QuotaPagedPoolUsage,
85
 
            'QuotaPeakNonPagedPoolUsage':
86
 
                mem_struct.QuotaPeakNonPagedPoolUsage,
87
 
            'QuotaNonPagedPoolUsage': mem_struct.QuotaNonPagedPoolUsage,
88
 
            'PagefileUsage': mem_struct.PagefileUsage,
89
 
            'PeakPagefileUsage': mem_struct.PeakPagefileUsage,
90
 
            'PrivateUsage': mem_struct.PrivateUsage,
91
 
            }
92
105
    if short:
93
106
        # using base-2 units (see HACKING.txt).
94
107
        trace.note(gettext('WorkingSize {0:>7}KiB'
119
132
    console window and return tuple (sizex, sizey) if success,
120
133
    or default size (defaultx, defaulty) otherwise.
121
134
    """
122
 
    import ctypes
 
135
    if not has_ctypes_win32:
 
136
        # no ctypes is found
 
137
        return (defaultx, defaulty)
 
138
 
123
139
    # To avoid problem with redirecting output via pipe
124
140
    # we need to use stderr instead of stdout
125
141
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
142
158
 
143
159
    Result is always unicode (or None).
144
160
    """
145
 
    import ctypes
146
 
    try:
147
 
        SHGetSpecialFolderPath = \
148
 
            ctypes.windll.shell32.SHGetSpecialFolderPathW
149
 
    except AttributeError:
150
 
        pass
151
 
    else:
152
 
        buf = ctypes.create_unicode_buffer(MAX_PATH)
153
 
        if SHGetSpecialFolderPath(None, buf, csidl, 0):
154
 
            return buf.value
 
161
    if has_ctypes_win32:
 
162
        try:
 
163
            SHGetSpecialFolderPath = \
 
164
                ctypes.windll.shell32.SHGetSpecialFolderPathW
 
165
        except AttributeError:
 
166
            pass
 
167
        else:
 
168
            buf = ctypes.create_unicode_buffer(MAX_PATH)
 
169
            if SHGetSpecialFolderPath(None, buf, csidl, 0):
 
170
                return buf.value
 
171
    return None
155
172
 
156
173
 
157
174
def get_appdata_location():
167
184
    if appdata:
168
185
        return appdata
169
186
    # Use APPDATA if defined, will return None if not
170
 
    return os.environ.get('APPDATA')
 
187
    return get_environ_unicode('APPDATA')
171
188
 
172
189
 
173
190
def get_local_appdata_location():
184
201
    if local:
185
202
        return local
186
203
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
187
 
    local = os.environ.get('LOCALAPPDATA')
 
204
    local = get_environ_unicode('LOCALAPPDATA')
188
205
    if local:
189
206
        return local
190
207
    return get_appdata_location()
199
216
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
200
217
    if home:
201
218
        return home
202
 
    home = os.environ.get('HOME')
 
219
    home = get_environ_unicode('HOME')
203
220
    if home is not None:
204
221
        return home
205
 
    homepath = os.environ.get('HOMEPATH')
 
222
    homepath = get_environ_unicode('HOMEPATH')
206
223
    if homepath is not None:
207
 
        return os.path.join(os.environ.get('HOMEDIR', ''), home)
 
224
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
208
225
    # at least return windows root directory
209
 
    windir = os.environ.get('WINDIR')
 
226
    windir = get_environ_unicode('WINDIR')
210
227
    if windir:
211
228
        return os.path.splitdrive(windir)[0] + '/'
212
229
    # otherwise C:\ is good enough for 98% users
217
234
    """Return user name as login name.
218
235
    If name cannot be obtained return None.
219
236
    """
220
 
    try:
221
 
        advapi32 = ctypes.windll.advapi32
222
 
        GetUserName = getattr(advapi32, 'GetUserNameW')
223
 
    except AttributeError:
224
 
        pass
225
 
    else:
226
 
        buf = ctypes.create_unicode_buffer(UNLEN + 1)
227
 
        n = ctypes.c_int(UNLEN + 1)
228
 
        if GetUserName(buf, ctypes.byref(n)):
229
 
            return buf.value
 
237
    if has_ctypes_win32:
 
238
        try:
 
239
            advapi32 = ctypes.windll.advapi32
 
240
            GetUserName = getattr(advapi32, 'GetUserNameW')
 
241
        except AttributeError:
 
242
            pass
 
243
        else:
 
244
            buf = ctypes.create_unicode_buffer(UNLEN + 1)
 
245
            n = ctypes.c_int(UNLEN + 1)
 
246
            if GetUserName(buf, ctypes.byref(n)):
 
247
                return buf.value
230
248
    # otherwise try env variables
231
 
    return os.environ.get('USERNAME')
 
249
    return get_environ_unicode('USERNAME')
232
250
 
233
251
 
234
252
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
242
260
 
243
261
    :return: A unicode string representing the host name.
244
262
    """
245
 
    import ctypes
246
 
    buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
247
 
    n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
 
263
    if has_ctypes_win32:
 
264
        try:
 
265
            kernel32 = ctypes.windll.kernel32
 
266
        except AttributeError:
 
267
            pass  # Missing the module we need
 
268
        else:
 
269
            buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
 
270
            n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
248
271
 
249
 
    # Try GetComputerNameEx which gives a proper Unicode hostname
250
 
    GetComputerNameEx = getattr(
251
 
        ctypes.windll.kernel32, 'GetComputerNameExW', None)
252
 
    if (GetComputerNameEx is not None
253
 
        and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
254
 
                              buf, ctypes.byref(n))):
255
 
        return buf.value
256
 
    return os.environ.get('COMPUTERNAME')
 
272
            # Try GetComputerNameEx which gives a proper Unicode hostname
 
273
            GetComputerNameEx = getattr(kernel32, 'GetComputerNameExW', None)
 
274
            if (GetComputerNameEx is not None
 
275
                and GetComputerNameEx(_WIN32_ComputerNameDnsHostname,
 
276
                                      buf, ctypes.byref(n))):
 
277
                return buf.value
 
278
    return get_environ_unicode('COMPUTERNAME')
257
279
 
258
280
 
259
281
def _ensure_with_dir(path):
343
365
 
344
366
    if type_id == REG_SZ:
345
367
        return path
 
368
    if type_id == REG_EXPAND_SZ and has_win32api:
 
369
        fullpath = win32api.ExpandEnvironmentStrings(path)
 
370
        if len(fullpath) > 1 and fullpath[0] == '"' and fullpath[-1] == '"':
 
371
            fullpath = fullpath[1:-1]   # remove quotes around value
 
372
        return fullpath
346
373
    return appname
347
374
 
348
375
 
349
376
def set_file_attr_hidden(path):
350
377
    """Set file attributes to hidden if possible"""
351
 
    from ctypes.wintypes import BOOL, DWORD, LPWSTR
352
 
    import ctypes
 
378
    if not has_ctypes_win32:
 
379
        return
 
380
    from ctypes.wintypes import BOOL, DWORD, LPCWSTR
 
381
    _kernel32 = ctypes.windll.kernel32
353
382
    # <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
354
 
    SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW
355
 
    SetFileAttributes.argtypes = LPWSTR, DWORD
356
 
    SetFileAttributes.restype = BOOL
 
383
    _SetFileAttributesW = ctypes.WINFUNCTYPE(BOOL, LPCWSTR, DWORD)(
 
384
        ("SetFileAttributesW", _kernel32))
357
385
    FILE_ATTRIBUTE_HIDDEN = 2
358
386
    if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
359
387
        e = ctypes.WinError()
403
431
    return args
404
432
 
405
433
 
406
 
def _ctypes_is_local_pid_dead(pid):
407
 
    import ctypes
408
 
    kernel32 = ctypes.wintypes.windll.kernel32
409
 
    """True if pid doesn't correspond to live process on this machine"""
410
 
    handle = kernel32.OpenProcess(1, False, pid)
411
 
    if not handle:
412
 
        errorcode = ctypes.GetLastError()
413
 
        if errorcode == 5:  # ERROR_ACCESS_DENIED
414
 
            # Probably something alive we're not allowed to kill
415
 
            return False
416
 
        elif errorcode == 87:  # ERROR_INVALID_PARAMETER
417
 
            return True
418
 
        raise ctypes.WinError(errorcode)
419
 
    Kernel32.CloseHandle(handle)
420
 
    return False
421
 
 
422
 
is_local_pid_dead = _ctypes_is_local_pid_dead
 
434
if has_ctypes_win32:
 
435
    def get_unicode_argv():
 
436
        prototype = ctypes.WINFUNCTYPE(ctypes.c_wchar_p)
 
437
        GetCommandLineW = prototype(("GetCommandLineW",
 
438
                                     ctypes.windll.kernel32))
 
439
        command_line = GetCommandLineW()
 
440
        if command_line is None:
 
441
            raise ctypes.WinError()
 
442
        # Skip the first argument, since we only care about parameters
 
443
        argv = _command_line_to_argv(command_line, sys.argv)[1:]
 
444
        return argv
 
445
 
 
446
    def get_environ_unicode(key, default=None):
 
447
        """Get `key` from environment as unicode or `default` if unset
 
448
 
 
449
        The environment is natively unicode on modern windows versions but
 
450
        Python 2 only accesses it through the legacy bytestring api.
 
451
 
 
452
        Environmental variable names are case insenstive on Windows.
 
453
 
 
454
        A large enough buffer will be allocated to retrieve the value, though
 
455
        it may take two calls to the underlying library function.
 
456
        """
 
457
        cfunc = getattr(get_environ_unicode, "_c_function", None)
 
458
        if cfunc is None:
 
459
            from ctypes.wintypes import DWORD, LPCWSTR, LPWSTR
 
460
            cfunc = ctypes.WINFUNCTYPE(DWORD, LPCWSTR, LPWSTR, DWORD)(
 
461
                ("GetEnvironmentVariableW", ctypes.windll.kernel32))
 
462
            get_environ_unicode._c_function = cfunc
 
463
        buffer_size = 256  # heuristic, 256 characters often enough
 
464
        while True:
 
465
            buf = ctypes.create_unicode_buffer(buffer_size)
 
466
            length = cfunc(key, buf, buffer_size)
 
467
            if not length:
 
468
                code = ctypes.GetLastError()
 
469
                if code == 203:  # ERROR_ENVVAR_NOT_FOUND
 
470
                    return default
 
471
                raise ctypes.WinError(code)
 
472
            if buffer_size > length:
 
473
                return buf[:length]
 
474
            buffer_size = length
 
475
 
 
476
 
 
477
if has_ctypes_win32:
 
478
    from ctypes.wintypes import BOOL, DWORD, HANDLE
 
479
    _kernel32 = ctypes.windll.kernel32
 
480
    _CloseHandle = ctypes.WINFUNCTYPE(BOOL, HANDLE)(
 
481
        ("CloseHandle", _kernel32))
 
482
    _OpenProcess = ctypes.WINFUNCTYPE(HANDLE, DWORD, BOOL, DWORD)(
 
483
        ("OpenProcess", _kernel32))
 
484
 
 
485
    def _ctypes_is_local_pid_dead(pid):
 
486
        """True if pid doesn't correspond to live process on this machine"""
 
487
        handle = _OpenProcess(1, False, pid)  # PROCESS_TERMINATE
 
488
        if not handle:
 
489
            errorcode = ctypes.GetLastError()
 
490
            if errorcode == 5:  # ERROR_ACCESS_DENIED
 
491
                # Probably something alive we're not allowed to kill
 
492
                return False
 
493
            elif errorcode == 87:  # ERROR_INVALID_PARAMETER
 
494
                return True
 
495
            raise ctypes.WinError(errorcode)
 
496
        _CloseHandle(handle)
 
497
        return False
 
498
 
 
499
    is_local_pid_dead = _ctypes_is_local_pid_dead