##// END OF EJS Templates
win32: optimize parameters for the CreateFile call in _getfileinfo...
Adrian Buehlmann -
r13374:1c613c1a default
parent child Browse files
Show More
@@ -1,182 +1,183 b''
1 # win32.py - utility functions that use win32 API
1 # win32.py - utility functions that use win32 API
2 #
2 #
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
3 # Copyright 2005-2009 Matt Mackall <mpm@selenic.com> and others
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """Utility functions that use win32 API.
8 """Utility functions that use win32 API.
9
9
10 Mark Hammond's win32all package allows better functionality on
10 Mark Hammond's win32all package allows better functionality on
11 Windows. This module overrides definitions in util.py. If not
11 Windows. This module overrides definitions in util.py. If not
12 available, import of this module will fail, and generic code will be
12 available, import of this module will fail, and generic code will be
13 used.
13 used.
14 """
14 """
15
15
16 import win32api
16 import win32api
17
17
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
18 import errno, os, sys, pywintypes, win32con, win32file, win32process
19 import winerror, win32gui, win32console
19 import winerror, win32gui, win32console
20 import osutil, encoding
20 import osutil, encoding
21 from win32com.shell import shell, shellcon
21 from win32com.shell import shell, shellcon
22
22
23 def os_link(src, dst):
23 def os_link(src, dst):
24 try:
24 try:
25 win32file.CreateHardLink(dst, src)
25 win32file.CreateHardLink(dst, src)
26 except pywintypes.error:
26 except pywintypes.error:
27 raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
27 raise OSError(errno.EINVAL, 'target implements hardlinks improperly')
28 except NotImplementedError: # Another fake error win Win98
28 except NotImplementedError: # Another fake error win Win98
29 raise OSError(errno.EINVAL, 'Hardlinking not supported')
29 raise OSError(errno.EINVAL, 'Hardlinking not supported')
30
30
31 def _getfileinfo(pathname):
31 def _getfileinfo(pathname):
32 """Return number of hardlinks for the given file."""
32 """Return number of hardlinks for the given file."""
33 try:
33 try:
34 fh = win32file.CreateFile(pathname,
34 fh = win32file.CreateFile(pathname, 0,
35 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
35 win32file.FILE_SHARE_READ | win32file.FILE_SHARE_WRITE |
36 win32file.FILE_SHARE_DELETE,
36 None, win32file.OPEN_EXISTING, 0, None)
37 None, win32file.OPEN_EXISTING, 0, None)
37 except pywintypes.error:
38 except pywintypes.error:
38 raise OSError(errno.ENOENT, 'The system cannot find the file specified')
39 raise OSError(errno.ENOENT, 'The system cannot find the file specified')
39 try:
40 try:
40 return win32file.GetFileInformationByHandle(fh)
41 return win32file.GetFileInformationByHandle(fh)
41 finally:
42 finally:
42 fh.Close()
43 fh.Close()
43
44
44 def nlinks(pathname):
45 def nlinks(pathname):
45 """Return number of hardlinks for the given file."""
46 """Return number of hardlinks for the given file."""
46 return _getfileinfo(pathname)[7]
47 return _getfileinfo(pathname)[7]
47
48
48 def samefile(fpath1, fpath2):
49 def samefile(fpath1, fpath2):
49 """Returns whether fpath1 and fpath2 refer to the same file. This is only
50 """Returns whether fpath1 and fpath2 refer to the same file. This is only
50 guaranteed to work for files, not directories."""
51 guaranteed to work for files, not directories."""
51 res1 = _getfileinfo(fpath1)
52 res1 = _getfileinfo(fpath1)
52 res2 = _getfileinfo(fpath2)
53 res2 = _getfileinfo(fpath2)
53 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
54 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
54 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
55 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
55
56
56 def samedevice(fpath1, fpath2):
57 def samedevice(fpath1, fpath2):
57 """Returns whether fpath1 and fpath2 are on the same device. This is only
58 """Returns whether fpath1 and fpath2 are on the same device. This is only
58 guaranteed to work for files, not directories."""
59 guaranteed to work for files, not directories."""
59 res1 = _getfileinfo(fpath1)
60 res1 = _getfileinfo(fpath1)
60 res2 = _getfileinfo(fpath2)
61 res2 = _getfileinfo(fpath2)
61 return res1[4] == res2[4]
62 return res1[4] == res2[4]
62
63
63 def testpid(pid):
64 def testpid(pid):
64 '''return True if pid is still running or unable to
65 '''return True if pid is still running or unable to
65 determine, False otherwise'''
66 determine, False otherwise'''
66 try:
67 try:
67 handle = win32api.OpenProcess(
68 handle = win32api.OpenProcess(
68 win32con.PROCESS_QUERY_INFORMATION, False, pid)
69 win32con.PROCESS_QUERY_INFORMATION, False, pid)
69 if handle:
70 if handle:
70 status = win32process.GetExitCodeProcess(handle)
71 status = win32process.GetExitCodeProcess(handle)
71 return status == win32con.STILL_ACTIVE
72 return status == win32con.STILL_ACTIVE
72 except pywintypes.error, details:
73 except pywintypes.error, details:
73 return details[0] != winerror.ERROR_INVALID_PARAMETER
74 return details[0] != winerror.ERROR_INVALID_PARAMETER
74 return True
75 return True
75
76
76 def lookup_reg(key, valname=None, scope=None):
77 def lookup_reg(key, valname=None, scope=None):
77 ''' Look up a key/value name in the Windows registry.
78 ''' Look up a key/value name in the Windows registry.
78
79
79 valname: value name. If unspecified, the default value for the key
80 valname: value name. If unspecified, the default value for the key
80 is used.
81 is used.
81 scope: optionally specify scope for registry lookup, this can be
82 scope: optionally specify scope for registry lookup, this can be
82 a sequence of scopes to look up in order. Default (CURRENT_USER,
83 a sequence of scopes to look up in order. Default (CURRENT_USER,
83 LOCAL_MACHINE).
84 LOCAL_MACHINE).
84 '''
85 '''
85 try:
86 try:
86 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
87 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
87 QueryValueEx, OpenKey
88 QueryValueEx, OpenKey
88 except ImportError:
89 except ImportError:
89 return None
90 return None
90
91
91 if scope is None:
92 if scope is None:
92 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
93 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
93 elif not isinstance(scope, (list, tuple)):
94 elif not isinstance(scope, (list, tuple)):
94 scope = (scope,)
95 scope = (scope,)
95 for s in scope:
96 for s in scope:
96 try:
97 try:
97 val = QueryValueEx(OpenKey(s, key), valname)[0]
98 val = QueryValueEx(OpenKey(s, key), valname)[0]
98 # never let a Unicode string escape into the wild
99 # never let a Unicode string escape into the wild
99 return encoding.tolocal(val.encode('UTF-8'))
100 return encoding.tolocal(val.encode('UTF-8'))
100 except EnvironmentError:
101 except EnvironmentError:
101 pass
102 pass
102
103
103 def system_rcpath_win32():
104 def system_rcpath_win32():
104 '''return default os-specific hgrc search path'''
105 '''return default os-specific hgrc search path'''
105 filename = win32api.GetModuleFileName(0)
106 filename = win32api.GetModuleFileName(0)
106 # Use mercurial.ini found in directory with hg.exe
107 # Use mercurial.ini found in directory with hg.exe
107 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
108 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
108 if os.path.isfile(progrc):
109 if os.path.isfile(progrc):
109 return [progrc]
110 return [progrc]
110 # Use hgrc.d found in directory with hg.exe
111 # Use hgrc.d found in directory with hg.exe
111 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
112 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
112 if os.path.isdir(progrcd):
113 if os.path.isdir(progrcd):
113 rcpath = []
114 rcpath = []
114 for f, kind in osutil.listdir(progrcd):
115 for f, kind in osutil.listdir(progrcd):
115 if f.endswith('.rc'):
116 if f.endswith('.rc'):
116 rcpath.append(os.path.join(progrcd, f))
117 rcpath.append(os.path.join(progrcd, f))
117 return rcpath
118 return rcpath
118 # else look for a system rcpath in the registry
119 # else look for a system rcpath in the registry
119 try:
120 try:
120 value = win32api.RegQueryValue(
121 value = win32api.RegQueryValue(
121 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
122 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
122 rcpath = []
123 rcpath = []
123 for p in value.split(os.pathsep):
124 for p in value.split(os.pathsep):
124 if p.lower().endswith('mercurial.ini'):
125 if p.lower().endswith('mercurial.ini'):
125 rcpath.append(p)
126 rcpath.append(p)
126 elif os.path.isdir(p):
127 elif os.path.isdir(p):
127 for f, kind in osutil.listdir(p):
128 for f, kind in osutil.listdir(p):
128 if f.endswith('.rc'):
129 if f.endswith('.rc'):
129 rcpath.append(os.path.join(p, f))
130 rcpath.append(os.path.join(p, f))
130 return rcpath
131 return rcpath
131 except pywintypes.error:
132 except pywintypes.error:
132 return []
133 return []
133
134
134 def user_rcpath_win32():
135 def user_rcpath_win32():
135 '''return os-specific hgrc search path to the user dir'''
136 '''return os-specific hgrc search path to the user dir'''
136 userdir = os.path.expanduser('~')
137 userdir = os.path.expanduser('~')
137 if sys.getwindowsversion()[3] != 2 and userdir == '~':
138 if sys.getwindowsversion()[3] != 2 and userdir == '~':
138 # We are on win < nt: fetch the APPDATA directory location and use
139 # We are on win < nt: fetch the APPDATA directory location and use
139 # the parent directory as the user home dir.
140 # the parent directory as the user home dir.
140 appdir = shell.SHGetPathFromIDList(
141 appdir = shell.SHGetPathFromIDList(
141 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
142 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
142 userdir = os.path.dirname(appdir)
143 userdir = os.path.dirname(appdir)
143 return [os.path.join(userdir, 'mercurial.ini'),
144 return [os.path.join(userdir, 'mercurial.ini'),
144 os.path.join(userdir, '.hgrc')]
145 os.path.join(userdir, '.hgrc')]
145
146
146 def getuser():
147 def getuser():
147 '''return name of current user'''
148 '''return name of current user'''
148 return win32api.GetUserName()
149 return win32api.GetUserName()
149
150
150 def set_signal_handler_win32():
151 def set_signal_handler_win32():
151 """Register a termination handler for console events including
152 """Register a termination handler for console events including
152 CTRL+C. python signal handlers do not work well with socket
153 CTRL+C. python signal handlers do not work well with socket
153 operations.
154 operations.
154 """
155 """
155 def handler(event):
156 def handler(event):
156 win32process.ExitProcess(1)
157 win32process.ExitProcess(1)
157 win32api.SetConsoleCtrlHandler(handler)
158 win32api.SetConsoleCtrlHandler(handler)
158
159
159 def hidewindow():
160 def hidewindow():
160 def callback(*args, **kwargs):
161 def callback(*args, **kwargs):
161 hwnd, pid = args
162 hwnd, pid = args
162 wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
163 wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
163 if pid == wpid:
164 if pid == wpid:
164 win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
165 win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
165
166
166 pid = win32process.GetCurrentProcessId()
167 pid = win32process.GetCurrentProcessId()
167 win32gui.EnumWindows(callback, pid)
168 win32gui.EnumWindows(callback, pid)
168
169
169 def termwidth():
170 def termwidth():
170 try:
171 try:
171 # Query stderr to avoid problems with redirections
172 # Query stderr to avoid problems with redirections
172 screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
173 screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
173 if screenbuf is None:
174 if screenbuf is None:
174 return 79
175 return 79
175 try:
176 try:
176 window = screenbuf.GetConsoleScreenBufferInfo()['Window']
177 window = screenbuf.GetConsoleScreenBufferInfo()['Window']
177 width = window.Right - window.Left
178 width = window.Right - window.Left
178 return width
179 return width
179 finally:
180 finally:
180 screenbuf.Detach()
181 screenbuf.Detach()
181 except pywintypes.error:
182 except pywintypes.error:
182 return 79
183 return 79
General Comments 0
You need to be logged in to leave comments. Login now