Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(75)

Side by Side Diff: client/utils/file_path.py

Issue 2949103004: Shuffle code around in file_path. (Closed)
Patch Set: . Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 # Copyright 2013 The LUCI Authors. All rights reserved. 1 # Copyright 2013 The LUCI Authors. All rights reserved.
2 # Use of this source code is governed under the Apache License, Version 2.0 2 # Use of this source code is governed under the Apache License, Version 2.0
3 # that can be found in the LICENSE file. 3 # that can be found in the LICENSE file.
4 4
5 """Provides functions: get_native_path_case(), isabs() and safe_join(). 5 """Provides functions: get_native_path_case(), isabs() and safe_join().
6 6
7 This module assumes that filesystem is not changing while current process 7 This module assumes that filesystem is not changing while current process
8 is running and thus it caches results of functions that depend on FS state. 8 is running and thus it caches results of functions that depend on FS state.
9 """ 9 """
10 10
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
239 # its group or that the current ACL permits this. Otherwise it will silently 239 # its group or that the current ACL permits this. Otherwise it will silently
240 # fail. 240 # fail.
241 win32security.SetFileSecurity( 241 win32security.SetFileSecurity(
242 fs.extend(path), win32security.DACL_SECURITY_INFORMATION, sd) 242 fs.extend(path), win32security.DACL_SECURITY_INFORMATION, sd)
243 # It's important to also look for the read only bit after, as it's possible 243 # It's important to also look for the read only bit after, as it's possible
244 # the set_read_only() call to remove the read only bit had silently failed 244 # the set_read_only() call to remove the read only bit had silently failed
245 # because there was no DACL for the user. 245 # because there was no DACL for the user.
246 if not (os.stat(path).st_mode & stat.S_IWUSR): 246 if not (os.stat(path).st_mode & stat.S_IWUSR):
247 os.chmod(path, 0777) 247 os.chmod(path, 0777)
248 248
249
249 def isabs(path): 250 def isabs(path):
250 """Accepts X: as an absolute path, unlike python's os.path.isabs().""" 251 """Accepts X: as an absolute path, unlike python's os.path.isabs()."""
251 return os.path.isabs(path) or len(path) == 2 and path[1] == ':' 252 return os.path.isabs(path) or len(path) == 2 and path[1] == ':'
252 253
253 254
254 def find_item_native_case(root, item): 255 def find_item_native_case(root, item):
255 """Gets the native path case of a single item based at root_path.""" 256 """Gets the native path case of a single item based at root_path."""
256 if item == '..': 257 if item == '..':
257 return item 258 return item
258 259
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 # The path does not exist. Try to recurse and reconstruct the path. 301 # The path does not exist. Try to recurse and reconstruct the path.
301 base = os.path.dirname(p) 302 base = os.path.dirname(p)
302 rest = os.path.basename(p) 303 rest = os.path.basename(p)
303 return os.path.join(get_native_path_case(base), rest) 304 return os.path.join(get_native_path_case(base), rest)
304 raise 305 raise
305 # Always upper case the first letter since GetLongPathName() will return the 306 # Always upper case the first letter since GetLongPathName() will return the
306 # drive letter in the case it was given. 307 # drive letter in the case it was given.
307 return out[0].upper() + out[1:] + suffix 308 return out[0].upper() + out[1:] + suffix
308 309
309 310
310 def enum_processes_win(): 311 def get_process_token():
312 """Get the current process token."""
313 TOKEN_ALL_ACCESS = 0xF01FF
314 token = ctypes.wintypes.HANDLE()
315 if not OpenProcessToken(
316 GetCurrentProcess(), TOKEN_ALL_ACCESS, ctypes.byref(token)):
317 # pylint: disable=undefined-variable
318 raise WindowsError('Couldn\'t get process token')
319 return token
320
321
322 def get_luid(name):
323 """Returns the LUID for a privilege."""
324 luid = LUID()
325 if not LookupPrivilegeValue(None, unicode(name), ctypes.byref(luid)):
326 # pylint: disable=undefined-variable
327 raise WindowsError('Couldn\'t lookup privilege value')
328 return luid
329
330
331 def enable_privilege(name):
332 """Enables the privilege for the current process token.
333
334 Returns:
335 - True if the assignment is successful.
336 """
337 SE_PRIVILEGE_ENABLED = 2
338 ERROR_NOT_ALL_ASSIGNED = 1300
339
340 size = ctypes.sizeof(TOKEN_PRIVILEGES) + ctypes.sizeof(LUID_AND_ATTRIBUTES)
341 buf = ctypes.create_string_buffer(size)
342 tp = ctypes.cast(buf, ctypes.POINTER(TOKEN_PRIVILEGES)).contents
343 tp.count = 1
344 tp.get_array()[0].LUID = get_luid(name)
345 tp.get_array()[0].Attributes = SE_PRIVILEGE_ENABLED
346 token = get_process_token()
347 try:
348 if not AdjustTokenPrivileges(token, False, tp, 0, None, None):
349 # pylint: disable=undefined-variable
350 raise WindowsError('Error in AdjustTokenPrivileges')
351 finally:
352 ctypes.windll.kernel32.CloseHandle(token)
353 return ctypes.windll.kernel32.GetLastError() != ERROR_NOT_ALL_ASSIGNED
354
355
356 def enable_symlink():
357 """Enable SeCreateSymbolicLinkPrivilege for the current token.
358
359 Returns:
360 - True if symlink support is enabled.
361
362 Thanks Microsoft. This is appreciated.
363 """
364 return enable_privilege(u'SeCreateSymbolicLinkPrivilege')
365
366
367 def kill_children_processes(root):
368 """Try to kill all children processes indistriminately and prints updates to
369 stderr.
370
371 Returns:
372 True if at least one child process was found.
373 """
374 processes = _get_children_processes_win(root)
375 if not processes:
376 return False
377 sys.stderr.write('Enumerating processes:\n')
378 for _, proc in sorted(processes.iteritems()):
379 sys.stderr.write(
380 '- pid %d; Handles: %d; Exe: %s; Cmd: %s\n' % (
381 proc.ProcessId,
382 proc.HandleCount,
383 proc.ExecutablePath,
384 proc.CommandLine))
385 sys.stderr.write('Terminating %d processes:\n' % len(processes))
386 for pid in sorted(processes):
387 try:
388 # Killing is asynchronous.
389 os.kill(pid, 9)
390 sys.stderr.write('- %d killed\n' % pid)
391 except OSError:
392 sys.stderr.write('- failed to kill %s\n' % pid)
393 return True
394
395
396 ## Windows private code.
397
398
399 def _enum_processes_win():
311 """Returns all processes on the system that are accessible to this process. 400 """Returns all processes on the system that are accessible to this process.
312 401
313 Returns: 402 Returns:
314 Win32_Process COM objects. See 403 Win32_Process COM objects. See
315 http://msdn.microsoft.com/library/aa394372.aspx for more details. 404 http://msdn.microsoft.com/library/aa394372.aspx for more details.
316 """ 405 """
317 import win32com.client # pylint: disable=F0401 406 import win32com.client # pylint: disable=F0401
318 wmi_service = win32com.client.Dispatch('WbemScripting.SWbemLocator') 407 wmi_service = win32com.client.Dispatch('WbemScripting.SWbemLocator')
319 wbem = wmi_service.ConnectServer('.', 'root\\cimv2') 408 wbem = wmi_service.ConnectServer('.', 'root\\cimv2')
320 return [proc for proc in wbem.ExecQuery('SELECT * FROM Win32_Process')] 409 return [proc for proc in wbem.ExecQuery('SELECT * FROM Win32_Process')]
321 410
322 411
323 def filter_processes_dir_win(processes, root_dir): 412 def _filter_processes_dir_win(processes, root_dir):
324 """Returns all processes which has their main executable located inside 413 """Returns all processes which has their main executable located inside
325 root_dir. 414 root_dir.
326 """ 415 """
327 def normalize_path(filename): 416 def normalize_path(filename):
328 try: 417 try:
329 return GetLongPathName(unicode(filename)).lower() 418 return GetLongPathName(unicode(filename)).lower()
330 except: # pylint: disable=W0702 419 except: # pylint: disable=W0702
331 return unicode(filename).lower() 420 return unicode(filename).lower()
332 421
333 root_dir = normalize_path(root_dir) 422 root_dir = normalize_path(root_dir)
(...skipping 11 matching lines...) Expand all
345 return None 434 return None
346 435
347 long_names = ((process_name(proc), proc) for proc in processes) 436 long_names = ((process_name(proc), proc) for proc in processes)
348 437
349 return [ 438 return [
350 proc for name, proc in long_names 439 proc for name, proc in long_names
351 if name is not None and name.startswith(root_dir) 440 if name is not None and name.startswith(root_dir)
352 ] 441 ]
353 442
354 443
355 def filter_processes_tree_win(processes): 444 def _filter_processes_tree_win(processes):
356 """Returns all the processes under the current process.""" 445 """Returns all the processes under the current process."""
357 # Convert to dict. 446 # Convert to dict.
358 processes = dict((p.ProcessId, p) for p in processes) 447 processes = dict((p.ProcessId, p) for p in processes)
359 root_pid = os.getpid() 448 root_pid = os.getpid()
360 out = {root_pid: processes[root_pid]} 449 out = {root_pid: processes[root_pid]}
361 while True: 450 while True:
362 found = set() 451 found = set()
363 for pid in out: 452 for pid in out:
364 found.update( 453 found.update(
365 p.ProcessId for p in processes.itervalues() 454 p.ProcessId for p in processes.itervalues()
366 if p.ParentProcessId == pid) 455 if p.ParentProcessId == pid)
367 found -= set(out) 456 found -= set(out)
368 if not found: 457 if not found:
369 break 458 break
370 out.update((p, processes[p]) for p in found) 459 out.update((p, processes[p]) for p in found)
371 return out.values() 460 return out.values()
372 461
373 462
374 def get_process_token(): 463 def _get_children_processes_win(root):
375 """Get the current process token.""" 464 """Returns a list of processes.
376 TOKEN_ALL_ACCESS = 0xF01FF
377 token = ctypes.wintypes.HANDLE()
378 if not OpenProcessToken(
379 GetCurrentProcess(), TOKEN_ALL_ACCESS, ctypes.byref(token)):
380 # pylint: disable=undefined-variable
381 raise WindowsError('Couldn\'t get process token')
382 return token
383 465
466 Enumerates both:
467 - all child processes from this process.
468 - processes where the main executable in inside 'root'. The reason is that
469 the ancestry may be broken so stray grand-children processes could be
470 undetected by the first technique.
384 471
385 def get_luid(name): 472 This technique is not fool-proof but gets mostly there.
386 """Returns the LUID for a privilege."""
387 luid = LUID()
388 if not LookupPrivilegeValue(None, unicode(name), ctypes.byref(luid)):
389 # pylint: disable=undefined-variable
390 raise WindowsError('Couldn\'t lookup privilege value')
391 return luid
392
393
394 def enable_privilege(name):
395 """Enables the privilege for the current process token.
396
397 Returns:
398 - True if the assignment is successful.
399 """ 473 """
400 SE_PRIVILEGE_ENABLED = 2 474 processes = _enum_processes_win()
401 ERROR_NOT_ALL_ASSIGNED = 1300 475 tree_processes = _filter_processes_tree_win(processes)
402 476 dir_processes = _filter_processes_dir_win(processes, root)
403 size = ctypes.sizeof(TOKEN_PRIVILEGES) + ctypes.sizeof(LUID_AND_ATTRIBUTES) 477 # Convert to dict to remove duplicates.
404 buf = ctypes.create_string_buffer(size) 478 processes = dict((p.ProcessId, p) for p in tree_processes)
405 tp = ctypes.cast(buf, ctypes.POINTER(TOKEN_PRIVILEGES)).contents 479 processes.update((p.ProcessId, p) for p in dir_processes)
406 tp.count = 1 480 processes.pop(os.getpid())
407 tp.get_array()[0].LUID = get_luid(name) 481 return processes
408 tp.get_array()[0].Attributes = SE_PRIVILEGE_ENABLED
409 token = get_process_token()
410 try:
411 if not AdjustTokenPrivileges(token, False, tp, 0, None, None):
412 # pylint: disable=undefined-variable
413 raise WindowsError('Error in AdjustTokenPrivileges')
414 finally:
415 ctypes.windll.kernel32.CloseHandle(token)
416 return ctypes.windll.kernel32.GetLastError() != ERROR_NOT_ALL_ASSIGNED
417
418
419 def enable_symlink():
420 """Enable SeCreateSymbolicLinkPrivilege for the current token.
421
422 Returns:
423 - True if symlink support is enabled.
424
425 Thanks Microsoft. This is appreciated.
426 """
427 return enable_privilege(u'SeCreateSymbolicLinkPrivilege')
428 482
429 483
430 elif sys.platform == 'darwin': 484 elif sys.platform == 'darwin':
431 485
432 486
433 # On non-windows, keep the stdlib behavior. 487 # On non-windows, keep the stdlib behavior.
434 isabs = os.path.isabs 488 isabs = os.path.isabs
435 489
436 490
437 def _native_case(p):
438 """Gets the native path case. Warning: this function resolves symlinks."""
439 try:
440 rel_ref, _ = Carbon.File.FSPathMakeRef(p.encode('utf-8'))
441 # The OSX underlying code uses NFD but python strings are in NFC. This
442 # will cause issues with os.listdir() for example. Since the dtrace log
443 # *is* in NFC, normalize it here.
444 out = unicodedata.normalize(
445 'NFC', rel_ref.FSRefMakePath().decode('utf-8'))
446 if p.endswith(os.path.sep) and not out.endswith(os.path.sep):
447 return out + os.path.sep
448 return out
449 except MacOS.Error, e:
450 if e.args[0] in (-43, -120):
451 # The path does not exist. Try to recurse and reconstruct the path.
452 # -43 means file not found.
453 # -120 means directory not found.
454 base = os.path.dirname(p)
455 rest = os.path.basename(p)
456 return os.path.join(_native_case(base), rest)
457 raise OSError(
458 e.args[0], 'Failed to get native path for %s' % p, p, e.args[1])
459
460
461 def _split_at_symlink_native(base_path, rest):
462 """Returns the native path for a symlink."""
463 base, symlink, rest = split_at_symlink(base_path, rest)
464 if symlink:
465 if not base_path:
466 base_path = base
467 else:
468 base_path = safe_join(base_path, base)
469 symlink = find_item_native_case(base_path, symlink)
470 return base, symlink, rest
471
472
473 def find_item_native_case(root_path, item): 491 def find_item_native_case(root_path, item):
474 """Gets the native path case of a single item based at root_path. 492 """Gets the native path case of a single item based at root_path.
475 493
476 There is no API to get the native path case of symlinks on OSX. So it 494 There is no API to get the native path case of symlinks on OSX. So it
477 needs to be done the slow way. 495 needs to be done the slow way.
478 """ 496 """
479 if item == '..': 497 if item == '..':
480 return item 498 return item
481 499
482 item = item.lower() 500 item = item.lower()
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 # Make sure no symlink was resolved. 548 # Make sure no symlink was resolved.
531 assert base.lower() == path.lower(), (base, path) 549 assert base.lower() == path.lower(), (base, path)
532 logging.debug('get_native_path_case(%s) = %s' % (path, base)) 550 logging.debug('get_native_path_case(%s) = %s' % (path, base))
533 return base 551 return base
534 552
535 553
536 def enable_symlink(): 554 def enable_symlink():
537 return True 555 return True
538 556
539 557
558 ## OSX private code.
559
560
561 def _native_case(p):
562 """Gets the native path case. Warning: this function resolves symlinks."""
563 try:
564 rel_ref, _ = Carbon.File.FSPathMakeRef(p.encode('utf-8'))
565 # The OSX underlying code uses NFD but python strings are in NFC. This
566 # will cause issues with os.listdir() for example. Since the dtrace log
567 # *is* in NFC, normalize it here.
568 out = unicodedata.normalize(
569 'NFC', rel_ref.FSRefMakePath().decode('utf-8'))
570 if p.endswith(os.path.sep) and not out.endswith(os.path.sep):
571 return out + os.path.sep
572 return out
573 except MacOS.Error, e:
574 if e.args[0] in (-43, -120):
575 # The path does not exist. Try to recurse and reconstruct the path.
576 # -43 means file not found.
577 # -120 means directory not found.
578 base = os.path.dirname(p)
579 rest = os.path.basename(p)
580 return os.path.join(_native_case(base), rest)
581 raise OSError(
582 e.args[0], 'Failed to get native path for %s' % p, p, e.args[1])
583
584
585 def _split_at_symlink_native(base_path, rest):
586 """Returns the native path for a symlink."""
587 base, symlink, rest = split_at_symlink(base_path, rest)
588 if symlink:
589 if not base_path:
590 base_path = base
591 else:
592 base_path = safe_join(base_path, base)
593 symlink = find_item_native_case(base_path, symlink)
594 return base, symlink, rest
595
596
540 else: # OSes other than Windows and OSX. 597 else: # OSes other than Windows and OSX.
541 598
542 599
543 # On non-windows, keep the stdlib behavior. 600 # On non-windows, keep the stdlib behavior.
544 isabs = os.path.isabs 601 isabs = os.path.isabs
545 602
546 603
547 def find_item_native_case(root, item): 604 def find_item_native_case(root, item):
548 """Gets the native path case of a single item based at root_path.""" 605 """Gets the native path case of a single item based at root_path."""
549 if item == '..': 606 if item == '..':
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
645 logging.debug( 702 logging.debug(
646 'split_at_symlink(%s, %s) -> (%s, %s, %s)' % 703 'split_at_symlink(%s, %s) -> (%s, %s, %s)' %
647 (base_dir, relfile, base, symlink, rest)) 704 (base_dir, relfile, base, symlink, rest))
648 return base, symlink, rest 705 return base, symlink, rest
649 if index == len(relfile): 706 if index == len(relfile):
650 break 707 break
651 index += 1 708 index += 1
652 return relfile, None, None 709 return relfile, None, None
653 710
654 711
712 def kill_children_processes(root):
713 """Not yet implemented on posix."""
714 # pylint: disable=unused-argument
715 return False
716
717
655 def relpath(path, root): 718 def relpath(path, root):
656 """os.path.relpath() that keeps trailing os.path.sep.""" 719 """os.path.relpath() that keeps trailing os.path.sep."""
657 out = os.path.relpath(path, root) 720 out = os.path.relpath(path, root)
658 if path.endswith(os.path.sep): 721 if path.endswith(os.path.sep):
659 out += os.path.sep 722 out += os.path.sep
660 return out 723 return out
661 724
662 725
663 def safe_relpath(filepath, basepath): 726 def safe_relpath(filepath, basepath):
664 """Do not throw on Windows when filepath and basepath are on different drives. 727 """Do not throw on Windows when filepath and basepath are on different drives.
(...skipping 21 matching lines...) Expand all
686 """posix.relpath() that keeps trailing slash. 749 """posix.relpath() that keeps trailing slash.
687 750
688 It is different from relpath() since it can be used on Windows. 751 It is different from relpath() since it can be used on Windows.
689 """ 752 """
690 out = posixpath.relpath(path, root) 753 out = posixpath.relpath(path, root)
691 if path.endswith('/'): 754 if path.endswith('/'):
692 out += '/' 755 out += '/'
693 return out 756 return out
694 757
695 758
696 def cleanup_path(x):
697 """Cleans up a relative path. Converts any os.path.sep to '/' on Windows."""
698 if x:
699 x = x.rstrip(os.path.sep).replace(os.path.sep, '/')
700 if x == '.':
701 x = ''
702 if x:
703 x += '/'
704 return x
705
706
707 def is_url(path): 759 def is_url(path):
708 """Returns True if it looks like an HTTP url instead of a file path.""" 760 """Returns True if it looks like an HTTP url instead of a file path."""
709 return bool(re.match(r'^https?://.+$', path)) 761 return bool(re.match(r'^https?://.+$', path))
710 762
711 763
712 def path_starts_with(prefix, path): 764 def path_starts_with(prefix, path):
713 """Returns true if the components of the path |prefix| are the same as the 765 """Returns true if the components of the path |prefix| are the same as the
714 initial components of |path| (or all of the components of |path|). The paths 766 initial components of |path| (or all of the components of |path|). The paths
715 must be absolute. 767 must be absolute.
716 """ 768 """
(...skipping 400 matching lines...) Expand 10 before | Expand all | Expand 10 after
1117 # The same path may be listed multiple times. 1169 # The same path may be listed multiple times.
1118 for path in sorted(set(path for _, path, _ in errors)): 1170 for path in sorted(set(path for _, path, _ in errors)):
1119 sys.stderr.write('- %s\n' % path) 1171 sys.stderr.write('- %s\n' % path)
1120 1172
1121 # If soft retries fail on Linux, there's nothing better we can do. 1173 # If soft retries fail on Linux, there's nothing better we can do.
1122 if sys.platform != 'win32': 1174 if sys.platform != 'win32':
1123 raise errors[0][2][0], errors[0][2][1], errors[0][2][2] 1175 raise errors[0][2][0], errors[0][2][1], errors[0][2][2]
1124 1176
1125 # The soft way was not good enough. Try the hard way. 1177 # The soft way was not good enough. Try the hard way.
1126 for i in xrange(max_tries): 1178 for i in xrange(max_tries):
1127 if not _kill_children_processes_win(root): 1179 if not kill_children_processes(root):
1128 break 1180 break
1129 if i != max_tries - 1: 1181 if i != max_tries - 1:
1130 time.sleep((i+1)*2) 1182 time.sleep((i+1)*2)
1131 else: 1183 else:
1132 processes = _get_children_processes_win(root) 1184 processes = _get_children_processes_win(root)
1133 if processes: 1185 if processes:
1134 sys.stderr.write('Failed to terminate processes.\n') 1186 sys.stderr.write('Failed to terminate processes.\n')
1135 raise errors[0][2][0], errors[0][2][1], errors[0][2][2] 1187 raise errors[0][2][0], errors[0][2][1], errors[0][2][2]
1136 1188
1137 # Now that annoying processes in root are evicted, try again. 1189 # Now that annoying processes in root are evicted, try again.
1138 errors = [] 1190 errors = []
1139 fs.rmtree(root, onerror=lambda *args: errors.append(args)) 1191 fs.rmtree(root, onerror=lambda *args: errors.append(args))
1140 if errors and fs.exists(root): 1192 if errors and fs.exists(root):
1141 # There's no hope: the directory was tried to be removed 4 times. Give up 1193 # There's no hope: the directory was tried to be removed 4 times. Give up
1142 # and raise an exception. 1194 # and raise an exception.
1143 sys.stderr.write( 1195 sys.stderr.write(
1144 'Failed to delete %s. The following files remain:\n' % root) 1196 'Failed to delete %s. The following files remain:\n' % root)
1145 # The same path may be listed multiple times. 1197 # The same path may be listed multiple times.
1146 for path in sorted(set(path for _, path, _ in errors)): 1198 for path in sorted(set(path for _, path, _ in errors)):
1147 sys.stderr.write('- %s\n' % path) 1199 sys.stderr.write('- %s\n' % path)
1148 raise errors[0][2][0], errors[0][2][1], errors[0][2][2] 1200 raise errors[0][2][0], errors[0][2][1], errors[0][2][2]
1149 return False 1201 return False
1150 1202
1151 1203
1152 ## Private code. 1204 ## Private code.
1153
1154
1155 def _kill_children_processes_win(root):
1156 """Try to kill all children processes indistriminately and prints updates to
1157 stderr.
1158
1159 Returns:
1160 True if at least one child process was found.
1161 """
1162 processes = _get_children_processes_win(root)
1163 if not processes:
1164 return False
1165 sys.stderr.write('Enumerating processes:\n')
1166 for _, proc in sorted(processes.iteritems()):
1167 sys.stderr.write(
1168 '- pid %d; Handles: %d; Exe: %s; Cmd: %s\n' % (
1169 proc.ProcessId,
1170 proc.HandleCount,
1171 proc.ExecutablePath,
1172 proc.CommandLine))
1173 sys.stderr.write('Terminating %d processes:\n' % len(processes))
1174 for pid in sorted(processes):
1175 try:
1176 # Killing is asynchronous.
1177 os.kill(pid, 9)
1178 sys.stderr.write('- %d killed\n' % pid)
1179 except OSError:
1180 sys.stderr.write('- failed to kill %s\n' % pid)
1181 return True
1182
1183
1184 def _get_children_processes_win(root):
1185 """Returns a list of processes.
1186
1187 Enumerates both:
1188 - all child processes from this process.
1189 - processes where the main executable in inside 'root'. The reason is that
1190 the ancestry may be broken so stray grand-children processes could be
1191 undetected by the first technique.
1192
1193 This technique is not fool-proof but gets mostly there.
1194 """
1195 processes = enum_processes_win()
1196 tree_processes = filter_processes_tree_win(processes)
1197 dir_processes = filter_processes_dir_win(processes, root)
1198 # Convert to dict to remove duplicates.
1199 processes = dict((p.ProcessId, p) for p in tree_processes)
1200 processes.update((p.ProcessId, p) for p in dir_processes)
1201 processes.pop(os.getpid())
1202 return processes
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698