Left: | ||
Right: |
LEFT | RIGHT |
---|---|
1 # -*- coding: utf-8 -*- | 1 # -*- coding: utf-8 -*- |
2 """The SleuthKit (TSK) file entry implementation.""" | 2 """The SleuthKit (TSK) file entry implementation.""" |
3 | |
4 from __future__ import unicode_literals | |
3 | 5 |
4 import copy | 6 import copy |
5 | 7 |
6 import pytsk3 | 8 import pytsk3 |
7 | 9 |
8 from dfdatetime import definitions as dfdatetime_definitions | 10 from dfdatetime import definitions as dfdatetime_definitions |
9 from dfdatetime import interface as dfdatetime_interface | 11 from dfdatetime import interface as dfdatetime_interface |
10 | 12 |
11 from dfvfs.lib import definitions | 13 from dfvfs.lib import definitions |
12 from dfvfs.lib import errors | 14 from dfvfs.lib import errors |
13 from dfvfs.path import tsk_path_spec | 15 from dfvfs.path import tsk_path_spec |
14 from dfvfs.resolver import resolver | 16 from dfvfs.resolver import resolver |
15 from dfvfs.vfs import file_entry | 17 from dfvfs.vfs import file_entry |
16 | 18 |
17 | 19 |
18 class TSKTime(dfdatetime_interface.DateTimeValues): | 20 class TSKTime(dfdatetime_interface.DateTimeValues): |
onager
2017/07/18 15:44:24
Shouldn't this be in dfdatetime? Perhaps add a TOD
Joachim Metz
2017/07/18 19:40:37
Good question, my initial take on this was it is s
| |
19 """SleuthKit timestamp.""" | 21 """SleuthKit timestamp.""" |
20 | 22 |
21 def __init__(self, timestamp=None, timestamp_fragment=None): | 23 def __init__(self, timestamp=None, timestamp_fragment=None): |
22 """Initializes a SleuthKit timestamp. | 24 """Initializes a SleuthKit timestamp. |
23 | 25 |
24 Args: | 26 Args: |
25 timestamp (Optional[int]): POSIX timestamp. | 27 timestamp (Optional[int]): POSIX timestamp. |
26 timestamp_fragment (Optional[int]): POSIX timestamp fragment. | 28 timestamp_fragment (Optional[int]): POSIX timestamp fragment. |
27 """ | 29 """ |
28 # Sleuthkit 4.2.0 switched from 100 nano seconds precision to | 30 # Sleuthkit 4.2.0 switched from 100 nano seconds precision to |
(...skipping 15 matching lines...) Expand all Loading... | |
44 time_string (str): date and time value formatted as: | 46 time_string (str): date and time value formatted as: |
45 YYYY-MM-DD hh:mm:ss.######[+-]##:## | 47 YYYY-MM-DD hh:mm:ss.######[+-]##:## |
46 | 48 |
47 Where # are numeric digits ranging from 0 to 9 and the seconds | 49 Where # are numeric digits ranging from 0 to 9 and the seconds |
48 fraction can be either 3 or 6 digits. The time of day, seconds | 50 fraction can be either 3 or 6 digits. The time of day, seconds |
49 fraction and time zone offset are optional. The default time zone | 51 fraction and time zone offset are optional. The default time zone |
50 is UTC. | 52 is UTC. |
51 """ | 53 """ |
52 date_time_values = self._CopyDateTimeFromString(time_string) | 54 date_time_values = self._CopyDateTimeFromString(time_string) |
53 | 55 |
54 year = date_time_values.get(u'year', 0) | 56 year = date_time_values.get('year', 0) |
55 month = date_time_values.get(u'month', 0) | 57 month = date_time_values.get('month', 0) |
56 day_of_month = date_time_values.get(u'day_of_month', 0) | 58 day_of_month = date_time_values.get('day_of_month', 0) |
57 hours = date_time_values.get(u'hours', 0) | 59 hours = date_time_values.get('hours', 0) |
58 minutes = date_time_values.get(u'minutes', 0) | 60 minutes = date_time_values.get('minutes', 0) |
59 seconds = date_time_values.get(u'seconds', 0) | 61 seconds = date_time_values.get('seconds', 0) |
60 microseconds = date_time_values.get(u'microseconds', 0) | 62 microseconds = date_time_values.get('microseconds', 0) |
61 | 63 |
62 self.timestamp = self._GetNumberOfSecondsFromElements( | 64 self.timestamp = self._GetNumberOfSecondsFromElements( |
63 year, month, day_of_month, hours, minutes, seconds) | 65 year, month, day_of_month, hours, minutes, seconds) |
64 self.timestamp_fragment = microseconds | 66 self.timestamp_fragment = microseconds |
65 | 67 |
66 if pytsk3.TSK_VERSION_NUM >= 0x040200ff: | 68 if pytsk3.TSK_VERSION_NUM >= 0x040200ff: |
67 self.timestamp_fragment *= 1000 | 69 self.timestamp_fragment *= 1000 |
68 else: | 70 else: |
69 self.timestamp_fragment *= 10 | 71 self.timestamp_fragment *= 10 |
70 | 72 |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
118 | 120 |
119 Args: | 121 Args: |
120 tsk_attribute (pytsk3.Attribute): TSK attribute. | 122 tsk_attribute (pytsk3.Attribute): TSK attribute. |
121 """ | 123 """ |
122 super(TSKAttribute, self).__init__() | 124 super(TSKAttribute, self).__init__() |
123 self._tsk_attribute = tsk_attribute | 125 self._tsk_attribute = tsk_attribute |
124 | 126 |
125 @property | 127 @property |
126 def attribute_type(self): | 128 def attribute_type(self): |
127 """object: attribute type.""" | 129 """object: attribute type.""" |
128 return getattr(self._tsk_attribute.info, u'type', None) | 130 return getattr(self._tsk_attribute.info, 'type', None) |
129 | 131 |
130 | 132 |
131 class TSKDataStream(file_entry.DataStream): | 133 class TSKDataStream(file_entry.DataStream): |
132 """File system data stream that uses pytks3.""" | 134 """File system data stream that uses pytks3.""" |
133 | 135 |
134 def __init__(self, tsk_attribute): | 136 def __init__(self, tsk_attribute): |
135 """Initializes a data stream. | 137 """Initializes a data stream. |
136 | 138 |
137 Args: | 139 Args: |
138 tsk_attribute (pytsk3.Attribute): TSK attribute. | 140 tsk_attribute (pytsk3.Attribute): TSK attribute. |
139 """ | 141 """ |
140 super(TSKDataStream, self).__init__() | 142 super(TSKDataStream, self).__init__() |
141 self._tsk_attribute = tsk_attribute | 143 self._tsk_attribute = tsk_attribute |
142 | 144 |
143 @property | 145 @property |
144 def name(self): | 146 def name(self): |
145 """str: name.""" | 147 """str: name.""" |
146 if self._tsk_attribute: | 148 if self._tsk_attribute: |
147 # The value of the attribute name will be None for the default | 149 # The value of the attribute name will be None for the default |
148 # data stream. | 150 # data stream. |
149 attribute_name = getattr(self._tsk_attribute.info, u'name', None) | 151 attribute_name = getattr(self._tsk_attribute.info, 'name', None) |
150 if attribute_name: | 152 if attribute_name: |
151 try: | 153 try: |
152 # pytsk3 returns an UTF-8 encoded byte string. | 154 # pytsk3 returns an UTF-8 encoded byte string. |
153 return attribute_name.decode(u'utf8') | 155 return attribute_name.decode('utf8') |
154 except UnicodeError: | 156 except UnicodeError: |
155 pass | 157 pass |
156 | 158 |
157 return u'' | 159 return '' |
158 | 160 |
159 | 161 |
160 class TSKDirectory(file_entry.Directory): | 162 class TSKDirectory(file_entry.Directory): |
161 """File system directory that uses pytsk3.""" | 163 """File system directory that uses pytsk3.""" |
162 | 164 |
163 def _EntriesGenerator(self): | 165 def _EntriesGenerator(self): |
164 """Retrieves directory entries. | 166 """Retrieves directory entries. |
165 | 167 |
166 Since a directory can contain a vast number of entries using | 168 Since a directory can contain a vast number of entries using |
167 a generator is more memory efficient. | 169 a generator is more memory efficient. |
168 | 170 |
169 Yields: | 171 Yields: |
170 TSKPathSpec: a path specification. | 172 TSKPathSpec: a path specification. |
171 | 173 |
172 Raises: | 174 Raises: |
173 BackEndError: if pytsk3 cannot open the directory. | 175 BackEndError: if pytsk3 cannot open the directory. |
174 """ | 176 """ |
175 # Opening a file by inode number is faster than opening a file | 177 # Opening a file by inode number is faster than opening a file |
176 # by location. | 178 # by location. |
177 inode = getattr(self.path_spec, u'inode', None) | 179 inode = getattr(self.path_spec, 'inode', None) |
178 location = getattr(self.path_spec, u'location', None) | 180 location = getattr(self.path_spec, 'location', None) |
179 | 181 |
180 fs_info = self._file_system.GetFsInfo() | 182 fs_info = self._file_system.GetFsInfo() |
181 tsk_directory = None | 183 tsk_directory = None |
182 | 184 |
183 try: | 185 try: |
184 if inode is not None: | 186 if inode is not None: |
185 tsk_directory = fs_info.open_dir(inode=inode) | 187 tsk_directory = fs_info.open_dir(inode=inode) |
186 elif location is not None: | 188 elif location is not None: |
187 tsk_directory = fs_info.open_dir(path=location) | 189 tsk_directory = fs_info.open_dir(path=location) |
188 | 190 |
189 except IOError as exception: | 191 except IOError as exception: |
190 raise errors.BackEndError( | 192 raise errors.BackEndError( |
191 u'Unable to open directory with error: {0:s}'.format(exception)) | 193 'Unable to open directory with error: {0:s}'.format(exception)) |
192 | 194 |
193 if not tsk_directory: | 195 if not tsk_directory: |
194 return | 196 return |
195 | 197 |
196 for tsk_directory_entry in tsk_directory: | 198 for tsk_directory_entry in tsk_directory: |
197 # Note that because pytsk3.Directory does not explicitly defines info | 199 # Note that because pytsk3.Directory does not explicitly defines info |
198 # we need to check if the attribute exists and has a value other | 200 # we need to check if the attribute exists and has a value other |
199 # than None. | 201 # than None. |
200 if getattr(tsk_directory_entry, u'info', None) is None: | 202 if getattr(tsk_directory_entry, 'info', None) is None: |
201 continue | 203 continue |
202 | 204 |
203 # Note that because pytsk3.TSK_FS_FILE does not explicitly defines fs_info | 205 # Note that because pytsk3.TSK_FS_FILE does not explicitly defines fs_info |
204 # we need to check if the attribute exists and has a value other | 206 # we need to check if the attribute exists and has a value other |
205 # than None. | 207 # than None. |
206 if getattr(tsk_directory_entry.info, u'fs_info', None) is None: | 208 if getattr(tsk_directory_entry.info, 'fs_info', None) is None: |
207 continue | 209 continue |
208 | 210 |
209 # Note that because pytsk3.TSK_FS_FILE does not explicitly defines meta | 211 # Note that because pytsk3.TSK_FS_FILE does not explicitly defines meta |
210 # we need to check if the attribute exists and has a value other | 212 # we need to check if the attribute exists and has a value other |
211 # than None. | 213 # than None. |
212 if getattr(tsk_directory_entry.info, u'meta', None) is None: | 214 if getattr(tsk_directory_entry.info, 'meta', None) is None: |
213 # Most directory entries will have an "inode" but not all, e.g. | 215 # Most directory entries will have an "inode" but not all, e.g. |
214 # previously deleted files. Currently directory entries without | 216 # previously deleted files. Currently directory entries without |
215 # a pytsk3.TSK_FS_META object are ignored. | 217 # a pytsk3.TSK_FS_META object are ignored. |
216 continue | 218 continue |
217 | 219 |
218 # Note that because pytsk3.TSK_FS_META does not explicitly defines addr | 220 # Note that because pytsk3.TSK_FS_META does not explicitly defines addr |
219 # we need to check if the attribute exists. | 221 # we need to check if the attribute exists. |
220 if not hasattr(tsk_directory_entry.info.meta, u'addr'): | 222 if not hasattr(tsk_directory_entry.info.meta, 'addr'): |
221 continue | 223 continue |
222 | 224 |
223 directory_entry_inode = tsk_directory_entry.info.meta.addr | 225 directory_entry_inode = tsk_directory_entry.info.meta.addr |
224 directory_entry = None | 226 directory_entry = None |
225 | 227 |
226 # Ignore references to self. | 228 # Ignore references to self. |
227 if directory_entry_inode == inode: | 229 if directory_entry_inode == inode: |
228 continue | 230 continue |
229 | 231 |
230 # On non-NTFS file systems ignore inode 0. | 232 # On non-NTFS file systems ignore inode 0. |
231 if directory_entry_inode == 0 and not self._file_system.IsNTFS(): | 233 if directory_entry_inode == 0 and not self._file_system.IsNTFS(): |
232 continue | 234 continue |
233 | 235 |
234 # Note that because pytsk3.TSK_FS_FILE does not explicitly defines name | 236 # Note that because pytsk3.TSK_FS_FILE does not explicitly defines name |
235 # we need to check if the attribute exists and has a value other | 237 # we need to check if the attribute exists and has a value other |
236 # than None. | 238 # than None. |
237 if getattr(tsk_directory_entry.info, u'name', None) is not None: | 239 if getattr(tsk_directory_entry.info, 'name', None) is not None: |
238 # Ignore file entries marked as "unallocated". | 240 # Ignore file entries marked as "unallocated". |
239 flags = getattr(tsk_directory_entry.info.name, u'flags', 0) | 241 flags = getattr(tsk_directory_entry.info.name, 'flags', 0) |
240 if int(flags) & pytsk3.TSK_FS_NAME_FLAG_UNALLOC: | 242 if int(flags) & pytsk3.TSK_FS_NAME_FLAG_UNALLOC: |
241 continue | 243 continue |
242 | 244 |
243 directory_entry = getattr(tsk_directory_entry.info.name, u'name', u'') | 245 directory_entry = getattr(tsk_directory_entry.info.name, 'name', '') |
244 | 246 |
245 try: | 247 try: |
246 # pytsk3 returns an UTF-8 encoded byte string. | 248 # pytsk3 returns an UTF-8 encoded byte string. |
247 directory_entry = directory_entry.decode(u'utf8') | 249 directory_entry = directory_entry.decode('utf8') |
248 except UnicodeError: | 250 except UnicodeError: |
249 # Continue here since we cannot represent the directory entry. | 251 # Continue here since we cannot represent the directory entry. |
250 continue | 252 continue |
251 | 253 |
252 if directory_entry: | 254 if directory_entry: |
253 # Ignore references to self or parent. | 255 # Ignore references to self or parent. |
254 if directory_entry in [u'.', u'..']: | 256 if directory_entry in ['.', '..']: |
255 continue | 257 continue |
256 | 258 |
257 if location == self._file_system.PATH_SEPARATOR: | 259 if location == self._file_system.PATH_SEPARATOR: |
258 directory_entry = self._file_system.JoinPath([directory_entry]) | 260 directory_entry = self._file_system.JoinPath([directory_entry]) |
259 else: | 261 else: |
260 directory_entry = self._file_system.JoinPath([ | 262 directory_entry = self._file_system.JoinPath([ |
261 location, directory_entry]) | 263 location, directory_entry]) |
262 | 264 |
263 yield tsk_path_spec.TSKPathSpec( | 265 yield tsk_path_spec.TSKPathSpec( |
264 inode=directory_entry_inode, location=directory_entry, | 266 inode=directory_entry_inode, location=directory_entry, |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
309 | 311 |
310 Raises: | 312 Raises: |
311 BackEndError: if the TSK File .info or .info.meta attribute is missing. | 313 BackEndError: if the TSK File .info or .info.meta attribute is missing. |
312 """ | 314 """ |
313 if (not tsk_file or not tsk_file.info or not tsk_file.info.meta or | 315 if (not tsk_file or not tsk_file.info or not tsk_file.info.meta or |
314 not tsk_file.info.fs_info): | 316 not tsk_file.info.fs_info): |
315 tsk_file = file_system.GetTSKFileByPathSpec(path_spec) | 317 tsk_file = file_system.GetTSKFileByPathSpec(path_spec) |
316 if (not tsk_file or not tsk_file.info or not tsk_file.info.meta or | 318 if (not tsk_file or not tsk_file.info or not tsk_file.info.meta or |
317 not tsk_file.info.fs_info): | 319 not tsk_file.info.fs_info): |
318 raise errors.BackEndError( | 320 raise errors.BackEndError( |
319 u'Missing TSK File .info, .info.meta or .info.fs_info') | 321 'Missing TSK File .info, .info.meta or .info.fs_info') |
320 | 322 |
321 super(TSKFileEntry, self).__init__( | 323 super(TSKFileEntry, self).__init__( |
322 resolver_context, file_system, path_spec, is_root=is_root, | 324 resolver_context, file_system, path_spec, is_root=is_root, |
323 is_virtual=is_virtual) | 325 is_virtual=is_virtual) |
324 self._file_system_type = tsk_file.info.fs_info.ftype | 326 self._file_system_type = tsk_file.info.fs_info.ftype |
325 self._name = None | 327 self._name = None |
326 self._parent_inode = parent_inode | 328 self._parent_inode = parent_inode |
327 self._tsk_file = tsk_file | 329 self._tsk_file = tsk_file |
328 | 330 |
329 # The type is an instance of pytsk3.TSK_FS_META_TYPE_ENUM. | 331 # The type is an instance of pytsk3.TSK_FS_META_TYPE_ENUM. |
330 tsk_fs_meta_type = getattr( | 332 tsk_fs_meta_type = getattr( |
331 tsk_file.info.meta, u'type', pytsk3.TSK_FS_META_TYPE_UNDEF) | 333 tsk_file.info.meta, 'type', pytsk3.TSK_FS_META_TYPE_UNDEF) |
332 | 334 |
333 if tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_REG: | 335 if tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_REG: |
334 self._type = definitions.FILE_ENTRY_TYPE_FILE | 336 self._type = definitions.FILE_ENTRY_TYPE_FILE |
335 elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_DIR: | 337 elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_DIR: |
336 self._type = definitions.FILE_ENTRY_TYPE_DIRECTORY | 338 self._type = definitions.FILE_ENTRY_TYPE_DIRECTORY |
337 elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_LNK: | 339 elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_LNK: |
338 self._type = definitions.FILE_ENTRY_TYPE_LINK | 340 self._type = definitions.FILE_ENTRY_TYPE_LINK |
339 elif (tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_CHR or | 341 elif (tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_CHR or |
340 tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_BLK): | 342 tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_BLK): |
341 self._type = definitions.FILE_ENTRY_TYPE_DEVICE | 343 self._type = definitions.FILE_ENTRY_TYPE_DEVICE |
(...skipping 11 matching lines...) Expand all Loading... | |
353 def _GetAttributes(self): | 355 def _GetAttributes(self): |
354 """Retrieves the attributes. | 356 """Retrieves the attributes. |
355 | 357 |
356 Returns: | 358 Returns: |
357 list[TSKAttribute]: attributes. | 359 list[TSKAttribute]: attributes. |
358 """ | 360 """ |
359 if self._attributes is None: | 361 if self._attributes is None: |
360 self._attributes = [] | 362 self._attributes = [] |
361 | 363 |
362 for tsk_attribute in self._tsk_file: | 364 for tsk_attribute in self._tsk_file: |
363 if getattr(tsk_attribute, u'info', None) is None: | 365 if getattr(tsk_attribute, 'info', None) is None: |
364 continue | 366 continue |
365 | 367 |
366 # At the moment there is no way to expose the attribute data | 368 # At the moment there is no way to expose the attribute data |
367 # from pytsk3. | 369 # from pytsk3. |
368 attribute_object = TSKAttribute(tsk_attribute) | 370 attribute_object = TSKAttribute(tsk_attribute) |
369 self._attributes.append(attribute_object) | 371 self._attributes.append(attribute_object) |
370 | 372 |
371 return self._attributes | 373 return self._attributes |
372 | 374 |
373 def _GetDataStreams(self): | 375 def _GetDataStreams(self): |
(...skipping 11 matching lines...) Expand all Loading... | |
385 elif self._file_system.IsNTFS(): | 387 elif self._file_system.IsNTFS(): |
386 known_data_attribute_types = [pytsk3.TSK_FS_ATTR_TYPE_NTFS_DATA] | 388 known_data_attribute_types = [pytsk3.TSK_FS_ATTR_TYPE_NTFS_DATA] |
387 | 389 |
388 else: | 390 else: |
389 known_data_attribute_types = None | 391 known_data_attribute_types = None |
390 | 392 |
391 self._data_streams = [] | 393 self._data_streams = [] |
392 | 394 |
393 if not known_data_attribute_types: | 395 if not known_data_attribute_types: |
394 tsk_fs_meta_type = getattr( | 396 tsk_fs_meta_type = getattr( |
395 self._tsk_file.info.meta, u'type', pytsk3.TSK_FS_META_TYPE_UNDEF) | 397 self._tsk_file.info.meta, 'type', pytsk3.TSK_FS_META_TYPE_UNDEF) |
396 if tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_REG: | 398 if tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_REG: |
397 self._data_streams.append(TSKDataStream(None)) | 399 self._data_streams.append(TSKDataStream(None)) |
398 | 400 |
399 else: | 401 else: |
400 for tsk_attribute in self._tsk_file: | 402 for tsk_attribute in self._tsk_file: |
401 if getattr(tsk_attribute, u'info', None) is None: | 403 if getattr(tsk_attribute, 'info', None) is None: |
402 continue | 404 continue |
403 | 405 |
404 attribute_type = getattr(tsk_attribute.info, u'type', None) | 406 attribute_type = getattr(tsk_attribute.info, 'type', None) |
405 if attribute_type in known_data_attribute_types: | 407 if attribute_type in known_data_attribute_types: |
406 self._data_streams.append(TSKDataStream(tsk_attribute)) | 408 self._data_streams.append(TSKDataStream(tsk_attribute)) |
407 | 409 |
408 return self._data_streams | 410 return self._data_streams |
409 | 411 |
410 def _GetDirectory(self): | 412 def _GetDirectory(self): |
411 """Retrieves a directory. | 413 """Retrieves a directory. |
412 | 414 |
413 Returns: | 415 Returns: |
414 TSKDirectory: directory or None. | 416 TSKDirectory: directory or None. |
415 """ | 417 """ |
416 if self._type == definitions.FILE_ENTRY_TYPE_DIRECTORY: | 418 if self._type == definitions.FILE_ENTRY_TYPE_DIRECTORY: |
417 return TSKDirectory(self._file_system, self.path_spec) | 419 return TSKDirectory(self._file_system, self.path_spec) |
418 | 420 |
419 def _GetLink(self): | 421 def _GetLink(self): |
420 """Retrieves the link. | 422 """Retrieves the link. |
421 | 423 |
422 Returns: | 424 Returns: |
423 str: path of the linked file. | 425 str: path of the linked file. |
424 """ | 426 """ |
425 if self._link is None: | 427 if self._link is None: |
426 self._link = u'' | 428 self._link = '' |
427 | 429 |
428 if self._type != definitions.FILE_ENTRY_TYPE_LINK: | 430 if self._type != definitions.FILE_ENTRY_TYPE_LINK: |
429 return self._link | 431 return self._link |
430 | 432 |
431 # Note that the SleuthKit does not expose NTFS | 433 # Note that the SleuthKit does not expose NTFS |
432 # IO_REPARSE_TAG_MOUNT_POINT or IO_REPARSE_TAG_SYMLINK as a link. | 434 # IO_REPARSE_TAG_MOUNT_POINT or IO_REPARSE_TAG_SYMLINK as a link. |
433 link = getattr(self._tsk_file.info.meta, u'link', None) | 435 link = getattr(self._tsk_file.info.meta, 'link', None) |
434 | 436 |
435 if link is None: | 437 if link is None: |
436 return self._link | 438 return self._link |
437 | 439 |
438 try: | 440 try: |
439 # pytsk3 returns an UTF-8 encoded byte string without a leading | 441 # pytsk3 returns an UTF-8 encoded byte string without a leading |
440 # path segment separator. | 442 # path segment separator. |
441 link = u'{0:s}{1:s}'.format( | 443 link = '{0:s}{1:s}'.format( |
442 self._file_system.PATH_SEPARATOR, link.decode(u'utf8')) | 444 self._file_system.PATH_SEPARATOR, link.decode('utf8')) |
443 except UnicodeError: | 445 except UnicodeError: |
444 raise errors.BackEndError( | 446 raise errors.BackEndError( |
445 u'pytsk3 returned a non UTF-8 formatted link.') | 447 'pytsk3 returned a non UTF-8 formatted link.') |
446 | 448 |
447 self._link = link | 449 self._link = link |
448 | 450 |
449 return self._link | 451 return self._link |
450 | 452 |
451 def _GetStat(self): | 453 def _GetStat(self): |
452 """Retrieves the stat object. | 454 """Retrieves the stat object. |
453 | 455 |
454 Returns: | 456 Returns: |
455 VFSStat: stat object. | 457 VFSStat: stat object. |
456 """ | 458 """ |
457 stat_object = super(TSKFileEntry, self)._GetStat() | 459 stat_object = super(TSKFileEntry, self)._GetStat() |
458 | 460 |
459 # File data stat information. | 461 # File data stat information. |
460 stat_object.size = getattr(self._tsk_file.info.meta, u'size', None) | 462 stat_object.size = getattr(self._tsk_file.info.meta, 'size', None) |
461 | 463 |
462 # Date and time stat information. | 464 # Date and time stat information. |
463 stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple( | 465 stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple( |
464 self._tsk_file, u'bkup') | 466 self._tsk_file, 'bkup') |
465 if stat_time is not None: | 467 if stat_time is not None: |
466 stat_object.bkup = stat_time | 468 stat_object.bkup = stat_time |
467 stat_object.bkup_nano = stat_time_nano | 469 stat_object.bkup_nano = stat_time_nano |
468 | 470 |
469 stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple( | 471 stat_time, stat_time_nano = self._TSKFileTimeCopyToStatTimeTuple( |
470 self._tsk_file, u'dtime') | 472 self._tsk_file, 'dtime') |
471 if stat_time is not None: | 473 if stat_time is not None: |
472 stat_object.dtime = stat_time | 474 stat_object.dtime = stat_time |
473 stat_object.dtime_nano = stat_time_nano | 475 stat_object.dtime_nano = stat_time_nano |
474 | 476 |
475 # Ownership and permissions stat information. | 477 # Ownership and permissions stat information. |
476 mode = getattr(self._tsk_file.info.meta, u'mode', None) | 478 mode = getattr(self._tsk_file.info.meta, 'mode', None) |
477 if mode is not None: | 479 if mode is not None: |
478 # We need to cast mode to an int since it is of type | 480 # We need to cast mode to an int since it is of type |
479 # pytsk3.TSK_FS_META_MODE_ENUM. | 481 # pytsk3.TSK_FS_META_MODE_ENUM. |
480 stat_object.mode = int(mode) | 482 stat_object.mode = int(mode) |
481 | 483 |
482 stat_object.uid = getattr(self._tsk_file.info.meta, u'uid', None) | 484 stat_object.uid = getattr(self._tsk_file.info.meta, 'uid', None) |
483 stat_object.gid = getattr(self._tsk_file.info.meta, u'gid', None) | 485 stat_object.gid = getattr(self._tsk_file.info.meta, 'gid', None) |
484 | 486 |
485 # File entry type stat information. | 487 # File entry type stat information. |
486 | 488 |
487 # Other stat information. | 489 # Other stat information. |
488 stat_object.ino = getattr(self._tsk_file.info.meta, u'addr', None) | 490 stat_object.ino = getattr(self._tsk_file.info.meta, 'addr', None) |
489 # stat_object.dev = stat_info.st_dev | 491 # stat_object.dev = stat_info.st_dev |
490 # stat_object.nlink = getattr(self._tsk_file.info.meta, u'nlink', None) | 492 # stat_object.nlink = getattr(self._tsk_file.info.meta, 'nlink', None) |
491 # stat_object.fs_type = u'Unknown' | 493 # stat_object.fs_type = 'Unknown' |
492 | 494 |
493 flags = getattr(self._tsk_file.info.meta, u'flags', 0) | 495 flags = getattr(self._tsk_file.info.meta, 'flags', 0) |
494 | 496 |
495 # The flags are an instance of pytsk3.TSK_FS_META_FLAG_ENUM. | 497 # The flags are an instance of pytsk3.TSK_FS_META_FLAG_ENUM. |
496 if int(flags) & pytsk3.TSK_FS_META_FLAG_ALLOC: | 498 if int(flags) & pytsk3.TSK_FS_META_FLAG_ALLOC: |
497 stat_object.is_allocated = True | 499 stat_object.is_allocated = True |
498 else: | 500 else: |
499 stat_object.is_allocated = False | 501 stat_object.is_allocated = False |
500 | 502 |
501 return stat_object | 503 return stat_object |
502 | 504 |
503 def _GetTimeValue(self, name): | 505 def _GetTimeValue(self, name): |
504 """Retrieves a date and time value. | 506 """Retrieves a date and time value. |
505 | 507 |
506 Args: | 508 Args: |
507 name (str): name of the date and time value. | 509 name (str): name of the date and time value, for exmample "atime" or |
onager
2017/07/18 15:44:24
+for example, mtime, atime...
Joachim Metz
2017/07/18 19:40:37
Done.
| |
510 "mtime". | |
508 | 511 |
509 Returns: | 512 Returns: |
510 dfdatetime.DateTimeValues: date and time value or None if not available. | 513 dfdatetime.DateTimeValues: date and time value or None if not available. |
511 """ | 514 """ |
512 timestamp = getattr(self._tsk_file.info.meta, name, None) | 515 timestamp = getattr(self._tsk_file.info.meta, name, None) |
513 | 516 |
514 if self._file_system_type in self._TSK_HAS_NANO_FS_TYPES: | 517 if self._file_system_type in self._TSK_HAS_NANO_FS_TYPES: |
515 name_fragment = u'{0:s}_nano'.format(name) | 518 name_fragment = '{0:s}_nano'.format(name) |
516 timestamp_fragment = getattr( | 519 timestamp_fragment = getattr( |
517 self._tsk_file.info.meta, name_fragment, None) | 520 self._tsk_file.info.meta, name_fragment, None) |
518 else: | 521 else: |
519 timestamp_fragment = None | 522 timestamp_fragment = None |
520 | 523 |
521 return TSKTime(timestamp=timestamp, timestamp_fragment=timestamp_fragment) | 524 return TSKTime(timestamp=timestamp, timestamp_fragment=timestamp_fragment) |
522 | 525 |
523 def _TSKFileTimeCopyToStatTimeTuple(self, tsk_file, time_value): | 526 def _TSKFileTimeCopyToStatTimeTuple(self, tsk_file, time_value): |
524 """Copies a SleuthKit file object time value to a stat timestamp tuple. | 527 """Copies a SleuthKit file object time value to a stat timestamp tuple. |
525 | 528 |
526 Args: | 529 Args: |
527 tsk_file (pytsk3.File): TSK file. | 530 tsk_file (pytsk3.File): TSK file. |
528 time_value (str): name of the time value. | 531 time_value (str): name of the time value. |
529 | 532 |
530 Returns: | 533 Returns: |
531 tuple containing: | 534 tuple containing: |
532 int: POSIX timestamp in seconds. None on error, or if the file system | 535 int: POSIX timestamp in seconds. None on error, or if the file system |
533 does not include the requested timestamp. | 536 does not include the requested timestamp. |
534 int: remainder in 100 nano seconds. None on error, or if the file system | 537 int: remainder in 100 nano seconds. None on error, or if the file system |
535 does not support sub-second precision. | 538 does not support sub-second precision. |
536 | 539 |
537 Raises: | 540 Raises: |
538 BackEndError: if the TSK File .info, .info.meta or info.fs_info | 541 BackEndError: if the TSK File .info, .info.meta or info.fs_info |
539 attribute is missing. | 542 attribute is missing. |
540 """ | 543 """ |
541 if (not tsk_file or not tsk_file.info or not tsk_file.info.meta or | 544 if (not tsk_file or not tsk_file.info or not tsk_file.info.meta or |
542 not tsk_file.info.fs_info): | 545 not tsk_file.info.fs_info): |
543 raise errors.BackEndError( | 546 raise errors.BackEndError( |
544 u'Missing TSK File .info, .info.meta. or .info.fs_info') | 547 'Missing TSK File .info, .info.meta. or .info.fs_info') |
545 | 548 |
546 stat_time = getattr(tsk_file.info.meta, time_value, None) | 549 stat_time = getattr(tsk_file.info.meta, time_value, None) |
547 stat_time_nano = None | 550 stat_time_nano = None |
548 if self._file_system_type in self._TSK_HAS_NANO_FS_TYPES: | 551 if self._file_system_type in self._TSK_HAS_NANO_FS_TYPES: |
549 time_value_nano = u'{0:s}_nano'.format(time_value) | 552 time_value_nano = '{0:s}_nano'.format(time_value) |
550 stat_time_nano = getattr(tsk_file.info.meta, time_value_nano, None) | 553 stat_time_nano = getattr(tsk_file.info.meta, time_value_nano, None) |
551 | 554 |
552 # Sleuthkit 4.2.0 switched from 100 nano seconds precision to | 555 # Sleuthkit 4.2.0 switched from 100 nano seconds precision to |
553 # 1 nano seconds precision. | 556 # 1 nano seconds precision. |
554 if stat_time_nano is not None and pytsk3.TSK_VERSION_NUM >= 0x040200ff: | 557 if stat_time_nano is not None and pytsk3.TSK_VERSION_NUM >= 0x040200ff: |
555 stat_time_nano /= 100 | 558 stat_time_nano /= 100 |
556 | 559 |
557 return stat_time, stat_time_nano | 560 return stat_time, stat_time_nano |
558 | 561 |
559 @property | 562 @property |
560 def access_time(self): | 563 def access_time(self): |
561 """dfdatetime.DateTimeValues: access time or None if not available.""" | 564 """dfdatetime.DateTimeValues: access time or None if not available.""" |
562 if self._file_system_type in self._TSK_NO_ATIME_FS_TYPES: | 565 if self._file_system_type in self._TSK_NO_ATIME_FS_TYPES: |
563 return | 566 return |
564 | 567 |
565 return self._GetTimeValue(u'atime') | 568 return self._GetTimeValue('atime') |
566 | 569 |
567 @property | 570 @property |
568 def change_time(self): | 571 def change_time(self): |
569 """dfdatetime.DateTimeValues: change time or None if not available.""" | 572 """dfdatetime.DateTimeValues: change time or None if not available.""" |
570 if self._file_system_type in self._TSK_NO_CTIME_FS_TYPES: | 573 if self._file_system_type in self._TSK_NO_CTIME_FS_TYPES: |
571 return | 574 return |
572 | 575 |
573 return self._GetTimeValue(u'ctime') | 576 return self._GetTimeValue('ctime') |
574 | 577 |
575 @property | 578 @property |
576 def creation_time(self): | 579 def creation_time(self): |
577 """dfdatetime.DateTimeValues: creation time or None if not available.""" | 580 """dfdatetime.DateTimeValues: creation time or None if not available.""" |
578 if self._file_system_type in self._TSK_NO_CRTIME_FS_TYPES: | 581 if self._file_system_type in self._TSK_NO_CRTIME_FS_TYPES: |
579 return | 582 return |
580 | 583 |
581 return self._GetTimeValue(u'crtime') | 584 return self._GetTimeValue('crtime') |
582 | 585 |
583 @property | 586 @property |
584 def name(self): | 587 def name(self): |
585 """str: name of the file entry, which does not include the full path. | 588 """str: name of the file entry, which does not include the full path. |
586 | 589 |
587 Raises: | 590 Raises: |
588 BackEndError: if pytsk3 returns a non UTF-8 formatted name. | 591 BackEndError: if pytsk3 returns a non UTF-8 formatted name. |
589 """ | 592 """ |
590 if self._name is None: | 593 if self._name is None: |
591 # If pytsk3.FS_Info.open() was used file.info has an attribute name | 594 # If pytsk3.FS_Info.open() was used file.info has an attribute name |
592 # (pytsk3.TSK_FS_FILE) that contains the name string. Otherwise the | 595 # (pytsk3.TSK_FS_FILE) that contains the name string. Otherwise the |
593 # name from the path specification is used. | 596 # name from the path specification is used. |
594 if getattr(self._tsk_file.info, u'name', None) is not None: | 597 if getattr(self._tsk_file.info, 'name', None) is not None: |
595 name = getattr(self._tsk_file.info.name, u'name', None) | 598 name = getattr(self._tsk_file.info.name, 'name', None) |
596 | 599 |
597 try: | 600 try: |
598 # pytsk3 returns an UTF-8 encoded byte string. | 601 # pytsk3 returns an UTF-8 encoded byte string. |
599 self._name = name.decode(u'utf8') | 602 self._name = name.decode('utf8') |
600 except UnicodeError: | 603 except UnicodeError: |
601 raise errors.BackEndError( | 604 raise errors.BackEndError( |
602 u'pytsk3 returned a non UTF-8 formatted name.') | 605 'pytsk3 returned a non UTF-8 formatted name.') |
603 | 606 |
604 else: | 607 else: |
605 location = getattr(self.path_spec, u'location', None) | 608 location = getattr(self.path_spec, 'location', None) |
606 if location: | 609 if location: |
607 self._name = self._file_system.BasenamePath(location) | 610 self._name = self._file_system.BasenamePath(location) |
608 | 611 |
609 return self._name | 612 return self._name |
610 | 613 |
611 @property | 614 @property |
612 def modification_time(self): | 615 def modification_time(self): |
613 """dfdatetime.DateTimeValues: modification time or None if not available.""" | 616 """dfdatetime.DateTimeValues: modification time or None if not available.""" |
614 if self._file_system_type in self._TSK_NO_MTIME_FS_TYPES: | 617 if self._file_system_type in self._TSK_NO_MTIME_FS_TYPES: |
615 return | 618 return |
616 | 619 |
617 return self._GetTimeValue(u'mtime') | 620 return self._GetTimeValue('mtime') |
618 | 621 |
619 @property | 622 @property |
620 def sub_file_entries(self): | 623 def sub_file_entries(self): |
621 """generator(TSKFileEntry): sub file entries.""" | 624 """generator(TSKFileEntry): sub file entries.""" |
622 if self._directory is None: | 625 if self._directory is None: |
623 self._directory = self._GetDirectory() | 626 self._directory = self._GetDirectory() |
624 | 627 |
625 if self._directory: | 628 if self._directory: |
626 for path_spec in self._directory.entries: | 629 for path_spec in self._directory.entries: |
627 yield TSKFileEntry(self._resolver_context, self._file_system, path_spec) | 630 yield TSKFileEntry(self._resolver_context, self._file_system, path_spec) |
628 | 631 |
629 def GetFileObject(self, data_stream_name=u''): | 632 def GetFileObject(self, data_stream_name=''): |
630 """Retrieves the file-like object. | 633 """Retrieves the file-like object. |
631 | 634 |
632 Args: | 635 Args: |
633 data_stream_name (Optional[str]): data stream name, where an empty | 636 data_stream_name (Optional[str]): data stream name, where an empty |
634 string represents the default data stream. | 637 string represents the default data stream. |
635 | 638 |
636 Returns: | 639 Returns: |
637 TSKFileIO: file-like object or None. | 640 TSKFileIO: file-like object or None. |
638 """ | 641 """ |
639 data_stream_names = [ | 642 data_stream_names = [ |
640 data_stream.name for data_stream in self._GetDataStreams()] | 643 data_stream.name for data_stream in self._GetDataStreams()] |
641 if data_stream_name and data_stream_name not in data_stream_names: | 644 if data_stream_name and data_stream_name not in data_stream_names: |
642 return | 645 return |
643 | 646 |
644 path_spec = copy.deepcopy(self.path_spec) | 647 path_spec = copy.deepcopy(self.path_spec) |
645 if data_stream_name: | 648 if data_stream_name: |
646 setattr(path_spec, u'data_stream', data_stream_name) | 649 setattr(path_spec, 'data_stream', data_stream_name) |
647 | 650 |
648 return resolver.Resolver.OpenFileObject( | 651 return resolver.Resolver.OpenFileObject( |
649 path_spec, resolver_context=self._resolver_context) | 652 path_spec, resolver_context=self._resolver_context) |
650 | 653 |
651 def GetLinkedFileEntry(self): | 654 def GetLinkedFileEntry(self): |
652 """Retrieves the linked file entry, e.g. for a symbolic link. | 655 """Retrieves the linked file entry, e.g. for a symbolic link. |
653 | 656 |
654 Returns: | 657 Returns: |
655 TSKFileEntry: linked file entry or None. | 658 TSKFileEntry: linked file entry or None. |
656 """ | 659 """ |
657 link = self._GetLink() | 660 link = self._GetLink() |
658 if not link: | 661 if not link: |
659 return | 662 return |
660 | 663 |
661 # TODO: is there a way to determine the link inode number here? | 664 # TODO: is there a way to determine the link inode number here? |
662 link_inode = None | 665 link_inode = None |
663 | 666 |
664 parent_path_spec = getattr(self.path_spec, u'parent', None) | 667 parent_path_spec = getattr(self.path_spec, 'parent', None) |
665 path_spec = tsk_path_spec.TSKPathSpec( | 668 path_spec = tsk_path_spec.TSKPathSpec( |
666 location=link, parent=parent_path_spec) | 669 location=link, parent=parent_path_spec) |
667 | 670 |
668 root_inode = self._file_system.GetRootInode() | 671 root_inode = self._file_system.GetRootInode() |
669 if (link == self._file_system.LOCATION_ROOT or | 672 if (link == self._file_system.LOCATION_ROOT or |
670 (link_inode is not None and root_inode is not None and | 673 (link_inode is not None and root_inode is not None and |
671 link_inode == root_inode)): | 674 link_inode == root_inode)): |
672 is_root = True | 675 is_root = True |
673 else: | 676 else: |
674 is_root = False | 677 is_root = False |
675 | 678 |
676 return TSKFileEntry( | 679 return TSKFileEntry( |
677 self._resolver_context, self._file_system, path_spec, is_root=is_root) | 680 self._resolver_context, self._file_system, path_spec, is_root=is_root) |
678 | 681 |
679 def GetParentFileEntry(self): | 682 def GetParentFileEntry(self): |
680 """Retrieves the parent file entry. | 683 """Retrieves the parent file entry. |
681 | 684 |
682 Returns: | 685 Returns: |
683 TSKFileEntry: parent file entry or None. | 686 TSKFileEntry: parent file entry or None. |
684 """ | 687 """ |
685 location = getattr(self.path_spec, u'location', None) | 688 location = getattr(self.path_spec, 'location', None) |
686 if location is None: | 689 if location is None: |
687 return | 690 return |
688 parent_inode = self._parent_inode | 691 parent_inode = self._parent_inode |
689 parent_location = self._file_system.DirnamePath(location) | 692 parent_location = self._file_system.DirnamePath(location) |
690 if parent_inode is None and parent_location is None: | 693 if parent_inode is None and parent_location is None: |
691 return | 694 return |
692 if parent_location == u'': | 695 if parent_location == '': |
693 parent_location = self._file_system.PATH_SEPARATOR | 696 parent_location = self._file_system.PATH_SEPARATOR |
694 | 697 |
695 root_inode = self._file_system.GetRootInode() | 698 root_inode = self._file_system.GetRootInode() |
696 if (parent_location == self._file_system.LOCATION_ROOT or | 699 if (parent_location == self._file_system.LOCATION_ROOT or |
697 (parent_inode is not None and root_inode is not None and | 700 (parent_inode is not None and root_inode is not None and |
698 parent_inode == root_inode)): | 701 parent_inode == root_inode)): |
699 is_root = True | 702 is_root = True |
700 else: | 703 else: |
701 is_root = False | 704 is_root = False |
702 | 705 |
703 parent_path_spec = getattr(self.path_spec, u'parent', None) | 706 parent_path_spec = getattr(self.path_spec, 'parent', None) |
704 path_spec = tsk_path_spec.TSKPathSpec( | 707 path_spec = tsk_path_spec.TSKPathSpec( |
705 inode=parent_inode, location=parent_location, parent=parent_path_spec) | 708 inode=parent_inode, location=parent_location, parent=parent_path_spec) |
706 return TSKFileEntry( | 709 return TSKFileEntry( |
707 self._resolver_context, self._file_system, path_spec, is_root=is_root) | 710 self._resolver_context, self._file_system, path_spec, is_root=is_root) |
708 | 711 |
709 def GetTSKFile(self): | 712 def GetTSKFile(self): |
710 """Retrieves the SleuthKit file object. | 713 """Retrieves the SleuthKit file object. |
711 | 714 |
712 Returns: | 715 Returns: |
713 pytsk3.File: TSK file. | 716 pytsk3.File: TSK file. |
714 | 717 |
715 Raises: | 718 Raises: |
716 PathSpecError: if the path specification is missing inode and location. | 719 PathSpecError: if the path specification is missing inode and location. |
717 """ | 720 """ |
718 return self._tsk_file | 721 return self._tsk_file |
LEFT | RIGHT |