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