| OLD | NEW |
| 1 # Copyright 2015 The LUCI Authors. All rights reserved. | 1 # Copyright 2015 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 """Wraps os, os.path and shutil functions to work around MAX_PATH on Windows.""" | 5 """Wraps os, os.path and shutil functions to work around MAX_PATH on Windows.""" |
| 6 | 6 |
| 7 import __builtin__ | 7 import __builtin__ |
| 8 import inspect | 8 import inspect |
| 9 import os | 9 import os |
| 10 import shutil | 10 import shutil |
| 11 import sys | 11 import sys |
| 12 | 12 |
| 13 | 13 |
| 14 if sys.platform == 'win32': | 14 if sys.platform == 'win32': |
| 15 | 15 |
| 16 | 16 |
| 17 import ctypes | 17 import ctypes |
| 18 GetFileAttributesW = ctypes.windll.kernel32.GetFileAttributesW | |
| 19 GetFileAttributesW.argtypes = (ctypes.c_wchar_p,) | |
| 20 GetFileAttributesW.restype = ctypes.c_uint | |
| 21 CreateSymbolicLinkW = ctypes.windll.kernel32.CreateSymbolicLinkW | 18 CreateSymbolicLinkW = ctypes.windll.kernel32.CreateSymbolicLinkW |
| 22 CreateSymbolicLinkW.argtypes = ( | 19 CreateSymbolicLinkW.argtypes = ( |
| 23 ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) | 20 ctypes.c_wchar_p, ctypes.c_wchar_p, ctypes.c_uint32) |
| 24 CreateSymbolicLinkW.restype = ctypes.c_ubyte | 21 CreateSymbolicLinkW.restype = ctypes.c_ubyte |
| 22 DeleteFile = ctypes.windll.kernel32.DeleteFileW |
| 23 DeleteFile.argtypes = (ctypes.c_wchar_p,) |
| 24 DeleteFile.restype = ctypes.c_bool |
| 25 GetFileAttributesW = ctypes.windll.kernel32.GetFileAttributesW |
| 26 GetFileAttributesW.argtypes = (ctypes.c_wchar_p,) |
| 27 GetFileAttributesW.restype = ctypes.c_uint |
| 28 RemoveDirectory = ctypes.windll.kernel32.RemoveDirectoryW |
| 29 RemoveDirectory.argtypes = (ctypes.c_wchar_p,) |
| 30 RemoveDirectory.restype = ctypes.c_bool |
| 25 | 31 |
| 26 | 32 |
| 27 def extend(path): | 33 def extend(path): |
| 28 """Adds '\\\\?\\' when given an absolute path so the MAX_PATH (260) limit is | 34 """Adds '\\\\?\\' when given an absolute path so the MAX_PATH (260) limit is |
| 29 not enforced. | 35 not enforced. |
| 30 """ | 36 """ |
| 31 assert os.path.isabs(path), path | 37 assert os.path.isabs(path), path |
| 32 assert isinstance(path, unicode), path | 38 assert isinstance(path, unicode), path |
| 33 prefix = u'\\\\?\\' | 39 prefix = u'\\\\?\\' |
| 34 return path if path.startswith(prefix) else prefix + path | 40 return path if path.startswith(prefix) else prefix + path |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 68 Privilege constants: | 74 Privilege constants: |
| 69 https://msdn.microsoft.com/library/windows/desktop/bb530716.aspx | 75 https://msdn.microsoft.com/library/windows/desktop/bb530716.aspx |
| 70 """ | 76 """ |
| 71 # TODO(maruel): This forces always creating absolute path symlinks. | 77 # TODO(maruel): This forces always creating absolute path symlinks. |
| 72 source = extend(source) | 78 source = extend(source) |
| 73 flags = 1 if os.path.isdir(source) else 0 | 79 flags = 1 if os.path.isdir(source) else 0 |
| 74 if not CreateSymbolicLinkW(extend(link_name), source, flags): | 80 if not CreateSymbolicLinkW(extend(link_name), source, flags): |
| 75 raise WindowsError() # pylint: disable=undefined-variable | 81 raise WindowsError() # pylint: disable=undefined-variable |
| 76 | 82 |
| 77 | 83 |
| 84 def unlink(path): |
| 85 """Removes a symlink on Windows 7 and later. |
| 86 |
| 87 Does not delete the link source. |
| 88 |
| 89 If path is not a link, but a non-empty directory, will fail with a |
| 90 WindowsError. |
| 91 |
| 92 Useful material: |
| 93 CreateSymbolicLinkW: |
| 94 https://msdn.microsoft.com/library/windows/desktop/aa363866.aspx |
| 95 DeleteFileW: |
| 96 https://msdn.microsoft.com/en-us/library/windows/desktop/aa363915(v=vs.85)
.aspx |
| 97 RemoveDirectoryW: |
| 98 https://msdn.microsoft.com/en-us/library/windows/desktop/aa365488(v=vs.85)
.aspx |
| 99 """ |
| 100 path = extend(path) |
| 101 if os.path.isdir(path): |
| 102 if not RemoveDirectory(path): |
| 103 # pylint: disable=undefined-variable |
| 104 raise WindowsError('could not remove directory "%s"' % path) |
| 105 else: |
| 106 if not DeleteFile(path): |
| 107 # pylint: disable=undefined-variable |
| 108 raise WindowsError('could not delete file "%s"' % path) |
| 109 |
| 110 |
| 78 def walk(top, *args, **kwargs): | 111 def walk(top, *args, **kwargs): |
| 79 return os.walk(extend(top), *args, **kwargs) | 112 return os.walk(extend(top), *args, **kwargs) |
| 80 | 113 |
| 81 | 114 |
| 82 else: | 115 else: |
| 83 | 116 |
| 84 | 117 |
| 85 def extend(path): | 118 def extend(path): |
| 86 """Convert the path back to utf-8. | 119 """Convert the path back to utf-8. |
| 87 | 120 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 100 return path.decode('utf-8') | 133 return path.decode('utf-8') |
| 101 | 134 |
| 102 | 135 |
| 103 def islink(path): | 136 def islink(path): |
| 104 return os.path.islink(extend(path)) | 137 return os.path.islink(extend(path)) |
| 105 | 138 |
| 106 | 139 |
| 107 def symlink(source, link_name): | 140 def symlink(source, link_name): |
| 108 return os.symlink(source, extend(link_name)) | 141 return os.symlink(source, extend(link_name)) |
| 109 | 142 |
| 143 def unlink(path): |
| 144 return os.unlink(extend(path)) |
| 110 | 145 |
| 111 def walk(top, *args, **kwargs): | 146 def walk(top, *args, **kwargs): |
| 112 for root, dirs, files in os.walk(extend(top), *args, **kwargs): | 147 for root, dirs, files in os.walk(extend(top), *args, **kwargs): |
| 113 yield trim(root), dirs, files | 148 yield trim(root), dirs, files |
| 114 | 149 |
| 115 | 150 |
| 116 ## builtin | 151 ## builtin |
| 117 | 152 |
| 118 | 153 |
| 119 def open(path, *args, **kwargs): # pylint: disable=redefined-builtin | 154 def open(path, *args, **kwargs): # pylint: disable=redefined-builtin |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 170 for _fn in _os_fns: | 205 for _fn in _os_fns: |
| 171 if hasattr(os, _fn): | 206 if hasattr(os, _fn): |
| 172 sys.modules[__name__].__dict__.setdefault( | 207 sys.modules[__name__].__dict__.setdefault( |
| 173 _fn, _get_lambda(getattr(os, _fn))) | 208 _fn, _get_lambda(getattr(os, _fn))) |
| 174 | 209 |
| 175 | 210 |
| 176 for _fn in _os_path_fns: | 211 for _fn in _os_path_fns: |
| 177 if hasattr(os.path, _fn): | 212 if hasattr(os.path, _fn): |
| 178 sys.modules[__name__].__dict__.setdefault( | 213 sys.modules[__name__].__dict__.setdefault( |
| 179 _fn, _get_lambda(getattr(os.path, _fn))) | 214 _fn, _get_lambda(getattr(os.path, _fn))) |
| OLD | NEW |