Skip to content

Commit

Permalink
dfdatetime2
Browse files Browse the repository at this point in the history
  • Loading branch information
joachimmetz committed Jul 4, 2017
1 parent 62ae450 commit 4484ecf
Show file tree
Hide file tree
Showing 25 changed files with 922 additions and 719 deletions.
1 change: 0 additions & 1 deletion dfvfs/vfs/bde_file_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ def _GetStat(self):
"""
stat_object = super(BDEFileEntry, self)._GetStat()

# File data stat information.
stat_object.size = self._bde_volume.get_size()

return stat_object
Expand Down
57 changes: 37 additions & 20 deletions dfvfs/vfs/compressed_stream_file_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,46 +3,63 @@

from dfvfs.lib import definitions
from dfvfs.lib import errors
from dfvfs.resolver import resolver
from dfvfs.vfs import root_only_file_entry
from dfvfs.vfs import vfs_stat


class CompressedStreamFileEntry(root_only_file_entry.RootOnlyFileEntry):
"""Class that implements a compressed stream file entry object."""
"""Compressed stream file entry."""

TYPE_INDICATOR = definitions.TYPE_INDICATOR_COMPRESSED_STREAM

def _GetStat(self):
"""Retrieves the stat object.
def __init__(
self, resolver_context, file_system, path_spec, is_root=False,
is_virtual=False):
"""Initializes a file entry.
Returns:
The stat object (instance of vfs.VFSStat).
Args:
resolver_context (Context): resolver context.
file_system (FileSystem): file system.
path_spec (PathSpec): path specification.
is_root (Optional[bool]): True if the file entry is the root file entry
of the corresponding file system.
is_virtual (Optional[bool]): True if the file entry is a virtual file
Raises:
BackEndError: when the compressed stream is missing.
"""
compressed_stream = self.GetFileObject()
compressed_stream = resolver.Resolver.OpenFileObject(
path_spec, resolver_context=resolver_context)
if not compressed_stream:
raise errors.BackEndError(
u'Unable to open compressed stream: {0:s}.'.format(
self.path_spec.comparable))
raise errors.BackEndError(u'Missing compressed stream.')

try:
stat_object = vfs_stat.VFSStat()
super(CompressedStreamFileEntry, self).__init__(
resolver_context, file_system, path_spec, is_root=is_root,
is_virtual=is_virtual)
self._compressed_stream = compressed_stream
self._type = definitions.FILE_ENTRY_TYPE_FILE

# File data stat information.
stat_object.size = compressed_stream.get_size()
def __del__(self):
"""Cleans up the file entry."""
# __del__ can be invoked before __init__ has completed.
if hasattr(self, u'_compressed_stream'):
self._compressed_stream.close()
self._compressed_stream = None

# Date and time stat information.
super(CompressedStreamFileEntry, self).__del__()

# Ownership and permissions stat information.
def _GetStat(self):
"""Retrieves information about the file entry.
# File entry type stat information.
stat_object.type = stat_object.TYPE_FILE
Returns:
VFSStat: a stat object.
"""
stat_object = vfs_stat.VFSStat()

# Other stat information.
if self._compressed_stream:
stat_object.size = self._compressed_stream.get_size()

finally:
compressed_stream.close()
stat_object.type = self._type

return stat_object
203 changes: 98 additions & 105 deletions dfvfs/vfs/cpio_file_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@

import stat

from dfdatetime import posix_time as dfdatetime_posix_time

from dfvfs.lib import definitions
from dfvfs.lib import errors
from dfvfs.path import cpio_path_spec
from dfvfs.vfs import file_entry
from dfvfs.vfs import vfs_stat


class CPIODirectory(file_entry.Directory):
"""Class that implements a directory object using CPIOArchiveFile."""
"""File system directory that uses CPIOArchiveFile."""

def _EntriesGenerator(self):
"""Retrieves directory entries.
Expand All @@ -20,7 +21,7 @@ def _EntriesGenerator(self):
a generator is more memory efficient.
Yields:
A path specification (instance of path.CPIOPathSpec).
CPIOPathSpec: path specification.
"""
location = getattr(self.path_spec, u'location', None)

Expand Down Expand Up @@ -48,139 +49,135 @@ def _EntriesGenerator(self):


class CPIOFileEntry(file_entry.FileEntry):
"""Class that implements a file entry object using CPIOArchiveFile."""
"""File system file entry that uses CPIOArchiveFile."""

TYPE_INDICATOR = definitions.TYPE_INDICATOR_CPIO

def __init__(
self, resolver_context, file_system, path_spec, is_root=False,
is_virtual=False, cpio_archive_file_entry=None):
"""Initializes the file entry object.
self, resolver_context, file_system, path_spec,
cpio_archive_file_entry=None, is_root=False, is_virtual=False):
"""Initializes a file entry object.
Args:
resolver_context: the resolver context (instance of resolver.Context).
file_system: the file system object (instance of FileSystem).
path_spec: the path specification (instance of PathSpec).
is_root: optional boolean value to indicate if the file entry is
the root file entry of the corresponding file system.
is_virtual: optional boolean value to indicate if the file entry is
a virtual file entry emulated by the corresponding file
system.
cpio_archive_file_entry: optional CPIO archive file entry object
(instance of cpio.CPIOArchiveFileEntry).
resolver_context (Context): resolver context.
file_system (FileSystem): file system.
path_spec (PathSpec): path specification.
cpio_archive_file_entry (Optional[CPIOArchiveFileEntry]): CPIO archive
file entry.
is_root (Optional[bool]): True if the file entry is the root file entry
of the corresponding file system.
is_virtual (Optional[bool]): True if the file entry is a virtual file
entry emulated by the corresponding file system.
Raises:
BackEndError: when the CPIO archive file entry is missing in
a non-virtual file entry.
"""
if not is_virtual and cpio_archive_file_entry is None:
cpio_archive_file_entry = file_system.GetCPIOArchiveFileEntryByPathSpec(
path_spec)
if not is_virtual and cpio_archive_file_entry is None:
raise errors.BackEndError(
u'Missing CPIO archive file entry in non-virtual file entry.')

super(CPIOFileEntry, self).__init__(
resolver_context, file_system, path_spec, is_root=is_root,
is_virtual=is_virtual)
self._cpio_archive_file_entry = cpio_archive_file_entry

# The stat info member st_mode can have multiple types e.g.
# LINK and DIRECTORY in case of a symbolic link to a directory
# dfVFS currently only supports one type so we need to check
# for LINK first.
mode = getattr(cpio_archive_file_entry, u'mode', 0)
if stat.S_ISLNK(mode):
self._type = definitions.FILE_ENTRY_TYPE_LINK
# The root file entry is virtual and should have type directory.
elif is_virtual or stat.S_ISDIR(mode):
self._type = definitions.FILE_ENTRY_TYPE_DIRECTORY
elif stat.S_ISREG(mode):
self._type = definitions.FILE_ENTRY_TYPE_FILE
elif stat.S_ISCHR(mode) or stat.S_ISBLK(mode):
self._type = definitions.FILE_ENTRY_TYPE_DEVICE
elif stat.S_ISFIFO(mode):
self._type = definitions.FILE_ENTRY_TYPE_PIPE
elif stat.S_ISSOCK(mode):
self._type = definitions.FILE_ENTRY_TYPE_SOCKET

def _GetDirectory(self):
"""Retrieves a directory.
Returns:
A directory object (instance of Directory) or None.
CPIODirectory: a directory or None if not available.
"""
if self._stat_object is None:
self._stat_object = self._GetStat()

if (self._stat_object and
self._stat_object.type == self._stat_object.TYPE_DIRECTORY):
if self._type == definitions.FILE_ENTRY_TYPE_DIRECTORY:
return CPIODirectory(self._file_system, self.path_spec)
return

def _GetLink(self):
"""Retrieves the link.
Raises:
BackEndError: when the CPIO archive file entry is missing in
a non-virtual file entry.
Returns:
str: full path of the linked file entry.
"""
if self._link is None:
cpio_archive_file_entry = self.GetCPIOArchiveFileEntry()
if not self._is_virtual and cpio_archive_file_entry is None:
raise errors.BackEndError(
u'Missing CPIO archive file entry in non-virtual file entry.')

self._link = u''
if stat.S_ISLNK(cpio_archive_file_entry.mode):
cpio_archive_file = self._file_system.GetCPIOArchiveFile()
link_data = cpio_archive_file.ReadDataAtOffset(
cpio_archive_file_entry.data_offset,
cpio_archive_file_entry.data_size)

# TODO: should this be ASCII?
self._link = link_data.decode(u'ascii')
if self._type != definitions.FILE_ENTRY_TYPE_LINK:
return self._link

cpio_archive_file = self._file_system.GetCPIOArchiveFile()
link_data = cpio_archive_file.ReadDataAtOffset(
self._cpio_archive_file_entry.data_offset,
self._cpio_archive_file_entry.data_size)

# TODO: should this be ASCII?
self._link = link_data.decode(u'ascii')

return self._link

def _GetStat(self):
"""Retrieves the stat object.
"""Retrieves information about the file entry.
Returns:
The stat object (instance of vfs.VFSStat).
Raises:
BackEndError: when the CPIO archive file entry is missing in
a non-virtual file entry.
VFSStat: a stat object.
"""
cpio_archive_file_entry = self.GetCPIOArchiveFileEntry()
if not self._is_virtual and cpio_archive_file_entry is None:
raise errors.BackEndError(
u'Missing CPIO archive file entry in non-virtual file entry.')

stat_object = vfs_stat.VFSStat()
stat_object = super(CPIOFileEntry, self)._GetStat()

# File data stat information.
stat_object.size = getattr(cpio_archive_file_entry, u'data_size', None)

# Date and time stat information.
stat_object.mtime = getattr(
cpio_archive_file_entry, u'modification_time', None)
stat_object.size = getattr(
self._cpio_archive_file_entry, u'data_size', None)

# Ownership and permissions stat information.
mode = getattr(cpio_archive_file_entry, u'mode', 0)
mode = getattr(self._cpio_archive_file_entry, u'mode', 0)
stat_object.mode = stat.S_IMODE(mode)
stat_object.uid = getattr(
cpio_archive_file_entry, u'user_identifier', None)
self._cpio_archive_file_entry, u'user_identifier', None)
stat_object.gid = getattr(
cpio_archive_file_entry, u'group_identifier', None)

# File entry type stat information.

# The stat info member st_mode can have multiple types e.g.
# LINK and DIRECTORY in case of a symbolic link to a directory
# dfVFS currently only supports one type so we need to check
# for LINK first.
if stat.S_ISLNK(mode):
stat_object.type = stat_object.TYPE_LINK
# The root file entry is virtual and should have type directory.
elif self._is_virtual or stat.S_ISDIR(mode):
stat_object.type = stat_object.TYPE_DIRECTORY
elif stat.S_ISREG(mode):
stat_object.type = stat_object.TYPE_FILE
elif stat.S_ISCHR(mode) or stat.S_ISBLK(mode):
stat_object.type = stat_object.TYPE_DEVICE
elif stat.S_ISFIFO(mode):
stat_object.type = stat_object.TYPE_PIPE
elif stat.S_ISSOCK(mode):
stat_object.type = stat_object.TYPE_SOCKET
self._cpio_archive_file_entry, u'group_identifier', None)

return stat_object

@property
def name(self):
"""The name of the file entry, which does not include the full path."""
cpio_archive_file_entry = self.GetCPIOArchiveFileEntry()

"""str: name of the file entry, which does not include the full path."""
# Note that the root file entry is virtual and has no
# cpio_archive_file_entry.
if cpio_archive_file_entry is None:
if self._cpio_archive_file_entry is None:
return u''

return self._file_system.BasenamePath(cpio_archive_file_entry.path)
return self._file_system.BasenamePath(self._cpio_archive_file_entry.path)

@property
def modification_time(self):
"""dfdatetime.DateTimeValues: modification time or None if not available."""
timestamp = getattr(
self._cpio_archive_file_entry, u'modification_time', None)
if timestamp is not None:
return dfdatetime_posix_time.PosixTime(timestamp=timestamp)

@property
def sub_file_entries(self):
"""The sub file entries (generator of instance of vfs.FileEntry)."""
"""generator(CPIOFileEntry): sub file entries."""
if self._directory is None:
self._directory = self._GetDirectory()

Expand All @@ -193,42 +190,38 @@ def GetCPIOArchiveFileEntry(self):
"""Retrieves the CPIO archive file entry object.
Returns:
The CPIO archive file entry object (instance of
cpio.CPIOArchiveFileEntry).
CPIOArchiveFileEntry: CPIO archive file entry.
Raises:
ValueError: if the path specification is incorrect.
PathSpecError: if the path specification is incorrect.
"""
if not self._cpio_archive_file_entry:
location = getattr(self.path_spec, u'location', None)
if location is None:
raise ValueError(u'Path specification missing location.')

if not location.startswith(self._file_system.LOCATION_ROOT):
raise ValueError(u'Invalid location in path specification.')

if len(location) == 1:
return

cpio_archive_file = self._file_system.GetCPIOArchiveFile()
self._cpio_archive_file_entry = cpio_archive_file.GetFileEntryByPath(
location[1:])

return self._cpio_archive_file_entry

def GetParentFileEntry(self):
"""Retrieves the parent file entry."""
"""Retrieves the parent file entry.
Returns:
CPIOFileEntry: parent file entry or None if not available.
"""
location = getattr(self.path_spec, u'location', None)
if location is None:
return

parent_location = self._file_system.DirnamePath(location)
if parent_location is None:
return

if parent_location == u'':
parent_location = self._file_system.PATH_SEPARATOR
is_root = True
is_virtual = True
else:
is_root = False
is_virtual = False

parent_path_spec = getattr(self.path_spec, u'parent', None)
path_spec = cpio_path_spec.CPIOPathSpec(
location=parent_location, parent=parent_path_spec)
return CPIOFileEntry(self._resolver_context, self._file_system, path_spec)
return CPIOFileEntry(
self._resolver_context, self._file_system, path_spec,
is_root=is_root, is_virtual=is_virtual)
Loading

0 comments on commit 4484ecf

Please sign in to comment.