/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: Breezy landing bot
  • Author(s): Jelmer Vernooij
  • Date: 2020-07-28 02:47:10 UTC
  • mfrom: (7519.1.1 merge-3.1)
  • Revision ID: breezy.the.bot@gmail.com-20200728024710-a2ylds219f1lsl62
Merge lp:brz/3.1.

Merged from https://code.launchpad.net/~jelmer/brz/merge-3.1/+merge/388173

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
 
 
24
22
import glob
25
23
import os
26
24
import struct
31
29
    )
32
30
from breezy.i18n import gettext
33
31
 
34
 
has_ctypes_win32 = False
35
 
if sys.platform == 'win32':
36
 
    try:
37
 
        import ctypes
38
 
    except ImportError:
39
 
        has_ctypes_win32 = False
40
 
 
41
32
 
42
33
# Special Win32 API constants
43
34
# Handles of std streams
63
54
 
64
55
def debug_memory_win32api(message='', short=True):
65
56
    """Use trace.note() to dump the running memory info."""
 
57
    import ctypes
66
58
    from breezy import trace
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'))
 
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()'))
104
79
        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
            }
105
92
    if short:
106
93
        # using base-2 units (see HACKING.txt).
107
94
        trace.note(gettext('WorkingSize {0:>7}KiB'
132
119
    console window and return tuple (sizex, sizey) if success,
133
120
    or default size (defaultx, defaulty) otherwise.
134
121
    """
135
 
    if not has_ctypes_win32:
136
 
        # no ctypes is found
137
 
        return (defaultx, defaulty)
138
 
 
 
122
    import ctypes
139
123
    # To avoid problem with redirecting output via pipe
140
124
    # we need to use stderr instead of stdout
141
125
    h = ctypes.windll.kernel32.GetStdHandle(WIN32_STDERR_HANDLE)
158
142
 
159
143
    Result is always unicode (or None).
160
144
    """
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
 
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
172
155
 
173
156
 
174
157
def get_appdata_location():
184
167
    if appdata:
185
168
        return appdata
186
169
    # Use APPDATA if defined, will return None if not
187
 
    return get_environ_unicode('APPDATA')
 
170
    return os.environ.get('APPDATA')
188
171
 
189
172
 
190
173
def get_local_appdata_location():
201
184
    if local:
202
185
        return local
203
186
    # Vista supplies LOCALAPPDATA, but XP and earlier do not.
204
 
    local = get_environ_unicode('LOCALAPPDATA')
 
187
    local = os.environ.get('LOCALAPPDATA')
205
188
    if local:
206
189
        return local
207
190
    return get_appdata_location()
216
199
    home = _get_sh_special_folder_path(CSIDL_PERSONAL)
217
200
    if home:
218
201
        return home
219
 
    home = get_environ_unicode('HOME')
 
202
    home = os.environ.get('HOME')
220
203
    if home is not None:
221
204
        return home
222
 
    homepath = get_environ_unicode('HOMEPATH')
 
205
    homepath = os.environ.get('HOMEPATH')
223
206
    if homepath is not None:
224
 
        return os.path.join(get_environ_unicode('HOMEDIR', ''), home)
 
207
        return os.path.join(os.environ.get('HOMEDIR', ''), home)
225
208
    # at least return windows root directory
226
 
    windir = get_environ_unicode('WINDIR')
 
209
    windir = os.environ.get('WINDIR')
227
210
    if windir:
228
211
        return os.path.splitdrive(windir)[0] + '/'
229
212
    # otherwise C:\ is good enough for 98% users
234
217
    """Return user name as login name.
235
218
    If name cannot be obtained return None.
236
219
    """
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
 
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
248
230
    # otherwise try env variables
249
 
    return get_environ_unicode('USERNAME')
 
231
    return os.environ.get('USERNAME')
250
232
 
251
233
 
252
234
# 1 == ComputerNameDnsHostname, which returns "The DNS host name of the local
260
242
 
261
243
    :return: A unicode string representing the host name.
262
244
    """
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)
 
245
    import ctypes
 
246
    buf = ctypes.create_unicode_buffer(MAX_COMPUTERNAME_LENGTH + 1)
 
247
    n = ctypes.c_int(MAX_COMPUTERNAME_LENGTH + 1)
271
248
 
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')
 
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')
279
257
 
280
258
 
281
259
def _ensure_with_dir(path):
365
343
 
366
344
    if type_id == REG_SZ:
367
345
        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
373
346
    return appname
374
347
 
375
348
 
376
349
def set_file_attr_hidden(path):
377
350
    """Set file attributes to hidden if possible"""
378
 
    if not has_ctypes_win32:
379
 
        return
380
 
    from ctypes.wintypes import BOOL, DWORD, LPCWSTR
381
 
    _kernel32 = ctypes.windll.kernel32
 
351
    from ctypes.wintypes import BOOL, DWORD, LPWSTR
 
352
    import ctypes
382
353
    # <https://docs.microsoft.com/windows/desktop/api/fileapi/nf-fileapi-setfileattributesw>
383
 
    _SetFileAttributesW = ctypes.WINFUNCTYPE(BOOL, LPCWSTR, DWORD)(
384
 
        ("SetFileAttributesW", _kernel32))
 
354
    SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW
 
355
    SetFileAttributes.argtypes = LPWSTR, DWORD
 
356
    SetFileAttributes.restype = BOOL
385
357
    FILE_ATTRIBUTE_HIDDEN = 2
386
358
    if not SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN):
387
359
        e = ctypes.WinError()
431
403
    return args
432
404
 
433
405
 
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
 
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