Skip to content

Commit

Permalink
Added GetExtents method to data stream #597 (#638)
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimmetz authored Jan 14, 2022
1 parent 26aa235 commit 823e978
Show file tree
Hide file tree
Showing 18 changed files with 902 additions and 440 deletions.
39 changes: 18 additions & 21 deletions dfvfs/vfs/apfs_file_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,31 +208,28 @@ def GetAPFSFileEntry(self):
"""
return self._fsapfs_file_entry

def GetExtents(self, data_stream_name=''):
"""Retrieves extents of a specific data stream.
Args:
data_stream_name (Optional[str]): data stream name, where an empty
string represents the default data stream.
def GetExtents(self):
"""Retrieves the extents.
Returns:
list[Extent]: extents of the data stream.
list[Extent]: the extents.
"""
if self.entry_type != definitions.FILE_ENTRY_TYPE_FILE:
return []

extents = []
if (self.entry_type == definitions.FILE_ENTRY_TYPE_FILE and
not data_stream_name):
for extent_index in range(self._fsapfs_file_entry.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fsapfs_file_entry.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)
for extent_index in range(self._fsapfs_file_entry.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fsapfs_file_entry.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)

return extents

Expand Down
25 changes: 21 additions & 4 deletions dfvfs/vfs/data_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,35 @@
class DataStream(object):
"""Data stream interface."""

# The data stream object should not have a reference to its
# file entry since that will create a cyclic reference.
def __init__(self, file_entry):
"""Initializes the data stream.
Args:
file_entry (FileEntry): file entry.
"""
super(DataStream, self).__init__()
self._file_entry = file_entry
self._name = ''

@property
def name(self):
"""str: name."""
return ''
return self._name

def GetExtents(self):
"""Retrieves the extents.
Returns:
list[Extent]: the extents of the data stream.
"""
if self._file_entry:
return self._file_entry.GetExtents()
return []

def IsDefault(self):
"""Determines if the data stream is the default data stream.
Returns:
bool: True if the data stream is the default data stream.
"""
return True
return not bool(self._name)
39 changes: 18 additions & 21 deletions dfvfs/vfs/ext_file_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,31 +245,28 @@ def size(self):
"""int: size of the file entry in bytes or None if not available."""
return self._fsext_file_entry.size

def GetExtents(self, data_stream_name=''):
"""Retrieves extents of a specific data stream.
Args:
data_stream_name (Optional[str]): data stream name, where an empty
string represents the default data stream.
def GetExtents(self):
"""Retrieves the extents.
Returns:
list[Extent]: extents of the data stream.
list[Extent]: the extents.
"""
if self.entry_type != definitions.FILE_ENTRY_TYPE_FILE:
return []

extents = []
if (self.entry_type == definitions.FILE_ENTRY_TYPE_FILE and
not data_stream_name):
for extent_index in range(self._fsext_file_entry.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fsext_file_entry.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)
for extent_index in range(self._fsext_file_entry.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fsext_file_entry.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)

return extents

Expand Down
12 changes: 4 additions & 8 deletions dfvfs/vfs/file_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def _GetDataStreams(self):

# It is assumed that non-file file entries do not have data streams.
if self.entry_type == definitions.FILE_ENTRY_TYPE_FILE:
data_stream_object = data_stream.DataStream()
data_stream_object = data_stream.DataStream(self)
self._data_streams.append(data_stream_object)

return self._data_streams
Expand Down Expand Up @@ -308,15 +308,11 @@ def GetDataStream(self, name, case_sensitive=True):

return matching_data_stream

def GetExtents(self, data_stream_name=''): # pylint: disable=unused-argument
"""Retrieves extents of a specific data stream.
Args:
data_stream_name (Optional[str]): data stream name, where an empty
string represents the default data stream.
def GetExtents(self):
"""Retrieves the extents.
Returns:
list[Extent]: extents of the data stream.
list[Extent]: the extents.
"""
return []

Expand Down
40 changes: 27 additions & 13 deletions dfvfs/vfs/hfs_data_stream.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,48 @@
# -*- coding: utf-8 -*-
"""The HFS data stream implementation."""

from dfvfs.lib import definitions
from dfvfs.vfs import data_stream
from dfvfs.vfs import extent


class HFSDataStream(data_stream.DataStream):
"""File system data stream that uses pyfshfs."""

def __init__(self, fshfs_data_stream):
"""Initializes the data stream.
def __init__(self, file_entry, fshfs_data_stream):
"""Initializes a HFS data stream.
Args:
file_entry (FileEntry): file entry.
fshfs_data_stream (pyfshfs.data_stream): HFS data stream.
"""
super(HFSDataStream, self).__init__()
super(HFSDataStream, self).__init__(file_entry)
self._fshfs_data_stream = fshfs_data_stream
self._name = ''

if fshfs_data_stream:
self._name = 'rsrc'

@property
def name(self):
"""str: name."""
return self._name

def IsDefault(self):
"""Determines if the data stream is the default (data fork) data stream.
def GetExtents(self):
"""Retrieves the extents.
Returns:
bool: True if the data stream is the default (data fork) data stream.
list[Extent]: the extents of the data stream.
"""
return not self._fshfs_data_stream
if not self._fshfs_data_stream:
return super(HFSDataStream, self).GetExtents()

extents = []
for extent_index in range(self._fshfs_data_stream.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fshfs_data_stream.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)

return extents
59 changes: 20 additions & 39 deletions dfvfs/vfs/hfs_file_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,12 @@ def _GetDataStreams(self):
self._data_streams = []

if self.entry_type == definitions.FILE_ENTRY_TYPE_FILE:
data_stream = hfs_data_stream.HFSDataStream(None)
data_stream = hfs_data_stream.HFSDataStream(self, None)
self._data_streams.append(data_stream)

fshfs_data_stream = self._fshfs_file_entry.get_resource_fork()
if fshfs_data_stream:
data_stream = hfs_data_stream.HFSDataStream(fshfs_data_stream)
data_stream = hfs_data_stream.HFSDataStream(self, fshfs_data_stream)
self._data_streams.append(data_stream)

return self._data_streams
Expand Down Expand Up @@ -246,47 +246,28 @@ def size(self):
"""int: size of the file entry in bytes or None if not available."""
return self._fshfs_file_entry.size

def GetExtents(self, data_stream_name=''):
"""Retrieves extents of a specific data stream.
Args:
data_stream_name (Optional[str]): data stream name, where an empty
string represents the default data stream.
def GetExtents(self):
"""Retrieves the extents.
Returns:
list[Extent]: extents of the data stream.
list[Extent]: the extents.
"""
if self.entry_type != definitions.FILE_ENTRY_TYPE_FILE:
return []

extents = []
if (self.entry_type == definitions.FILE_ENTRY_TYPE_FILE and
not data_stream_name):
for extent_index in range(self._fshfs_file_entry.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fshfs_file_entry.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)

elif data_stream_name == 'rsrc':
fshfs_data_stream = self._fshfs_file_entry.get_resource_fork()
if fshfs_data_stream:
for extent_index in range(fshfs_data_stream.number_of_extents):
extent_offset, extent_size, extent_flags = (
fshfs_data_stream.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)
for extent_index in range(self._fshfs_file_entry.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fshfs_file_entry.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)

return extents

Expand Down
42 changes: 30 additions & 12 deletions dfvfs/vfs/ntfs_data_stream.py
Original file line number Diff line number Diff line change
@@ -1,30 +1,48 @@
# -*- coding: utf-8 -*-
"""The NTFS data stream implementation."""

from dfvfs.lib import definitions
from dfvfs.vfs import data_stream
from dfvfs.vfs import extent


class NTFSDataStream(data_stream.DataStream):
"""File system data stream that uses pyfsntfs."""

def __init__(self, fsntfs_data_stream):
"""Initializes the data stream.
def __init__(self, file_entry, fsntfs_data_stream):
"""Initializes a NTFS data stream.
Args:
file_entry (FileEntry): file entry.
fsntfs_data_stream (pyfsntfs.data_stream): NTFS data stream.
"""
super(NTFSDataStream, self).__init__()
self._name = getattr(fsntfs_data_stream, 'name', None) or ''
super(NTFSDataStream, self).__init__(file_entry)
self._fsntfs_data_stream = fsntfs_data_stream

@property
def name(self):
"""str: name."""
return self._name
if fsntfs_data_stream:
self._name = fsntfs_data_stream.name

def IsDefault(self):
"""Determines if the data stream is the default data stream.
def GetExtents(self):
"""Retrieves the extents.
Returns:
bool: True if the data stream is the default data stream.
list[Extent]: the extents of the data stream.
"""
return not bool(self._name)
if not self._fsntfs_data_stream:
return super(NTFSDataStream, self).GetExtents()

extents = []
for extent_index in range(self._fsntfs_data_stream.number_of_extents):
extent_offset, extent_size, extent_flags = (
self._fsntfs_data_stream.get_extent(extent_index))

if extent_flags & 0x1:
extent_type = definitions.EXTENT_TYPE_SPARSE
else:
extent_type = definitions.EXTENT_TYPE_DATA

data_stream_extent = extent.Extent(
extent_type=extent_type, offset=extent_offset, size=extent_size)
extents.append(data_stream_extent)

return extents
Loading

0 comments on commit 823e978

Please sign in to comment.