##// END OF EJS Templates
win32: remove useless lstat() fallback in nlinks()...
Patrick Mezard -
r11992:ccd8e592 stable
parent child Browse files
Show More
@@ -1,205 +1,195 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,
35 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
35 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
36 None, win32file.OPEN_EXISTING, 0, None)
36 None, win32file.OPEN_EXISTING, 0, None)
37 try:
38 return win32file.GetFileInformationByHandle(fh)
39 finally:
40 fh.Close()
41 except pywintypes.error:
37 except pywintypes.error:
42 return None
38 raise OSError(errno.ENOENT, 'The system cannot find the file specified')
39 try:
40 return win32file.GetFileInformationByHandle(fh)
41 finally:
42 fh.Close()
43
43
44 def nlinks(pathname):
44 def nlinks(pathname):
45 """Return number of hardlinks for the given file."""
45 """Return number of hardlinks for the given file."""
46 res = _getfileinfo(pathname)
46 links = _getfileinfo(pathname)[7]
47 if res is not None:
48 links = res[7]
49 else:
50 links = os.lstat(pathname).st_nlink
51 if links < 2:
47 if links < 2:
52 # Known to be wrong for most network drives
48 # Known to be wrong for most network drives
53 dirname = os.path.dirname(pathname)
49 dirname = os.path.dirname(pathname)
54 if not dirname:
50 if not dirname:
55 dirname = '.'
51 dirname = '.'
56 dt = win32file.GetDriveType(dirname + '\\')
52 dt = win32file.GetDriveType(dirname + '\\')
57 if dt == 4 or dt == 1:
53 if dt == 4 or dt == 1:
58 # Fake hardlink to force COW for network drives
54 # Fake hardlink to force COW for network drives
59 links = 2
55 links = 2
60 return links
56 return links
61
57
62 def samefile(fpath1, fpath2):
58 def samefile(fpath1, fpath2):
63 """Returns whether fpath1 and fpath2 refer to the same file. This is only
59 """Returns whether fpath1 and fpath2 refer to the same file. This is only
64 guaranteed to work for files, not directories."""
60 guaranteed to work for files, not directories."""
65 res1 = _getfileinfo(fpath1)
61 res1 = _getfileinfo(fpath1)
66 res2 = _getfileinfo(fpath2)
62 res2 = _getfileinfo(fpath2)
67 if res1 is not None and res2 is not None:
63 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
68 # Index 4 is the volume serial number, and 8 and 9 contain the file ID
64 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
69 return res1[4] == res2[4] and res1[8] == res2[8] and res1[9] == res2[9]
70 else:
71 return False
72
65
73 def samedevice(fpath1, fpath2):
66 def samedevice(fpath1, fpath2):
74 """Returns whether fpath1 and fpath2 are on the same device. This is only
67 """Returns whether fpath1 and fpath2 are on the same device. This is only
75 guaranteed to work for files, not directories."""
68 guaranteed to work for files, not directories."""
76 res1 = _getfileinfo(fpath1)
69 res1 = _getfileinfo(fpath1)
77 res2 = _getfileinfo(fpath2)
70 res2 = _getfileinfo(fpath2)
78 if res1 is not None and res2 is not None:
71 return res1[4] == res2[4]
79 return res1[4] == res2[4]
80 else:
81 return False
82
72
83 def testpid(pid):
73 def testpid(pid):
84 '''return True if pid is still running or unable to
74 '''return True if pid is still running or unable to
85 determine, False otherwise'''
75 determine, False otherwise'''
86 try:
76 try:
87 handle = win32api.OpenProcess(
77 handle = win32api.OpenProcess(
88 win32con.PROCESS_QUERY_INFORMATION, False, pid)
78 win32con.PROCESS_QUERY_INFORMATION, False, pid)
89 if handle:
79 if handle:
90 status = win32process.GetExitCodeProcess(handle)
80 status = win32process.GetExitCodeProcess(handle)
91 return status == win32con.STILL_ACTIVE
81 return status == win32con.STILL_ACTIVE
92 except pywintypes.error, details:
82 except pywintypes.error, details:
93 return details[0] != winerror.ERROR_INVALID_PARAMETER
83 return details[0] != winerror.ERROR_INVALID_PARAMETER
94 return True
84 return True
95
85
96 def lookup_reg(key, valname=None, scope=None):
86 def lookup_reg(key, valname=None, scope=None):
97 ''' Look up a key/value name in the Windows registry.
87 ''' Look up a key/value name in the Windows registry.
98
88
99 valname: value name. If unspecified, the default value for the key
89 valname: value name. If unspecified, the default value for the key
100 is used.
90 is used.
101 scope: optionally specify scope for registry lookup, this can be
91 scope: optionally specify scope for registry lookup, this can be
102 a sequence of scopes to look up in order. Default (CURRENT_USER,
92 a sequence of scopes to look up in order. Default (CURRENT_USER,
103 LOCAL_MACHINE).
93 LOCAL_MACHINE).
104 '''
94 '''
105 try:
95 try:
106 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
96 from _winreg import HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE, \
107 QueryValueEx, OpenKey
97 QueryValueEx, OpenKey
108 except ImportError:
98 except ImportError:
109 return None
99 return None
110
100
111 if scope is None:
101 if scope is None:
112 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
102 scope = (HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE)
113 elif not isinstance(scope, (list, tuple)):
103 elif not isinstance(scope, (list, tuple)):
114 scope = (scope,)
104 scope = (scope,)
115 for s in scope:
105 for s in scope:
116 try:
106 try:
117 val = QueryValueEx(OpenKey(s, key), valname)[0]
107 val = QueryValueEx(OpenKey(s, key), valname)[0]
118 # never let a Unicode string escape into the wild
108 # never let a Unicode string escape into the wild
119 return encoding.tolocal(val.encode('UTF-8'))
109 return encoding.tolocal(val.encode('UTF-8'))
120 except EnvironmentError:
110 except EnvironmentError:
121 pass
111 pass
122
112
123 def system_rcpath_win32():
113 def system_rcpath_win32():
124 '''return default os-specific hgrc search path'''
114 '''return default os-specific hgrc search path'''
125 proc = win32api.GetCurrentProcess()
115 proc = win32api.GetCurrentProcess()
126 try:
116 try:
127 # This will fail on windows < NT
117 # This will fail on windows < NT
128 filename = win32process.GetModuleFileNameEx(proc, 0)
118 filename = win32process.GetModuleFileNameEx(proc, 0)
129 except:
119 except:
130 filename = win32api.GetModuleFileName(0)
120 filename = win32api.GetModuleFileName(0)
131 # Use mercurial.ini found in directory with hg.exe
121 # Use mercurial.ini found in directory with hg.exe
132 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
122 progrc = os.path.join(os.path.dirname(filename), 'mercurial.ini')
133 if os.path.isfile(progrc):
123 if os.path.isfile(progrc):
134 return [progrc]
124 return [progrc]
135 # Use hgrc.d found in directory with hg.exe
125 # Use hgrc.d found in directory with hg.exe
136 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
126 progrcd = os.path.join(os.path.dirname(filename), 'hgrc.d')
137 if os.path.isdir(progrcd):
127 if os.path.isdir(progrcd):
138 rcpath = []
128 rcpath = []
139 for f, kind in osutil.listdir(progrcd):
129 for f, kind in osutil.listdir(progrcd):
140 if f.endswith('.rc'):
130 if f.endswith('.rc'):
141 rcpath.append(os.path.join(progrcd, f))
131 rcpath.append(os.path.join(progrcd, f))
142 return rcpath
132 return rcpath
143 # else look for a system rcpath in the registry
133 # else look for a system rcpath in the registry
144 try:
134 try:
145 value = win32api.RegQueryValue(
135 value = win32api.RegQueryValue(
146 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
136 win32con.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Mercurial')
147 rcpath = []
137 rcpath = []
148 for p in value.split(os.pathsep):
138 for p in value.split(os.pathsep):
149 if p.lower().endswith('mercurial.ini'):
139 if p.lower().endswith('mercurial.ini'):
150 rcpath.append(p)
140 rcpath.append(p)
151 elif os.path.isdir(p):
141 elif os.path.isdir(p):
152 for f, kind in osutil.listdir(p):
142 for f, kind in osutil.listdir(p):
153 if f.endswith('.rc'):
143 if f.endswith('.rc'):
154 rcpath.append(os.path.join(p, f))
144 rcpath.append(os.path.join(p, f))
155 return rcpath
145 return rcpath
156 except pywintypes.error:
146 except pywintypes.error:
157 return []
147 return []
158
148
159 def user_rcpath_win32():
149 def user_rcpath_win32():
160 '''return os-specific hgrc search path to the user dir'''
150 '''return os-specific hgrc search path to the user dir'''
161 userdir = os.path.expanduser('~')
151 userdir = os.path.expanduser('~')
162 if sys.getwindowsversion()[3] != 2 and userdir == '~':
152 if sys.getwindowsversion()[3] != 2 and userdir == '~':
163 # We are on win < nt: fetch the APPDATA directory location and use
153 # We are on win < nt: fetch the APPDATA directory location and use
164 # the parent directory as the user home dir.
154 # the parent directory as the user home dir.
165 appdir = shell.SHGetPathFromIDList(
155 appdir = shell.SHGetPathFromIDList(
166 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
156 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
167 userdir = os.path.dirname(appdir)
157 userdir = os.path.dirname(appdir)
168 return [os.path.join(userdir, 'mercurial.ini'),
158 return [os.path.join(userdir, 'mercurial.ini'),
169 os.path.join(userdir, '.hgrc')]
159 os.path.join(userdir, '.hgrc')]
170
160
171 def getuser():
161 def getuser():
172 '''return name of current user'''
162 '''return name of current user'''
173 return win32api.GetUserName()
163 return win32api.GetUserName()
174
164
175 def set_signal_handler_win32():
165 def set_signal_handler_win32():
176 """Register a termination handler for console events including
166 """Register a termination handler for console events including
177 CTRL+C. python signal handlers do not work well with socket
167 CTRL+C. python signal handlers do not work well with socket
178 operations.
168 operations.
179 """
169 """
180 def handler(event):
170 def handler(event):
181 win32process.ExitProcess(1)
171 win32process.ExitProcess(1)
182 win32api.SetConsoleCtrlHandler(handler)
172 win32api.SetConsoleCtrlHandler(handler)
183
173
184 def hidewindow():
174 def hidewindow():
185 def callback(*args, **kwargs):
175 def callback(*args, **kwargs):
186 hwnd, pid = args
176 hwnd, pid = args
187 wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
177 wpid = win32process.GetWindowThreadProcessId(hwnd)[1]
188 if pid == wpid:
178 if pid == wpid:
189 win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
179 win32gui.ShowWindow(hwnd, win32con.SW_HIDE)
190
180
191 pid = win32process.GetCurrentProcessId()
181 pid = win32process.GetCurrentProcessId()
192 win32gui.EnumWindows(callback, pid)
182 win32gui.EnumWindows(callback, pid)
193
183
194 def termwidth_():
184 def termwidth_():
195 try:
185 try:
196 # Query stderr to avoid problems with redirections
186 # Query stderr to avoid problems with redirections
197 screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
187 screenbuf = win32console.GetStdHandle(win32console.STD_ERROR_HANDLE)
198 try:
188 try:
199 window = screenbuf.GetConsoleScreenBufferInfo()['Window']
189 window = screenbuf.GetConsoleScreenBufferInfo()['Window']
200 width = window.Right - window.Left
190 width = window.Right - window.Left
201 return width
191 return width
202 finally:
192 finally:
203 screenbuf.Detach()
193 screenbuf.Detach()
204 except pywintypes.error:
194 except pywintypes.error:
205 return 79
195 return 79
General Comments 0
You need to be logged in to leave comments. Login now