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