/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-05-24 00:39:50 UTC
  • mto: This revision was merged to the branch mainline in revision 7504.
  • Revision ID: jelmer@jelmer.uk-20200524003950-bbc545r76vc5yajg
Add github action.

Show diffs side-by-side

added added

removed removed

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