OLD | NEW |
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """A resolver for Windows paths to file system specific formats.""" | 2 """A resolver for Windows paths to file system specific formats.""" |
3 | 3 |
| 4 from __future__ import unicode_literals |
| 5 |
4 import re | 6 import re |
5 | 7 |
6 from dfvfs.lib import errors | 8 from dfvfs.lib import errors |
7 from dfvfs.lib import py2to3 | 9 from dfvfs.lib import py2to3 |
8 from dfvfs.path import factory as path_spec_factory | 10 from dfvfs.path import factory as path_spec_factory |
9 | 11 |
10 | 12 |
11 class WindowsPathResolver(object): | 13 class WindowsPathResolver(object): |
12 """Resolver object for Windows paths.""" | 14 """Resolver object for Windows paths.""" |
13 | 15 |
14 _PATH_SEPARATOR = u'\\' | 16 _PATH_SEPARATOR = '\\' |
15 _PATH_EXPANSION_VARIABLE = re.compile(r'^[%][^%]+[%]$') | 17 _PATH_EXPANSION_VARIABLE = re.compile(r'^[%][^%]+[%]$') |
16 | 18 |
17 def __init__(self, file_system, mount_point, drive_letter=u'C'): | 19 def __init__(self, file_system, mount_point, drive_letter='C'): |
18 """Initializes the Windows path helper. | 20 """Initializes a Windows path helper. |
19 | 21 |
20 The mount point indicates a path specification where the Windows | 22 The mount point indicates a path specification where the Windows |
21 file system is mounted. This can either be a path specification | 23 file system is mounted. This can either be a path specification |
22 into a storage media image or a directory accessible by the operating | 24 into a storage media image or a directory accessible by the operating |
23 system. | 25 system. |
24 | 26 |
25 Args: | 27 Args: |
26 file_system: the file system object (instance of FileSystem). | 28 file_system (FileSystem): a file system. |
27 mount_point: the mount point path specification (instance of PathSpec). | 29 mount_point (PathSpec): mount point path specification. |
28 drive_letter: optional string that contains the drive letter used by | 30 drive_letter (Optional[str]): drive letter used by the file system. |
29 the file system. | |
30 | 31 |
31 Raises: | 32 Raises: |
32 PathSpecError: if the mount point path specification is incorrect. | 33 PathSpecError: if the mount point path specification is incorrect. |
33 ValueError: when file system or mount point is not set. | 34 ValueError: when file system or mount point is not set. |
34 """ | 35 """ |
35 if not file_system or not mount_point: | 36 if not file_system or not mount_point: |
36 raise ValueError(u'Missing file system or mount point value.') | 37 raise ValueError('Missing file system or mount point value.') |
37 | 38 |
38 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( | 39 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( |
39 file_system.type_indicator): | 40 file_system.type_indicator): |
40 if not hasattr(mount_point, u'location'): | 41 if not hasattr(mount_point, 'location'): |
41 raise errors.PathSpecError( | 42 raise errors.PathSpecError( |
42 u'Mount point path specification missing location.') | 43 'Mount point path specification missing location.') |
43 | 44 |
44 super(WindowsPathResolver, self).__init__() | 45 super(WindowsPathResolver, self).__init__() |
45 | 46 |
46 self._drive_letter = drive_letter | 47 self._drive_letter = drive_letter |
47 self._environment_variables = {} | 48 self._environment_variables = {} |
48 self._file_system = file_system | 49 self._file_system = file_system |
49 self._mount_point = mount_point | 50 self._mount_point = mount_point |
50 | 51 |
51 # Windows paths: | 52 # Windows paths: |
52 # Device path: \\.\PhysicalDrive0 | 53 # Device path: \\.\PhysicalDrive0 |
(...skipping 10 matching lines...) Expand all Loading... |
63 # UNC path: \\server\share\directory\file.txt | 64 # UNC path: \\server\share\directory\file.txt |
64 # Path with environment variable: %SystemRoot%\file.txt | 65 # Path with environment variable: %SystemRoot%\file.txt |
65 # | 66 # |
66 # Note Windows also allows paths like: | 67 # Note Windows also allows paths like: |
67 # C:\..\directory\file.txt | 68 # C:\..\directory\file.txt |
68 | 69 |
69 def _PathStripPrefix(self, path): | 70 def _PathStripPrefix(self, path): |
70 """Strips the prefix from a path. | 71 """Strips the prefix from a path. |
71 | 72 |
72 Args: | 73 Args: |
73 path: the Windows path to strip the prefix from. | 74 path (str): Windows path to strip the prefix from. |
74 | 75 |
75 Returns: | 76 Returns: |
76 The path without the prefix or None if the path is not supported. | 77 str: path without the prefix or None if the path is not supported. |
77 """ | 78 """ |
78 if path.startswith(u'\\\\.\\') or path.startswith(u'\\\\?\\'): | 79 if path.startswith('\\\\.\\') or path.startswith('\\\\?\\'): |
79 if len(path) < 7 or path[5] != u':' or path[6] != self._PATH_SEPARATOR: | 80 if len(path) < 7 or path[5] != ':' or path[6] != self._PATH_SEPARATOR: |
80 # Cannot handle a non-volume path. | 81 # Cannot handle a non-volume path. |
81 return | 82 return |
82 path = path[7:] | 83 path = path[7:] |
83 | 84 |
84 elif path.startswith(u'\\\\'): | 85 elif path.startswith('\\\\'): |
85 # Cannot handle an UNC path. | 86 # Cannot handle an UNC path. |
86 return | 87 return |
87 | 88 |
88 elif len(path) >= 3 and path[1] == u':': | 89 elif len(path) >= 3 and path[1] == ':': |
89 # Check if the path is a Volume 'absolute' path. | 90 # Check if the path is a Volume 'absolute' path. |
90 if path[2] != self._PATH_SEPARATOR: | 91 if path[2] != self._PATH_SEPARATOR: |
91 # Cannot handle a Volume 'relative' path. | 92 # Cannot handle a Volume 'relative' path. |
92 return | 93 return |
93 path = path[3:] | 94 path = path[3:] |
94 | 95 |
95 elif path.startswith(u'\\'): | 96 elif path.startswith('\\'): |
96 path = path[1:] | 97 path = path[1:] |
97 | 98 |
98 else: | 99 else: |
99 # Cannot handle a relative path. | 100 # Cannot handle a relative path. |
100 return | 101 return |
101 | 102 |
102 return path | 103 return path |
103 | 104 |
104 def _ResolvePath(self, path, expand_variables=True): | 105 def _ResolvePath(self, path, expand_variables=True): |
105 """Resolves a Windows path in file system specific format. | 106 """Resolves a Windows path in file system specific format. |
106 | 107 |
107 This function will check if the individual path segments exists within | 108 This function will check if the individual path segments exists within |
108 the file system. For this it will prefer the first case sensitive match | 109 the file system. For this it will prefer the first case sensitive match |
109 above a case insensitive match. If no match was found None is returned. | 110 above a case insensitive match. If no match was found None is returned. |
110 | 111 |
111 Args: | 112 Args: |
112 path: the Windows path to resolve. | 113 path (str): Windows path to resolve. |
113 expand_variables: optional value to indicate path variables should be | 114 expand_variables (Optional[bool]): True if path variables should be |
114 expanded or not. | 115 expanded or not. |
115 | 116 |
116 Returns: | 117 Returns: |
117 A tuple of the path in file system specific format and the matching path | 118 tuple[str, PathSpec]: location and matching path specification or |
118 specification. | 119 (None, None) if not available. |
119 """ | 120 """ |
120 # Allow for paths that start with an environment variable e.g. | 121 # Allow for paths that start with an environment variable e.g. |
121 # %SystemRoot%\file.txt | 122 # %SystemRoot%\file.txt |
122 if path.startswith(u'%'): | 123 if path.startswith('%'): |
123 path_segment, _, _ = path.partition(self._PATH_SEPARATOR) | 124 path_segment, _, _ = path.partition(self._PATH_SEPARATOR) |
124 if not self._PATH_EXPANSION_VARIABLE.match(path_segment): | 125 if not self._PATH_EXPANSION_VARIABLE.match(path_segment): |
125 path = None | 126 path = None |
126 else: | 127 else: |
127 path = self._PathStripPrefix(path) | 128 path = self._PathStripPrefix(path) |
128 | 129 |
129 if path is None: | 130 if path is None: |
130 return None, None | 131 return None, None |
131 | 132 |
132 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( | 133 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( |
133 self._file_system.type_indicator): | 134 self._file_system.type_indicator): |
134 file_entry = self._file_system.GetFileEntryByPathSpec(self._mount_point) | 135 file_entry = self._file_system.GetFileEntryByPathSpec(self._mount_point) |
135 expanded_path_segments = self._file_system.SplitPath( | 136 expanded_path_segments = self._file_system.SplitPath( |
136 self._mount_point.location) | 137 self._mount_point.location) |
137 else: | 138 else: |
138 file_entry = self._file_system.GetRootFileEntry() | 139 file_entry = self._file_system.GetRootFileEntry() |
139 expanded_path_segments = [] | 140 expanded_path_segments = [] |
140 | 141 |
141 number_of_expanded_path_segments = 0 | 142 number_of_expanded_path_segments = 0 |
142 | 143 |
143 search_path_segments = path.split(self._PATH_SEPARATOR) | 144 search_path_segments = path.split(self._PATH_SEPARATOR) |
144 while search_path_segments: | 145 while search_path_segments: |
145 path_segment = search_path_segments.pop(0) | 146 path_segment = search_path_segments.pop(0) |
146 if file_entry is None: | 147 if file_entry is None: |
147 return None, None | 148 return None, None |
148 | 149 |
149 # Ignore empty path segments or path segments containing a single dot. | 150 # Ignore empty path segments or path segments containing a single dot. |
150 if not path_segment or path_segment == u'.': | 151 if not path_segment or path_segment == '.': |
151 continue | 152 continue |
152 | 153 |
153 if path_segment == u'..': | 154 if path_segment == '..': |
154 # Only allow to traverse back up to the mount point. | 155 # Only allow to traverse back up to the mount point. |
155 if number_of_expanded_path_segments > 0: | 156 if number_of_expanded_path_segments > 0: |
156 _ = expanded_path_segments.pop(0) | 157 _ = expanded_path_segments.pop(0) |
157 number_of_expanded_path_segments -= 1 | 158 number_of_expanded_path_segments -= 1 |
158 file_entry = file_entry.GetParentFileEntry() | 159 file_entry = file_entry.GetParentFileEntry() |
159 continue | 160 continue |
160 | 161 |
161 if (expand_variables and | 162 if (expand_variables and |
162 self._PATH_EXPANSION_VARIABLE.match(path_segment)): | 163 self._PATH_EXPANSION_VARIABLE.match(path_segment)): |
163 path_segment = self._environment_variables.get( | 164 path_segment = self._environment_variables.get( |
(...skipping 17 matching lines...) Expand all Loading... |
181 number_of_expanded_path_segments += 1 | 182 number_of_expanded_path_segments += 1 |
182 file_entry = sub_file_entry | 183 file_entry = sub_file_entry |
183 | 184 |
184 location = self._file_system.JoinPath(expanded_path_segments) | 185 location = self._file_system.JoinPath(expanded_path_segments) |
185 return location, file_entry.path_spec | 186 return location, file_entry.path_spec |
186 | 187 |
187 def GetWindowsPath(self, path_spec): | 188 def GetWindowsPath(self, path_spec): |
188 """Returns the Windows path based on a resolved path specification. | 189 """Returns the Windows path based on a resolved path specification. |
189 | 190 |
190 Args: | 191 Args: |
191 path_spec: the path specification (instance of PathSpec). | 192 path_spec (PathSpec): a path specification. |
192 | 193 |
193 Returns: | 194 Returns: |
194 The corresponding Windows path or None if the Windows path could not | 195 str: corresponding Windows path or None if the Windows path could not |
195 be determined. | 196 be determined. |
196 | 197 |
197 Raises: | 198 Raises: |
198 PathSpecError: if the path specification is incorrect. | 199 PathSpecError: if the path specification is incorrect. |
199 """ | 200 """ |
200 location = getattr(path_spec, u'location', None) | 201 location = getattr(path_spec, 'location', None) |
201 if location is None: | 202 if location is None: |
202 raise errors.PathSpecError(u'Path specification missing location.') | 203 raise errors.PathSpecError('Path specification missing location.') |
203 | 204 |
204 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( | 205 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( |
205 self._file_system.type_indicator): | 206 self._file_system.type_indicator): |
206 if not location.startswith(self._mount_point.location): | 207 if not location.startswith(self._mount_point.location): |
207 raise errors.PathSpecError( | 208 raise errors.PathSpecError( |
208 u'Path specification does not contain mount point.') | 209 'Path specification does not contain mount point.') |
209 else: | 210 else: |
210 if not hasattr(path_spec, u'parent'): | 211 if not hasattr(path_spec, 'parent'): |
211 raise errors.PathSpecError(u'Path specification missing parent.') | 212 raise errors.PathSpecError('Path specification missing parent.') |
212 | 213 |
213 if path_spec.parent != self._mount_point: | 214 if path_spec.parent != self._mount_point: |
214 raise errors.PathSpecError( | 215 raise errors.PathSpecError( |
215 u'Path specification does not contain mount point.') | 216 'Path specification does not contain mount point.') |
216 | 217 |
217 path_segments = self._file_system.SplitPath(location) | 218 path_segments = self._file_system.SplitPath(location) |
218 | 219 |
219 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( | 220 if path_spec_factory.Factory.IsSystemLevelTypeIndicator( |
220 self._file_system.type_indicator): | 221 self._file_system.type_indicator): |
221 mount_point_path_segments = self._file_system.SplitPath( | 222 mount_point_path_segments = self._file_system.SplitPath( |
222 self._mount_point.location) | 223 self._mount_point.location) |
223 path_segments = path_segments[len(mount_point_path_segments):] | 224 path_segments = path_segments[len(mount_point_path_segments):] |
224 | 225 |
225 return u'{0:s}:\\{1:s}'.format( | 226 return '{0:s}:\\{1:s}'.format( |
226 self._drive_letter, self._PATH_SEPARATOR.join(path_segments)) | 227 self._drive_letter, self._PATH_SEPARATOR.join(path_segments)) |
227 | 228 |
228 def ResolvePath(self, path, expand_variables=True): | 229 def ResolvePath(self, path, expand_variables=True): |
229 """Resolves a Windows path in file system specific format. | 230 """Resolves a Windows path in file system specific format. |
230 | 231 |
231 Args: | 232 Args: |
232 path: the Windows path to resolve. | 233 path (str): Windows path to resolve. |
233 expand_variables: optional value to indicate path variables should be | 234 expand_variables (Optional[bool]): True if path variables should be |
234 expanded or not. | 235 expanded or not. |
235 | 236 |
236 Returns: | 237 Returns: |
237 The path specification (instance of PathSpec) in file system | 238 PathSpec: path specification in file system specific format. |
238 specific format. | |
239 """ | 239 """ |
240 location, path_spec = self._ResolvePath( | 240 location, path_spec = self._ResolvePath( |
241 path, expand_variables=expand_variables) | 241 path, expand_variables=expand_variables) |
242 | 242 |
243 if not location or not path_spec: | 243 if not location or not path_spec: |
244 return | 244 return |
245 | 245 |
246 # Note that we don't want to set the keyword arguments when not used because | 246 # Note that we don't want to set the keyword arguments when not used because |
247 # the path specification base class will check for unused keyword arguments | 247 # the path specification base class will check for unused keyword arguments |
248 # and raise. | 248 # and raise. |
249 kwargs = path_spec_factory.Factory.GetProperties(path_spec) | 249 kwargs = path_spec_factory.Factory.GetProperties(path_spec) |
250 | 250 |
251 kwargs[u'location'] = location | 251 kwargs['location'] = location |
252 if not path_spec_factory.Factory.IsSystemLevelTypeIndicator( | 252 if not path_spec_factory.Factory.IsSystemLevelTypeIndicator( |
253 self._file_system.type_indicator): | 253 self._file_system.type_indicator): |
254 kwargs[u'parent'] = self._mount_point | 254 kwargs['parent'] = self._mount_point |
255 | 255 |
256 return path_spec_factory.Factory.NewPathSpec( | 256 return path_spec_factory.Factory.NewPathSpec( |
257 self._file_system.type_indicator, **kwargs) | 257 self._file_system.type_indicator, **kwargs) |
258 | 258 |
259 def SetEnvironmentVariable(self, name, value): | 259 def SetEnvironmentVariable(self, name, value): |
260 """Sets an environment variable in the Windows path helper. | 260 """Sets an environment variable in the Windows path helper. |
261 | 261 |
262 Args: | 262 Args: |
263 name: the name of the environment variable without enclosing | 263 name (str): name of the environment variable without enclosing |
264 %-characters, e.g. SystemRoot as in %SystemRoot%. | 264 %-characters, e.g. SystemRoot as in %SystemRoot%. |
265 value: the value of the environment variable. | 265 value (str): value of the environment variable. |
266 """ | 266 """ |
267 if isinstance(value, py2to3.STRING_TYPES): | 267 if isinstance(value, py2to3.STRING_TYPES): |
268 value = self._PathStripPrefix(value) | 268 value = self._PathStripPrefix(value) |
269 | 269 |
270 if value is not None: | 270 if value is not None: |
271 self._environment_variables[name.upper()] = value | 271 self._environment_variables[name.upper()] = value |
OLD | NEW |