2009-04-26 03:13:08 +04:00
|
|
|
# win32.py - utility functions that use win32 API
|
|
|
|
#
|
|
|
|
# Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
|
|
|
|
#
|
|
|
|
# This software may be used and distributed according to the terms of the
|
2010-01-20 07:20:08 +03:00
|
|
|
# GNU General Public License version 2 or any later version.
|
2009-04-26 03:24:49 +04:00
|
|
|
|
2015-08-09 04:52:59 +03:00
|
|
|
from __future__ import absolute_import
|
|
|
|
|
|
|
|
import ctypes
|
|
|
|
import errno
|
|
|
|
import msvcrt
|
|
|
|
import os
|
|
|
|
import random
|
|
|
|
import subprocess
|
2009-04-26 03:24:49 +04:00
|
|
|
|
2016-12-21 23:24:17 +03:00
|
|
|
from . import (
|
|
|
|
encoding,
|
|
|
|
pycompat,
|
|
|
|
)
|
2016-12-17 23:36:00 +03:00
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
_kernel32 = ctypes.windll.kernel32
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
_advapi32 = ctypes.windll.advapi32
|
|
|
|
_user32 = ctypes.windll.user32
|
2006-04-09 01:12:43 +04:00
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
_BOOL = ctypes.c_long
|
|
|
|
_WORD = ctypes.c_ushort
|
|
|
|
_DWORD = ctypes.c_ulong
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
_UINT = ctypes.c_uint
|
|
|
|
_LONG = ctypes.c_long
|
2011-02-14 13:12:26 +03:00
|
|
|
_LPCSTR = _LPSTR = ctypes.c_char_p
|
|
|
|
_HANDLE = ctypes.c_void_p
|
|
|
|
_HWND = _HANDLE
|
2006-04-09 01:12:43 +04:00
|
|
|
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
|
2006-04-09 01:12:43 +04:00
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
# GetLastError
|
|
|
|
_ERROR_SUCCESS = 0
|
2014-04-29 07:35:50 +04:00
|
|
|
_ERROR_NO_MORE_FILES = 18
|
2011-02-14 13:12:26 +03:00
|
|
|
_ERROR_INVALID_PARAMETER = 87
|
2015-04-08 05:30:25 +03:00
|
|
|
_ERROR_BROKEN_PIPE = 109
|
2011-02-14 13:12:26 +03:00
|
|
|
_ERROR_INSUFFICIENT_BUFFER = 122
|
|
|
|
|
|
|
|
# WPARAM is defined as UINT_PTR (unsigned type)
|
|
|
|
# LPARAM is defined as LONG_PTR (signed type)
|
|
|
|
if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
|
|
|
|
_WPARAM = ctypes.c_ulong
|
|
|
|
_LPARAM = ctypes.c_long
|
|
|
|
elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
|
|
|
|
_WPARAM = ctypes.c_ulonglong
|
|
|
|
_LPARAM = ctypes.c_longlong
|
|
|
|
|
|
|
|
class _FILETIME(ctypes.Structure):
|
|
|
|
_fields_ = [('dwLowDateTime', _DWORD),
|
|
|
|
('dwHighDateTime', _DWORD)]
|
|
|
|
|
|
|
|
class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
|
|
|
|
_fields_ = [('dwFileAttributes', _DWORD),
|
|
|
|
('ftCreationTime', _FILETIME),
|
|
|
|
('ftLastAccessTime', _FILETIME),
|
|
|
|
('ftLastWriteTime', _FILETIME),
|
|
|
|
('dwVolumeSerialNumber', _DWORD),
|
|
|
|
('nFileSizeHigh', _DWORD),
|
|
|
|
('nFileSizeLow', _DWORD),
|
|
|
|
('nNumberOfLinks', _DWORD),
|
|
|
|
('nFileIndexHigh', _DWORD),
|
|
|
|
('nFileIndexLow', _DWORD)]
|
|
|
|
|
2013-04-15 03:37:23 +04:00
|
|
|
# CreateFile
|
2011-02-14 13:12:26 +03:00
|
|
|
_FILE_SHARE_READ = 0x00000001
|
|
|
|
_FILE_SHARE_WRITE = 0x00000002
|
|
|
|
_FILE_SHARE_DELETE = 0x00000004
|
|
|
|
|
|
|
|
_OPEN_EXISTING = 3
|
|
|
|
|
2012-06-14 13:03:20 +04:00
|
|
|
_FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
|
|
|
|
|
2011-03-27 04:47:58 +04:00
|
|
|
# SetFileAttributes
|
|
|
|
_FILE_ATTRIBUTE_NORMAL = 0x80
|
2011-03-28 17:54:22 +04:00
|
|
|
_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
|
2011-03-27 04:47:58 +04:00
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
# Process Security and Access Rights
|
|
|
|
_PROCESS_QUERY_INFORMATION = 0x0400
|
|
|
|
|
|
|
|
# GetExitCodeProcess
|
|
|
|
_STILL_ACTIVE = 259
|
|
|
|
|
|
|
|
class _STARTUPINFO(ctypes.Structure):
|
|
|
|
_fields_ = [('cb', _DWORD),
|
|
|
|
('lpReserved', _LPSTR),
|
|
|
|
('lpDesktop', _LPSTR),
|
|
|
|
('lpTitle', _LPSTR),
|
|
|
|
('dwX', _DWORD),
|
|
|
|
('dwY', _DWORD),
|
|
|
|
('dwXSize', _DWORD),
|
|
|
|
('dwYSize', _DWORD),
|
|
|
|
('dwXCountChars', _DWORD),
|
|
|
|
('dwYCountChars', _DWORD),
|
|
|
|
('dwFillAttribute', _DWORD),
|
|
|
|
('dwFlags', _DWORD),
|
|
|
|
('wShowWindow', _WORD),
|
|
|
|
('cbReserved2', _WORD),
|
|
|
|
('lpReserved2', ctypes.c_char_p),
|
|
|
|
('hStdInput', _HANDLE),
|
|
|
|
('hStdOutput', _HANDLE),
|
|
|
|
('hStdError', _HANDLE)]
|
|
|
|
|
|
|
|
class _PROCESS_INFORMATION(ctypes.Structure):
|
|
|
|
_fields_ = [('hProcess', _HANDLE),
|
|
|
|
('hThread', _HANDLE),
|
|
|
|
('dwProcessId', _DWORD),
|
|
|
|
('dwThreadId', _DWORD)]
|
|
|
|
|
2012-06-25 21:11:29 +04:00
|
|
|
_CREATE_NO_WINDOW = 0x08000000
|
2011-02-14 13:12:26 +03:00
|
|
|
_SW_HIDE = 0
|
|
|
|
|
|
|
|
class _COORD(ctypes.Structure):
|
|
|
|
_fields_ = [('X', ctypes.c_short),
|
|
|
|
('Y', ctypes.c_short)]
|
|
|
|
|
|
|
|
class _SMALL_RECT(ctypes.Structure):
|
|
|
|
_fields_ = [('Left', ctypes.c_short),
|
|
|
|
('Top', ctypes.c_short),
|
|
|
|
('Right', ctypes.c_short),
|
|
|
|
('Bottom', ctypes.c_short)]
|
|
|
|
|
|
|
|
class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
|
|
|
|
_fields_ = [('dwSize', _COORD),
|
|
|
|
('dwCursorPosition', _COORD),
|
|
|
|
('wAttributes', _WORD),
|
|
|
|
('srWindow', _SMALL_RECT),
|
|
|
|
('dwMaximumWindowSize', _COORD)]
|
|
|
|
|
2011-05-15 23:27:59 +04:00
|
|
|
_STD_ERROR_HANDLE = _DWORD(-12).value
|
2011-02-14 13:12:26 +03:00
|
|
|
|
2014-02-08 17:35:07 +04:00
|
|
|
# CreateToolhelp32Snapshot, Process32First, Process32Next
|
|
|
|
_TH32CS_SNAPPROCESS = 0x00000002
|
|
|
|
_MAX_PATH = 260
|
|
|
|
|
|
|
|
class _tagPROCESSENTRY32(ctypes.Structure):
|
|
|
|
_fields_ = [('dwsize', _DWORD),
|
|
|
|
('cntUsage', _DWORD),
|
|
|
|
('th32ProcessID', _DWORD),
|
|
|
|
('th32DefaultHeapID', ctypes.c_void_p),
|
|
|
|
('th32ModuleID', _DWORD),
|
|
|
|
('cntThreads', _DWORD),
|
|
|
|
('th32ParentProcessID', _DWORD),
|
|
|
|
('pcPriClassBase', _LONG),
|
|
|
|
('dwFlags', _DWORD),
|
|
|
|
('szExeFile', ctypes.c_char * _MAX_PATH)]
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
super(_tagPROCESSENTRY32, self).__init__()
|
|
|
|
self.dwsize = ctypes.sizeof(self)
|
|
|
|
|
|
|
|
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
# types of parameters of C functions used (required by pypy)
|
|
|
|
|
|
|
|
_kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
|
|
|
|
_DWORD, _DWORD, _HANDLE]
|
|
|
|
_kernel32.CreateFileA.restype = _HANDLE
|
|
|
|
|
|
|
|
_kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
|
|
|
|
_kernel32.GetFileInformationByHandle.restype = _BOOL
|
|
|
|
|
|
|
|
_kernel32.CloseHandle.argtypes = [_HANDLE]
|
|
|
|
_kernel32.CloseHandle.restype = _BOOL
|
|
|
|
|
2011-09-14 02:01:07 +04:00
|
|
|
try:
|
|
|
|
_kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
|
|
|
|
_kernel32.CreateHardLinkA.restype = _BOOL
|
|
|
|
except AttributeError:
|
|
|
|
pass
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
|
|
|
|
_kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
|
|
|
|
_kernel32.SetFileAttributesA.restype = _BOOL
|
|
|
|
|
|
|
|
_kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
|
|
|
|
_kernel32.OpenProcess.restype = _HANDLE
|
|
|
|
|
|
|
|
_kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
|
|
|
|
_kernel32.GetExitCodeProcess.restype = _BOOL
|
|
|
|
|
|
|
|
_kernel32.GetLastError.argtypes = []
|
|
|
|
_kernel32.GetLastError.restype = _DWORD
|
|
|
|
|
|
|
|
_kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
|
|
|
|
_kernel32.GetModuleFileNameA.restype = _DWORD
|
|
|
|
|
|
|
|
_kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
|
|
|
|
ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
|
|
|
|
ctypes.c_void_p]
|
|
|
|
_kernel32.CreateProcessA.restype = _BOOL
|
|
|
|
|
|
|
|
_kernel32.ExitProcess.argtypes = [_UINT]
|
|
|
|
_kernel32.ExitProcess.restype = None
|
|
|
|
|
|
|
|
_kernel32.GetCurrentProcessId.argtypes = []
|
|
|
|
_kernel32.GetCurrentProcessId.restype = _DWORD
|
|
|
|
|
|
|
|
_SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
|
|
|
|
_kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
|
|
|
|
_kernel32.SetConsoleCtrlHandler.restype = _BOOL
|
|
|
|
|
|
|
|
_kernel32.GetStdHandle.argtypes = [_DWORD]
|
|
|
|
_kernel32.GetStdHandle.restype = _HANDLE
|
|
|
|
|
|
|
|
_kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
|
|
|
|
_kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
|
|
|
|
|
|
|
|
_advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
|
|
|
|
_advapi32.GetUserNameA.restype = _BOOL
|
|
|
|
|
|
|
|
_user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
|
|
|
|
_user32.GetWindowThreadProcessId.restype = _DWORD
|
|
|
|
|
|
|
|
_user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
|
|
|
|
_user32.ShowWindow.restype = _BOOL
|
|
|
|
|
|
|
|
_WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
|
|
|
|
_user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
|
|
|
|
_user32.EnumWindows.restype = _BOOL
|
|
|
|
|
2014-02-08 17:35:07 +04:00
|
|
|
_kernel32.CreateToolhelp32Snapshot.argtypes = [_DWORD, _DWORD]
|
|
|
|
_kernel32.CreateToolhelp32Snapshot.restype = _BOOL
|
|
|
|
|
2015-04-08 05:30:25 +03:00
|
|
|
_kernel32.PeekNamedPipe.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD,
|
|
|
|
ctypes.c_void_p, ctypes.c_void_p, ctypes.c_void_p]
|
|
|
|
_kernel32.PeekNamedPipe.restype = _BOOL
|
|
|
|
|
2014-02-08 17:35:07 +04:00
|
|
|
_kernel32.Process32First.argtypes = [_HANDLE, ctypes.c_void_p]
|
|
|
|
_kernel32.Process32First.restype = _BOOL
|
|
|
|
|
|
|
|
_kernel32.Process32Next.argtypes = [_HANDLE, ctypes.c_void_p]
|
|
|
|
_kernel32.Process32Next.restype = _BOOL
|
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
def _raiseoserror(name):
|
|
|
|
err = ctypes.WinError()
|
|
|
|
raise OSError(err.errno, '%s: %s' % (name, err.strerror))
|
|
|
|
|
|
|
|
def _getfileinfo(name):
|
|
|
|
fh = _kernel32.CreateFileA(name, 0,
|
|
|
|
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
|
2012-06-14 13:03:20 +04:00
|
|
|
None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
|
2011-02-14 13:12:26 +03:00
|
|
|
if fh == _INVALID_HANDLE_VALUE:
|
|
|
|
_raiseoserror(name)
|
2010-08-20 00:51:09 +04:00
|
|
|
try:
|
2011-02-14 13:12:26 +03:00
|
|
|
fi = _BY_HANDLE_FILE_INFORMATION()
|
|
|
|
if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
|
|
|
|
_raiseoserror(name)
|
|
|
|
return fi
|
2010-08-20 00:51:09 +04:00
|
|
|
finally:
|
2011-02-14 13:12:26 +03:00
|
|
|
_kernel32.CloseHandle(fh)
|
|
|
|
|
2011-05-06 17:34:34 +04:00
|
|
|
def oslink(src, dst):
|
2011-04-22 00:08:48 +04:00
|
|
|
try:
|
|
|
|
if not _kernel32.CreateHardLinkA(dst, src, None):
|
|
|
|
_raiseoserror(src)
|
|
|
|
except AttributeError: # Wine doesn't support this function
|
2011-02-14 13:12:26 +03:00
|
|
|
_raiseoserror(src)
|
2010-01-08 16:18:39 +03:00
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
def nlinks(name):
|
|
|
|
'''return number of hardlinks for the given file'''
|
|
|
|
return _getfileinfo(name).nNumberOfLinks
|
2006-04-09 01:12:43 +04:00
|
|
|
|
2012-06-14 13:03:20 +04:00
|
|
|
def samefile(path1, path2):
|
|
|
|
'''Returns whether path1 and path2 refer to the same file or directory.'''
|
|
|
|
res1 = _getfileinfo(path1)
|
|
|
|
res2 = _getfileinfo(path2)
|
2011-02-14 13:12:26 +03:00
|
|
|
return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
|
|
|
|
and res1.nFileIndexHigh == res2.nFileIndexHigh
|
|
|
|
and res1.nFileIndexLow == res2.nFileIndexLow)
|
2010-01-08 16:18:39 +03:00
|
|
|
|
2012-06-14 13:03:20 +04:00
|
|
|
def samedevice(path1, path2):
|
|
|
|
'''Returns whether path1 and path2 are on the same device.'''
|
|
|
|
res1 = _getfileinfo(path1)
|
|
|
|
res2 = _getfileinfo(path2)
|
2011-02-14 13:12:26 +03:00
|
|
|
return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
|
2010-01-08 16:18:39 +03:00
|
|
|
|
2015-04-08 05:30:25 +03:00
|
|
|
def peekpipe(pipe):
|
|
|
|
handle = msvcrt.get_osfhandle(pipe.fileno())
|
|
|
|
avail = _DWORD()
|
|
|
|
|
|
|
|
if not _kernel32.PeekNamedPipe(handle, None, 0, None, ctypes.byref(avail),
|
|
|
|
None):
|
|
|
|
err = _kernel32.GetLastError()
|
|
|
|
if err == _ERROR_BROKEN_PIPE:
|
|
|
|
return 0
|
|
|
|
raise ctypes.WinError(err)
|
|
|
|
|
|
|
|
return avail.value
|
|
|
|
|
2006-04-09 01:12:43 +04:00
|
|
|
def testpid(pid):
|
|
|
|
'''return True if pid is still running or unable to
|
|
|
|
determine, False otherwise'''
|
2011-02-14 13:12:26 +03:00
|
|
|
h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
|
|
|
|
if h:
|
|
|
|
try:
|
|
|
|
status = _DWORD()
|
|
|
|
if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
|
|
|
|
return status.value == _STILL_ACTIVE
|
|
|
|
finally:
|
|
|
|
_kernel32.CloseHandle(h)
|
|
|
|
return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
|
2006-04-09 01:12:43 +04:00
|
|
|
|
2011-05-06 17:36:05 +04:00
|
|
|
def executablepath():
|
2011-02-14 13:12:31 +03:00
|
|
|
'''return full path of hg.exe'''
|
2011-02-14 13:12:26 +03:00
|
|
|
size = 600
|
|
|
|
buf = ctypes.create_string_buffer(size + 1)
|
|
|
|
len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
|
|
|
|
if len == 0:
|
2015-03-28 13:19:34 +03:00
|
|
|
raise ctypes.WinError() # Note: WinError is a function
|
2011-02-14 13:12:26 +03:00
|
|
|
elif len == size:
|
|
|
|
raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
|
2011-02-14 13:12:31 +03:00
|
|
|
return buf.value
|
|
|
|
|
2009-03-26 21:54:44 +03:00
|
|
|
def getuser():
|
|
|
|
'''return name of current user'''
|
2011-02-14 13:12:26 +03:00
|
|
|
size = _DWORD(300)
|
|
|
|
buf = ctypes.create_string_buffer(size.value + 1)
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
|
2015-03-23 02:08:13 +03:00
|
|
|
raise ctypes.WinError()
|
2011-02-14 13:12:26 +03:00
|
|
|
return buf.value
|
2007-06-21 23:58:18 +04:00
|
|
|
|
2011-05-06 17:41:04 +04:00
|
|
|
_signalhandler = []
|
2011-02-14 13:12:26 +03:00
|
|
|
|
2011-05-06 17:41:04 +04:00
|
|
|
def setsignalhandler():
|
2011-02-14 13:12:26 +03:00
|
|
|
'''Register a termination handler for console events including
|
2007-06-21 23:58:18 +04:00
|
|
|
CTRL+C. python signal handlers do not work well with socket
|
|
|
|
operations.
|
2011-02-14 13:12:26 +03:00
|
|
|
'''
|
2007-06-21 23:58:18 +04:00
|
|
|
def handler(event):
|
2011-02-14 13:12:26 +03:00
|
|
|
_kernel32.ExitProcess(1)
|
|
|
|
|
2011-05-06 17:41:04 +04:00
|
|
|
if _signalhandler:
|
2011-02-14 13:12:26 +03:00
|
|
|
return # already registered
|
|
|
|
h = _SIGNAL_HANDLER(handler)
|
2011-05-06 17:41:04 +04:00
|
|
|
_signalhandler.append(h) # needed to prevent garbage collection
|
2011-02-14 13:12:26 +03:00
|
|
|
if not _kernel32.SetConsoleCtrlHandler(h, True):
|
2015-03-23 02:08:13 +03:00
|
|
|
raise ctypes.WinError()
|
2011-02-14 13:12:26 +03:00
|
|
|
|
2010-01-10 20:13:34 +03:00
|
|
|
def hidewindow():
|
2011-02-14 13:12:26 +03:00
|
|
|
|
|
|
|
def callback(hwnd, pid):
|
|
|
|
wpid = _DWORD()
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
_user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
|
2011-02-14 13:12:26 +03:00
|
|
|
if pid == wpid.value:
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
_user32.ShowWindow(hwnd, _SW_HIDE)
|
2011-02-14 13:12:26 +03:00
|
|
|
return False # stop enumerating windows
|
|
|
|
return True
|
2010-01-10 20:13:34 +03:00
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
pid = _kernel32.GetCurrentProcessId()
|
win32.py: add argtypes and restype
This is a feature of ctypes. Without these, pypy complains with
RuntimeWarning: C function without declared arguments called
RuntimeWarning: C function without declared return type called
As a side effect of specifying restypes, the return value of e.g. CreateFileA
is now implicitly converted to an instance of _HANDLE, so we also need to
change the definition
_INVALID_HANDLE_VALUE = -1
to
_INVALID_HANDLE_VALUE = _HANDLE(-1).value
Otherwise, tests for equality to _INVALID_HANDLE_VALUE in code like
def _getfileinfo(name):
fh = _kernel32.CreateFileA(name, 0,
_FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
None, _OPEN_EXISTING, 0, None)
if fh == _INVALID_HANDLE_VALUE:
_raiseoserror(name)
would now fail to detect an invalid handle, which in turn would lead to
exceptions raised with wrong errno values, like e.g.
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 9] missing.txt: The handle is invalid.
instead of the correct (as per this patch and before it)
>>> nlinks('missing.txt')
Traceback (most recent call last):
...
OSError: [Errno 2] missing.txt: The system cannot find the file specified.
2011-05-15 23:33:51 +04:00
|
|
|
_user32.EnumWindows(_WNDENUMPROC(callback), pid)
|
2010-04-25 20:27:12 +04:00
|
|
|
|
2016-10-20 17:09:05 +03:00
|
|
|
def termsize():
|
2011-02-14 13:12:26 +03:00
|
|
|
# cmd.exe does not handle CR like a unix console, the CR is
|
|
|
|
# counted in the line length. On 80 columns consoles, if 80
|
|
|
|
# characters are written, the following CR won't apply on the
|
|
|
|
# current line but on the new one. Keep room for it.
|
2016-10-20 16:57:12 +03:00
|
|
|
width = 80 - 1
|
2016-10-20 17:09:05 +03:00
|
|
|
height = 25
|
2011-02-14 13:12:26 +03:00
|
|
|
# Query stderr to avoid problems with redirections
|
|
|
|
screenbuf = _kernel32.GetStdHandle(
|
|
|
|
_STD_ERROR_HANDLE) # don't close the handle returned
|
|
|
|
if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
|
2016-10-20 17:09:05 +03:00
|
|
|
return width, height
|
2011-02-14 13:12:26 +03:00
|
|
|
csbi = _CONSOLE_SCREEN_BUFFER_INFO()
|
|
|
|
if not _kernel32.GetConsoleScreenBufferInfo(
|
|
|
|
screenbuf, ctypes.byref(csbi)):
|
2016-10-20 17:09:05 +03:00
|
|
|
return width, height
|
2016-10-20 16:57:12 +03:00
|
|
|
width = csbi.srWindow.Right - csbi.srWindow.Left # don't '+ 1'
|
2016-10-20 17:09:05 +03:00
|
|
|
height = csbi.srWindow.Bottom - csbi.srWindow.Top + 1
|
|
|
|
return width, height
|
2011-02-14 13:12:26 +03:00
|
|
|
|
2014-02-08 17:35:07 +04:00
|
|
|
def _1stchild(pid):
|
|
|
|
'''return the 1st found child of the given pid
|
|
|
|
|
|
|
|
None is returned when no child is found'''
|
|
|
|
pe = _tagPROCESSENTRY32()
|
|
|
|
|
|
|
|
# create handle to list all processes
|
|
|
|
ph = _kernel32.CreateToolhelp32Snapshot(_TH32CS_SNAPPROCESS, 0)
|
|
|
|
if ph == _INVALID_HANDLE_VALUE:
|
2015-03-23 02:08:13 +03:00
|
|
|
raise ctypes.WinError()
|
2014-02-08 17:35:07 +04:00
|
|
|
try:
|
|
|
|
r = _kernel32.Process32First(ph, ctypes.byref(pe))
|
|
|
|
# loop over all processes
|
|
|
|
while r:
|
|
|
|
if pe.th32ParentProcessID == pid:
|
|
|
|
# return first child found
|
|
|
|
return pe.th32ProcessID
|
|
|
|
r = _kernel32.Process32Next(ph, ctypes.byref(pe))
|
|
|
|
finally:
|
|
|
|
_kernel32.CloseHandle(ph)
|
|
|
|
if _kernel32.GetLastError() != _ERROR_NO_MORE_FILES:
|
2015-03-23 02:08:13 +03:00
|
|
|
raise ctypes.WinError()
|
2014-02-08 17:35:07 +04:00
|
|
|
return None # no child found
|
|
|
|
|
|
|
|
class _tochildpid(int): # pid is _DWORD, which always matches in an int
|
|
|
|
'''helper for spawndetached, returns the child pid on conversion to string
|
|
|
|
|
|
|
|
Does not resolve the child pid immediately because the child may not yet be
|
|
|
|
started.
|
|
|
|
'''
|
|
|
|
def childpid(self):
|
|
|
|
'''returns the child pid of the first found child of the process
|
|
|
|
with this pid'''
|
|
|
|
return _1stchild(self)
|
|
|
|
def __str__(self):
|
|
|
|
# run when the pid is written to the file
|
|
|
|
ppid = self.childpid()
|
|
|
|
if ppid is None:
|
|
|
|
# race, child has exited since check
|
|
|
|
# fall back to this pid. Its process will also have disappeared,
|
|
|
|
# raising the same error type later as when the child pid would
|
|
|
|
# be returned.
|
|
|
|
return " %d" % self
|
|
|
|
return str(ppid)
|
|
|
|
|
2011-02-14 13:12:26 +03:00
|
|
|
def spawndetached(args):
|
|
|
|
# No standard library function really spawns a fully detached
|
|
|
|
# process under win32 because they allocate pipes or other objects
|
|
|
|
# to handle standard streams communications. Passing these objects
|
|
|
|
# to the child process requires handle inheritance to be enabled
|
|
|
|
# which makes really detached processes impossible.
|
|
|
|
si = _STARTUPINFO()
|
|
|
|
si.cb = ctypes.sizeof(_STARTUPINFO)
|
|
|
|
|
|
|
|
pi = _PROCESS_INFORMATION()
|
|
|
|
|
|
|
|
env = ''
|
2016-12-17 23:36:00 +03:00
|
|
|
for k in encoding.environ:
|
|
|
|
env += "%s=%s\0" % (k, encoding.environ[k])
|
2011-02-14 13:12:26 +03:00
|
|
|
if not env:
|
|
|
|
env = '\0'
|
|
|
|
env += '\0'
|
|
|
|
|
|
|
|
args = subprocess.list2cmdline(args)
|
2012-08-28 01:14:27 +04:00
|
|
|
# Not running the command in shell mode makes Python 2.6 hang when
|
2011-02-14 13:12:26 +03:00
|
|
|
# writing to hgweb output socket.
|
2016-12-17 23:36:00 +03:00
|
|
|
comspec = encoding.environ.get("COMSPEC", "cmd.exe")
|
2011-02-14 13:12:26 +03:00
|
|
|
args = comspec + " /c " + args
|
|
|
|
|
|
|
|
res = _kernel32.CreateProcessA(
|
2012-06-25 21:11:29 +04:00
|
|
|
None, args, None, None, False, _CREATE_NO_WINDOW,
|
2016-12-21 23:24:17 +03:00
|
|
|
env, pycompat.getcwd(), ctypes.byref(si), ctypes.byref(pi))
|
2011-02-14 13:12:26 +03:00
|
|
|
if not res:
|
2015-03-23 02:08:13 +03:00
|
|
|
raise ctypes.WinError()
|
2011-02-14 13:12:26 +03:00
|
|
|
|
2014-02-08 17:35:07 +04:00
|
|
|
# _tochildpid because the process is the child of COMSPEC
|
|
|
|
return _tochildpid(pi.dwProcessId)
|
2011-03-27 04:17:48 +04:00
|
|
|
|
|
|
|
def unlink(f):
|
|
|
|
'''try to implement POSIX' unlink semantics on Windows'''
|
|
|
|
|
2014-05-03 12:33:54 +04:00
|
|
|
if os.path.isdir(f):
|
|
|
|
# use EPERM because it is POSIX prescribed value, even though
|
|
|
|
# unlink(2) on directories returns EISDIR on Linux
|
|
|
|
raise IOError(errno.EPERM,
|
|
|
|
"Unlinking directory not permitted: '%s'" % f)
|
windows: check target type before actual unlinking to follow POSIX semantics
Creation and writing into target file via vfs (a.k.a opener) is done
after "unlink()" target file, if it exists.
For example, it is assumed that the revision X consists of file 'A',
and the revision Y consists of file 'A/B'. Merging revision X into Y
tries to "unlink()" on directory 'A' of 'A/B', before creation of file
'A'.
On POSIX environment, directories should be removed by "rmdir(2)", and
"unlink(2)" on directories fails. "unlink()" of Mercurial (and Python)
uses "unlink(2)" directly, so unlinking in the merge case above would
fail.
In the other hand, on Windows environment, "unlink()" of Mercurial
tries to rename before actual unlinking, to follow POSIX semantics:
already opened file can be unlinked safely.
This causes unexpected success in unlinking in the merge case above,
even though directory 'A' is renamed to another. This confuses users.
This patch checks whether target is directory or not before renaming,
and raises IOError(errno.EPERM) if so, to follow POSIX semantics.
2013-05-07 00:04:11 +04:00
|
|
|
|
2011-03-27 04:17:48 +04:00
|
|
|
# POSIX allows to unlink and rename open files. Windows has serious
|
|
|
|
# problems with doing that:
|
|
|
|
# - Calling os.unlink (or os.rename) on a file f fails if f or any
|
|
|
|
# hardlinked copy of f has been opened with Python's open(). There is no
|
|
|
|
# way such a file can be deleted or renamed on Windows (other than
|
|
|
|
# scheduling the delete or rename for the next reboot).
|
|
|
|
# - Calling os.unlink on a file that has been opened with Mercurial's
|
|
|
|
# posixfile (or comparable methods) will delay the actual deletion of
|
|
|
|
# the file for as long as the file is held open. The filename is blocked
|
|
|
|
# during that time and cannot be used for recreating a new file under
|
|
|
|
# that same name ("zombie file"). Directories containing such zombie files
|
|
|
|
# cannot be removed or moved.
|
|
|
|
# A file that has been opened with posixfile can be renamed, so we rename
|
|
|
|
# f to a random temporary name before calling os.unlink on it. This allows
|
|
|
|
# callers to recreate f immediately while having other readers do their
|
|
|
|
# implicit zombie filename blocking on a temporary name.
|
|
|
|
|
|
|
|
for tries in xrange(10):
|
|
|
|
temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
|
|
|
|
try:
|
|
|
|
os.rename(f, temp) # raises OSError EEXIST if temp exists
|
|
|
|
break
|
2015-06-24 08:20:08 +03:00
|
|
|
except OSError as e:
|
2011-03-27 04:17:48 +04:00
|
|
|
if e.errno != errno.EEXIST:
|
|
|
|
raise
|
|
|
|
else:
|
2013-01-01 22:50:23 +04:00
|
|
|
raise IOError(errno.EEXIST, "No usable temporary filename found")
|
2011-03-27 04:17:48 +04:00
|
|
|
|
|
|
|
try:
|
|
|
|
os.unlink(temp)
|
2011-03-27 04:47:58 +04:00
|
|
|
except OSError:
|
|
|
|
# The unlink might have failed because the READONLY attribute may heave
|
|
|
|
# been set on the original file. Rename works fine with READONLY set,
|
|
|
|
# but not os.unlink. Reset all attributes and try again.
|
|
|
|
_kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
|
|
|
|
try:
|
|
|
|
os.unlink(temp)
|
|
|
|
except OSError:
|
|
|
|
# The unlink might have failed due to some very rude AV-Scanners.
|
|
|
|
# Leaking a tempfile is the lesser evil than aborting here and
|
|
|
|
# leaving some potentially serious inconsistencies.
|
|
|
|
pass
|
2011-03-28 17:54:22 +04:00
|
|
|
|
|
|
|
def makedir(path, notindexed):
|
|
|
|
os.mkdir(path)
|
|
|
|
if notindexed:
|
|
|
|
_kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
|