##// END OF EJS Templates
win32: add missing definition of _ERROR_NO_MORE_FILES caught by pyflakes
Yuya Nishihara -
r21193:07f98258 stable
parent child Browse files
Show More
@@ -1,485 +1,486 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 import ctypes, errno, os, subprocess, random
9 9
10 10 _kernel32 = ctypes.windll.kernel32
11 11 _advapi32 = ctypes.windll.advapi32
12 12 _user32 = ctypes.windll.user32
13 13
14 14 _BOOL = ctypes.c_long
15 15 _WORD = ctypes.c_ushort
16 16 _DWORD = ctypes.c_ulong
17 17 _UINT = ctypes.c_uint
18 18 _LONG = ctypes.c_long
19 19 _LPCSTR = _LPSTR = ctypes.c_char_p
20 20 _HANDLE = ctypes.c_void_p
21 21 _HWND = _HANDLE
22 22
23 23 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
24 24
25 25 # GetLastError
26 26 _ERROR_SUCCESS = 0
27 _ERROR_NO_MORE_FILES = 18
27 28 _ERROR_SHARING_VIOLATION = 32
28 29 _ERROR_INVALID_PARAMETER = 87
29 30 _ERROR_INSUFFICIENT_BUFFER = 122
30 31
31 32 # WPARAM is defined as UINT_PTR (unsigned type)
32 33 # LPARAM is defined as LONG_PTR (signed type)
33 34 if ctypes.sizeof(ctypes.c_long) == ctypes.sizeof(ctypes.c_void_p):
34 35 _WPARAM = ctypes.c_ulong
35 36 _LPARAM = ctypes.c_long
36 37 elif ctypes.sizeof(ctypes.c_longlong) == ctypes.sizeof(ctypes.c_void_p):
37 38 _WPARAM = ctypes.c_ulonglong
38 39 _LPARAM = ctypes.c_longlong
39 40
40 41 class _FILETIME(ctypes.Structure):
41 42 _fields_ = [('dwLowDateTime', _DWORD),
42 43 ('dwHighDateTime', _DWORD)]
43 44
44 45 class _BY_HANDLE_FILE_INFORMATION(ctypes.Structure):
45 46 _fields_ = [('dwFileAttributes', _DWORD),
46 47 ('ftCreationTime', _FILETIME),
47 48 ('ftLastAccessTime', _FILETIME),
48 49 ('ftLastWriteTime', _FILETIME),
49 50 ('dwVolumeSerialNumber', _DWORD),
50 51 ('nFileSizeHigh', _DWORD),
51 52 ('nFileSizeLow', _DWORD),
52 53 ('nNumberOfLinks', _DWORD),
53 54 ('nFileIndexHigh', _DWORD),
54 55 ('nFileIndexLow', _DWORD)]
55 56
56 57 # CreateFile
57 58 _FILE_SHARE_READ = 0x00000001
58 59 _FILE_SHARE_WRITE = 0x00000002
59 60 _FILE_SHARE_DELETE = 0x00000004
60 61
61 62 _OPEN_EXISTING = 3
62 63
63 64 _FILE_FLAG_OPEN_REPARSE_POINT = 0x00200000
64 65 _FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
65 66 _FILE_FLAG_DELETE_ON_CLOSE = 0x04000000
66 67
67 68 # SetFileAttributes
68 69 _FILE_ATTRIBUTE_NORMAL = 0x80
69 70 _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED = 0x2000
70 71
71 72 # Process Security and Access Rights
72 73 _PROCESS_QUERY_INFORMATION = 0x0400
73 74
74 75 # GetExitCodeProcess
75 76 _STILL_ACTIVE = 259
76 77
77 78 class _STARTUPINFO(ctypes.Structure):
78 79 _fields_ = [('cb', _DWORD),
79 80 ('lpReserved', _LPSTR),
80 81 ('lpDesktop', _LPSTR),
81 82 ('lpTitle', _LPSTR),
82 83 ('dwX', _DWORD),
83 84 ('dwY', _DWORD),
84 85 ('dwXSize', _DWORD),
85 86 ('dwYSize', _DWORD),
86 87 ('dwXCountChars', _DWORD),
87 88 ('dwYCountChars', _DWORD),
88 89 ('dwFillAttribute', _DWORD),
89 90 ('dwFlags', _DWORD),
90 91 ('wShowWindow', _WORD),
91 92 ('cbReserved2', _WORD),
92 93 ('lpReserved2', ctypes.c_char_p),
93 94 ('hStdInput', _HANDLE),
94 95 ('hStdOutput', _HANDLE),
95 96 ('hStdError', _HANDLE)]
96 97
97 98 class _PROCESS_INFORMATION(ctypes.Structure):
98 99 _fields_ = [('hProcess', _HANDLE),
99 100 ('hThread', _HANDLE),
100 101 ('dwProcessId', _DWORD),
101 102 ('dwThreadId', _DWORD)]
102 103
103 104 _CREATE_NO_WINDOW = 0x08000000
104 105 _SW_HIDE = 0
105 106
106 107 class _COORD(ctypes.Structure):
107 108 _fields_ = [('X', ctypes.c_short),
108 109 ('Y', ctypes.c_short)]
109 110
110 111 class _SMALL_RECT(ctypes.Structure):
111 112 _fields_ = [('Left', ctypes.c_short),
112 113 ('Top', ctypes.c_short),
113 114 ('Right', ctypes.c_short),
114 115 ('Bottom', ctypes.c_short)]
115 116
116 117 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
117 118 _fields_ = [('dwSize', _COORD),
118 119 ('dwCursorPosition', _COORD),
119 120 ('wAttributes', _WORD),
120 121 ('srWindow', _SMALL_RECT),
121 122 ('dwMaximumWindowSize', _COORD)]
122 123
123 124 _STD_ERROR_HANDLE = _DWORD(-12).value
124 125
125 126 # CreateToolhelp32Snapshot, Process32First, Process32Next
126 127 _TH32CS_SNAPPROCESS = 0x00000002
127 128 _MAX_PATH = 260
128 129
129 130 class _tagPROCESSENTRY32(ctypes.Structure):
130 131 _fields_ = [('dwsize', _DWORD),
131 132 ('cntUsage', _DWORD),
132 133 ('th32ProcessID', _DWORD),
133 134 ('th32DefaultHeapID', ctypes.c_void_p),
134 135 ('th32ModuleID', _DWORD),
135 136 ('cntThreads', _DWORD),
136 137 ('th32ParentProcessID', _DWORD),
137 138 ('pcPriClassBase', _LONG),
138 139 ('dwFlags', _DWORD),
139 140 ('szExeFile', ctypes.c_char * _MAX_PATH)]
140 141
141 142 def __init__(self):
142 143 super(_tagPROCESSENTRY32, self).__init__()
143 144 self.dwsize = ctypes.sizeof(self)
144 145
145 146
146 147 # types of parameters of C functions used (required by pypy)
147 148
148 149 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
149 150 _DWORD, _DWORD, _HANDLE]
150 151 _kernel32.CreateFileA.restype = _HANDLE
151 152
152 153 _kernel32.GetFileInformationByHandle.argtypes = [_HANDLE, ctypes.c_void_p]
153 154 _kernel32.GetFileInformationByHandle.restype = _BOOL
154 155
155 156 _kernel32.CloseHandle.argtypes = [_HANDLE]
156 157 _kernel32.CloseHandle.restype = _BOOL
157 158
158 159 try:
159 160 _kernel32.CreateHardLinkA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p]
160 161 _kernel32.CreateHardLinkA.restype = _BOOL
161 162 except AttributeError:
162 163 pass
163 164
164 165 _kernel32.SetFileAttributesA.argtypes = [_LPCSTR, _DWORD]
165 166 _kernel32.SetFileAttributesA.restype = _BOOL
166 167
167 168 _kernel32.OpenProcess.argtypes = [_DWORD, _BOOL, _DWORD]
168 169 _kernel32.OpenProcess.restype = _HANDLE
169 170
170 171 _kernel32.GetExitCodeProcess.argtypes = [_HANDLE, ctypes.c_void_p]
171 172 _kernel32.GetExitCodeProcess.restype = _BOOL
172 173
173 174 _kernel32.GetLastError.argtypes = []
174 175 _kernel32.GetLastError.restype = _DWORD
175 176
176 177 _kernel32.GetModuleFileNameA.argtypes = [_HANDLE, ctypes.c_void_p, _DWORD]
177 178 _kernel32.GetModuleFileNameA.restype = _DWORD
178 179
179 180 _kernel32.CreateProcessA.argtypes = [_LPCSTR, _LPCSTR, ctypes.c_void_p,
180 181 ctypes.c_void_p, _BOOL, _DWORD, ctypes.c_void_p, _LPCSTR, ctypes.c_void_p,
181 182 ctypes.c_void_p]
182 183 _kernel32.CreateProcessA.restype = _BOOL
183 184
184 185 _kernel32.ExitProcess.argtypes = [_UINT]
185 186 _kernel32.ExitProcess.restype = None
186 187
187 188 _kernel32.GetCurrentProcessId.argtypes = []
188 189 _kernel32.GetCurrentProcessId.restype = _DWORD
189 190
190 191 _SIGNAL_HANDLER = ctypes.WINFUNCTYPE(_BOOL, _DWORD)
191 192 _kernel32.SetConsoleCtrlHandler.argtypes = [_SIGNAL_HANDLER, _BOOL]
192 193 _kernel32.SetConsoleCtrlHandler.restype = _BOOL
193 194
194 195 _kernel32.GetStdHandle.argtypes = [_DWORD]
195 196 _kernel32.GetStdHandle.restype = _HANDLE
196 197
197 198 _kernel32.GetConsoleScreenBufferInfo.argtypes = [_HANDLE, ctypes.c_void_p]
198 199 _kernel32.GetConsoleScreenBufferInfo.restype = _BOOL
199 200
200 201 _advapi32.GetUserNameA.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
201 202 _advapi32.GetUserNameA.restype = _BOOL
202 203
203 204 _user32.GetWindowThreadProcessId.argtypes = [_HANDLE, ctypes.c_void_p]
204 205 _user32.GetWindowThreadProcessId.restype = _DWORD
205 206
206 207 _user32.ShowWindow.argtypes = [_HANDLE, ctypes.c_int]
207 208 _user32.ShowWindow.restype = _BOOL
208 209
209 210 _WNDENUMPROC = ctypes.WINFUNCTYPE(_BOOL, _HWND, _LPARAM)
210 211 _user32.EnumWindows.argtypes = [_WNDENUMPROC, _LPARAM]
211 212 _user32.EnumWindows.restype = _BOOL
212 213
213 214 _kernel32.CreateToolhelp32Snapshot.argtypes = [_DWORD, _DWORD]
214 215 _kernel32.CreateToolhelp32Snapshot.restype = _BOOL
215 216
216 217 _kernel32.Process32First.argtypes = [_HANDLE, ctypes.c_void_p]
217 218 _kernel32.Process32First.restype = _BOOL
218 219
219 220 _kernel32.Process32Next.argtypes = [_HANDLE, ctypes.c_void_p]
220 221 _kernel32.Process32Next.restype = _BOOL
221 222
222 223 def _raiseoserror(name):
223 224 err = ctypes.WinError()
224 225 raise OSError(err.errno, '%s: %s' % (name, err.strerror))
225 226
226 227 def _getfileinfo(name):
227 228 fh = _kernel32.CreateFileA(name, 0,
228 229 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
229 230 None, _OPEN_EXISTING, _FILE_FLAG_BACKUP_SEMANTICS, None)
230 231 if fh == _INVALID_HANDLE_VALUE:
231 232 _raiseoserror(name)
232 233 try:
233 234 fi = _BY_HANDLE_FILE_INFORMATION()
234 235 if not _kernel32.GetFileInformationByHandle(fh, ctypes.byref(fi)):
235 236 _raiseoserror(name)
236 237 return fi
237 238 finally:
238 239 _kernel32.CloseHandle(fh)
239 240
240 241 def oslink(src, dst):
241 242 try:
242 243 if not _kernel32.CreateHardLinkA(dst, src, None):
243 244 _raiseoserror(src)
244 245 except AttributeError: # Wine doesn't support this function
245 246 _raiseoserror(src)
246 247
247 248 def nlinks(name):
248 249 '''return number of hardlinks for the given file'''
249 250 return _getfileinfo(name).nNumberOfLinks
250 251
251 252 def samefile(path1, path2):
252 253 '''Returns whether path1 and path2 refer to the same file or directory.'''
253 254 res1 = _getfileinfo(path1)
254 255 res2 = _getfileinfo(path2)
255 256 return (res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
256 257 and res1.nFileIndexHigh == res2.nFileIndexHigh
257 258 and res1.nFileIndexLow == res2.nFileIndexLow)
258 259
259 260 def samedevice(path1, path2):
260 261 '''Returns whether path1 and path2 are on the same device.'''
261 262 res1 = _getfileinfo(path1)
262 263 res2 = _getfileinfo(path2)
263 264 return res1.dwVolumeSerialNumber == res2.dwVolumeSerialNumber
264 265
265 266 def testpid(pid):
266 267 '''return True if pid is still running or unable to
267 268 determine, False otherwise'''
268 269 h = _kernel32.OpenProcess(_PROCESS_QUERY_INFORMATION, False, pid)
269 270 if h:
270 271 try:
271 272 status = _DWORD()
272 273 if _kernel32.GetExitCodeProcess(h, ctypes.byref(status)):
273 274 return status.value == _STILL_ACTIVE
274 275 finally:
275 276 _kernel32.CloseHandle(h)
276 277 return _kernel32.GetLastError() != _ERROR_INVALID_PARAMETER
277 278
278 279 def executablepath():
279 280 '''return full path of hg.exe'''
280 281 size = 600
281 282 buf = ctypes.create_string_buffer(size + 1)
282 283 len = _kernel32.GetModuleFileNameA(None, ctypes.byref(buf), size)
283 284 if len == 0:
284 285 raise ctypes.WinError
285 286 elif len == size:
286 287 raise ctypes.WinError(_ERROR_INSUFFICIENT_BUFFER)
287 288 return buf.value
288 289
289 290 def getuser():
290 291 '''return name of current user'''
291 292 size = _DWORD(300)
292 293 buf = ctypes.create_string_buffer(size.value + 1)
293 294 if not _advapi32.GetUserNameA(ctypes.byref(buf), ctypes.byref(size)):
294 295 raise ctypes.WinError
295 296 return buf.value
296 297
297 298 _signalhandler = []
298 299
299 300 def setsignalhandler():
300 301 '''Register a termination handler for console events including
301 302 CTRL+C. python signal handlers do not work well with socket
302 303 operations.
303 304 '''
304 305 def handler(event):
305 306 _kernel32.ExitProcess(1)
306 307
307 308 if _signalhandler:
308 309 return # already registered
309 310 h = _SIGNAL_HANDLER(handler)
310 311 _signalhandler.append(h) # needed to prevent garbage collection
311 312 if not _kernel32.SetConsoleCtrlHandler(h, True):
312 313 raise ctypes.WinError
313 314
314 315 def hidewindow():
315 316
316 317 def callback(hwnd, pid):
317 318 wpid = _DWORD()
318 319 _user32.GetWindowThreadProcessId(hwnd, ctypes.byref(wpid))
319 320 if pid == wpid.value:
320 321 _user32.ShowWindow(hwnd, _SW_HIDE)
321 322 return False # stop enumerating windows
322 323 return True
323 324
324 325 pid = _kernel32.GetCurrentProcessId()
325 326 _user32.EnumWindows(_WNDENUMPROC(callback), pid)
326 327
327 328 def termwidth():
328 329 # cmd.exe does not handle CR like a unix console, the CR is
329 330 # counted in the line length. On 80 columns consoles, if 80
330 331 # characters are written, the following CR won't apply on the
331 332 # current line but on the new one. Keep room for it.
332 333 width = 79
333 334 # Query stderr to avoid problems with redirections
334 335 screenbuf = _kernel32.GetStdHandle(
335 336 _STD_ERROR_HANDLE) # don't close the handle returned
336 337 if screenbuf is None or screenbuf == _INVALID_HANDLE_VALUE:
337 338 return width
338 339 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
339 340 if not _kernel32.GetConsoleScreenBufferInfo(
340 341 screenbuf, ctypes.byref(csbi)):
341 342 return width
342 343 width = csbi.srWindow.Right - csbi.srWindow.Left
343 344 return width
344 345
345 346 def _1stchild(pid):
346 347 '''return the 1st found child of the given pid
347 348
348 349 None is returned when no child is found'''
349 350 pe = _tagPROCESSENTRY32()
350 351
351 352 # create handle to list all processes
352 353 ph = _kernel32.CreateToolhelp32Snapshot(_TH32CS_SNAPPROCESS, 0)
353 354 if ph == _INVALID_HANDLE_VALUE:
354 355 raise ctypes.WinError
355 356 try:
356 357 r = _kernel32.Process32First(ph, ctypes.byref(pe))
357 358 # loop over all processes
358 359 while r:
359 360 if pe.th32ParentProcessID == pid:
360 361 # return first child found
361 362 return pe.th32ProcessID
362 363 r = _kernel32.Process32Next(ph, ctypes.byref(pe))
363 364 finally:
364 365 _kernel32.CloseHandle(ph)
365 366 if _kernel32.GetLastError() != _ERROR_NO_MORE_FILES:
366 367 raise ctypes.WinError
367 368 return None # no child found
368 369
369 370 class _tochildpid(int): # pid is _DWORD, which always matches in an int
370 371 '''helper for spawndetached, returns the child pid on conversion to string
371 372
372 373 Does not resolve the child pid immediately because the child may not yet be
373 374 started.
374 375 '''
375 376 def childpid(self):
376 377 '''returns the child pid of the first found child of the process
377 378 with this pid'''
378 379 return _1stchild(self)
379 380 def __str__(self):
380 381 # run when the pid is written to the file
381 382 ppid = self.childpid()
382 383 if ppid is None:
383 384 # race, child has exited since check
384 385 # fall back to this pid. Its process will also have disappeared,
385 386 # raising the same error type later as when the child pid would
386 387 # be returned.
387 388 return " %d" % self
388 389 return str(ppid)
389 390
390 391 def spawndetached(args):
391 392 # No standard library function really spawns a fully detached
392 393 # process under win32 because they allocate pipes or other objects
393 394 # to handle standard streams communications. Passing these objects
394 395 # to the child process requires handle inheritance to be enabled
395 396 # which makes really detached processes impossible.
396 397 si = _STARTUPINFO()
397 398 si.cb = ctypes.sizeof(_STARTUPINFO)
398 399
399 400 pi = _PROCESS_INFORMATION()
400 401
401 402 env = ''
402 403 for k in os.environ:
403 404 env += "%s=%s\0" % (k, os.environ[k])
404 405 if not env:
405 406 env = '\0'
406 407 env += '\0'
407 408
408 409 args = subprocess.list2cmdline(args)
409 410 # Not running the command in shell mode makes Python 2.6 hang when
410 411 # writing to hgweb output socket.
411 412 comspec = os.environ.get("COMSPEC", "cmd.exe")
412 413 args = comspec + " /c " + args
413 414
414 415 res = _kernel32.CreateProcessA(
415 416 None, args, None, None, False, _CREATE_NO_WINDOW,
416 417 env, os.getcwd(), ctypes.byref(si), ctypes.byref(pi))
417 418 if not res:
418 419 raise ctypes.WinError
419 420
420 421 # _tochildpid because the process is the child of COMSPEC
421 422 return _tochildpid(pi.dwProcessId)
422 423
423 424 def unlink(f):
424 425 '''try to implement POSIX' unlink semantics on Windows'''
425 426
426 427 # If we can open f exclusively, no other processes must have open handles
427 428 # for it and we can expect its name will be deleted immediately when we
428 429 # close the handle unless we have another in the same process. We also
429 430 # expect we shall simply fail to open f if it is a directory.
430 431 fh = _kernel32.CreateFileA(f, 0, 0, None, _OPEN_EXISTING,
431 432 _FILE_FLAG_OPEN_REPARSE_POINT | _FILE_FLAG_DELETE_ON_CLOSE, None)
432 433 if fh != _INVALID_HANDLE_VALUE:
433 434 _kernel32.CloseHandle(fh)
434 435 return
435 436 error = _kernel32.GetLastError()
436 437 if error != _ERROR_SHARING_VIOLATION:
437 438 raise ctypes.WinError(error)
438 439
439 440 # POSIX allows to unlink and rename open files. Windows has serious
440 441 # problems with doing that:
441 442 # - Calling os.unlink (or os.rename) on a file f fails if f or any
442 443 # hardlinked copy of f has been opened with Python's open(). There is no
443 444 # way such a file can be deleted or renamed on Windows (other than
444 445 # scheduling the delete or rename for the next reboot).
445 446 # - Calling os.unlink on a file that has been opened with Mercurial's
446 447 # posixfile (or comparable methods) will delay the actual deletion of
447 448 # the file for as long as the file is held open. The filename is blocked
448 449 # during that time and cannot be used for recreating a new file under
449 450 # that same name ("zombie file"). Directories containing such zombie files
450 451 # cannot be removed or moved.
451 452 # A file that has been opened with posixfile can be renamed, so we rename
452 453 # f to a random temporary name before calling os.unlink on it. This allows
453 454 # callers to recreate f immediately while having other readers do their
454 455 # implicit zombie filename blocking on a temporary name.
455 456
456 457 for tries in xrange(10):
457 458 temp = '%s-%08x' % (f, random.randint(0, 0xffffffff))
458 459 try:
459 460 os.rename(f, temp) # raises OSError EEXIST if temp exists
460 461 break
461 462 except OSError, e:
462 463 if e.errno != errno.EEXIST:
463 464 raise
464 465 else:
465 466 raise IOError(errno.EEXIST, "No usable temporary filename found")
466 467
467 468 try:
468 469 os.unlink(temp)
469 470 except OSError:
470 471 # The unlink might have failed because the READONLY attribute may heave
471 472 # been set on the original file. Rename works fine with READONLY set,
472 473 # but not os.unlink. Reset all attributes and try again.
473 474 _kernel32.SetFileAttributesA(temp, _FILE_ATTRIBUTE_NORMAL)
474 475 try:
475 476 os.unlink(temp)
476 477 except OSError:
477 478 # The unlink might have failed due to some very rude AV-Scanners.
478 479 # Leaking a tempfile is the lesser evil than aborting here and
479 480 # leaving some potentially serious inconsistencies.
480 481 pass
481 482
482 483 def makedir(path, notindexed):
483 484 os.mkdir(path)
484 485 if notindexed:
485 486 _kernel32.SetFileAttributesA(path, _FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
General Comments 0
You need to be logged in to leave comments. Login now