diff --git a/.pylintrc b/.pylintrc index f5bdb2e0..0bd6276c 100644 --- a/.pylintrc +++ b/.pylintrc @@ -26,7 +26,7 @@ jobs=1 # List of plugins (as comma separated values of python modules names) to load, # usually to register additional checkers. -load-plugins= +load-plugins=pylint.extensions.docparams # Pickle collected data for later comparisons. persistent=yes @@ -56,22 +56,23 @@ confidence= # --disable=W" # disable= - duplicate-code, - parameter-unpacking, - raw-checker-failed, + assignment-from-none, bad-inline-option, - locally-disabled, - locally-enabled, - file-ignored, - suppressed-message, - useless-suppression, deprecated-pragma, - no-absolute-import, - metaclass-assignment, + duplicate-code, eq-without-hash, + file-ignored, fixme, + locally-disabled, + locally-enabled, logging-format-interpolation, + metaclass-assignment, + missing-param-doc, + no-absolute-import, no-self-use, + parameter-unpacking, + raw-checker-failed, + suppressed-message, too-few-public-methods, too-many-ancestors, too-many-boolean-expressions, @@ -83,7 +84,9 @@ disable= too-many-public-methods, too-many-return-statements, too-many-statements, - unsubscriptable-object + unsubscriptable-object, + useless-object-inheritance, + useless-suppression # Enable the message, report, category or checker with the given id(s). You can # either give multiple identifier separated by comma (,) or put this option diff --git a/dfvfs/analyzer/analyzer_helper.py b/dfvfs/analyzer/analyzer_helper.py index 101388a9..83a67ffd 100644 --- a/dfvfs/analyzer/analyzer_helper.py +++ b/dfvfs/analyzer/analyzer_helper.py @@ -7,10 +7,13 @@ class AnalyzerHelper(object): """Analyzer helper interface.""" + # pylint: disable=missing-raises-doc,redundant-returns-doc + @property def format_categories(self): - """set[str]: format categories, such as archive file or file system and - are defined in defintions.FORMAT_CATEGORIES. + """set[str]: format categories, such as archive file or file system. + + The format categories are defined in definitions.FORMAT_CATEGORIES. """ format_categories = getattr(self, 'FORMAT_CATEGORIES', None) if format_categories is None: diff --git a/dfvfs/analyzer/specification.py b/dfvfs/analyzer/specification.py index 858671e3..000f7f5e 100644 --- a/dfvfs/analyzer/specification.py +++ b/dfvfs/analyzer/specification.py @@ -132,9 +132,8 @@ def AddSpecification(self, specification): specification.identifier, signature_index) if signature_identifier in self._signature_map: - raise KeyError( - 'Signature {0:s} is already defined in map.'.format( - signature_identifier)) + raise KeyError('Signature {0:s} is already defined in map.'.format( + signature_identifier)) signature.SetIdentifier(signature_identifier) self._signature_map[signature_identifier] = specification @@ -143,7 +142,8 @@ def GetSpecificationBySignature(self, signature_identifier): """Retrieves a specification mapped to a signature identifier. Args: - identifier (str): unique signature identifier for a specification store. + signature_identifier (str): unique signature identifier for + a specification store. Returns: FormatSpecification: A format specification or None if the signature diff --git a/dfvfs/analyzer/tsk_partition_analyzer_helper.py b/dfvfs/analyzer/tsk_partition_analyzer_helper.py index 018ea753..72eee1f0 100644 --- a/dfvfs/analyzer/tsk_partition_analyzer_helper.py +++ b/dfvfs/analyzer/tsk_partition_analyzer_helper.py @@ -34,7 +34,7 @@ def AnalyzeFileObject(self, file_object): try: pytsk3.Volume_Info(tsk_image_object) except IOError: - return + return None return self.type_indicator diff --git a/dfvfs/compression/decompressor.py b/dfvfs/compression/decompressor.py index aebeb16a..5f4de63f 100644 --- a/dfvfs/compression/decompressor.py +++ b/dfvfs/compression/decompressor.py @@ -9,6 +9,8 @@ class Decompressor(object): """Decompressor interface.""" + # pylint: disable=redundant-returns-doc + @abc.abstractmethod def Decompress(self, compressed_data): """Decompresses the compressed data. diff --git a/dfvfs/compression/manager.py b/dfvfs/compression/manager.py index 2c5b727f..6222b7d6 100644 --- a/dfvfs/compression/manager.py +++ b/dfvfs/compression/manager.py @@ -41,7 +41,7 @@ def GetDecompressor(cls, compression_method): compression_method = compression_method.lower() decompressor = cls._decompressors.get(compression_method, None) if not decompressor: - return + return None return decompressor() diff --git a/dfvfs/credentials/manager.py b/dfvfs/credentials/manager.py index 48c80e05..b40415da 100644 --- a/dfvfs/credentials/manager.py +++ b/dfvfs/credentials/manager.py @@ -48,7 +48,7 @@ def GetCredentials(cls, path_spec): credentials support. """ if not path_spec: - return + return None return cls._credentials.get(path_spec.type_indicator, None) diff --git a/dfvfs/encoding/decoder.py b/dfvfs/encoding/decoder.py index 1ec6014e..54fad36d 100644 --- a/dfvfs/encoding/decoder.py +++ b/dfvfs/encoding/decoder.py @@ -9,6 +9,8 @@ class Decoder(object): """Decoder interface.""" + # pylint: disable=redundant-returns-doc + @abc.abstractmethod def Decode(self, encoded_data): """Decodes the encoded data. diff --git a/dfvfs/encoding/manager.py b/dfvfs/encoding/manager.py index b464155a..84583169 100644 --- a/dfvfs/encoding/manager.py +++ b/dfvfs/encoding/manager.py @@ -40,7 +40,7 @@ def GetDecoder(cls, encoding_method): encoding_method = encoding_method.lower() decoder = cls._decoders.get(encoding_method, None) if not decoder: - return + return None return decoder() diff --git a/dfvfs/encryption/decrypter.py b/dfvfs/encryption/decrypter.py index 6d146ab3..5430d7b8 100644 --- a/dfvfs/encryption/decrypter.py +++ b/dfvfs/encryption/decrypter.py @@ -24,6 +24,7 @@ def __init__(self, **kwargs): super(Decrypter, self).__init__() + # pylint: disable=redundant-returns-doc @abc.abstractmethod def Decrypt(self, encrypted_data): """Decrypts the encrypted data. @@ -32,5 +33,5 @@ def Decrypt(self, encrypted_data): encrypted_data (bytes): encrypted data. Returns: - tuple[bytes,bytes]: decrypted data and remaining encrypted data. + tuple[bytes, bytes]: decrypted data and remaining encrypted data. """ diff --git a/dfvfs/encryption/manager.py b/dfvfs/encryption/manager.py index d6ae29f2..4ad53d80 100644 --- a/dfvfs/encryption/manager.py +++ b/dfvfs/encryption/manager.py @@ -44,7 +44,7 @@ def GetDecrypter(cls, encryption_method, **kwargs): encryption_method = encryption_method.lower() decrypter = cls._decrypters.get(encryption_method, None) if not decrypter: - return + return None return decrypter(**kwargs) diff --git a/dfvfs/file_io/compressed_stream_io.py b/dfvfs/file_io/compressed_stream_io.py index 335682ff..e6a4dfef 100644 --- a/dfvfs/file_io/compressed_stream_io.py +++ b/dfvfs/file_io/compressed_stream_io.py @@ -109,6 +109,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -197,6 +198,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -271,6 +273,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -309,6 +312,7 @@ def get_offset(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -323,6 +327,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/cpio_file_io.py b/dfvfs/file_io/cpio_file_io.py index 85b2827c..b84fdf36 100644 --- a/dfvfs/file_io/cpio_file_io.py +++ b/dfvfs/file_io/cpio_file_io.py @@ -43,6 +43,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -82,6 +83,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -115,6 +117,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -139,6 +142,7 @@ def get_offset(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -153,6 +157,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/data_range_io.py b/dfvfs/file_io/data_range_io.py index 9908f2f0..0e72a956 100644 --- a/dfvfs/file_io/data_range_io.py +++ b/dfvfs/file_io/data_range_io.py @@ -65,6 +65,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -99,6 +100,7 @@ def SetRange(self, range_offset, range_size): Raises: IOError: if the file-like object is already open. + OSError: if the file-like object is already open. ValueError: if the range offset or range size is invalid. """ if self._is_open: @@ -137,6 +139,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -176,6 +179,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -203,6 +207,7 @@ def get_offset(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -217,6 +222,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/encoded_stream_io.py b/dfvfs/file_io/encoded_stream_io.py index 4da9ec2b..f4f15b68 100644 --- a/dfvfs/file_io/encoded_stream_io.py +++ b/dfvfs/file_io/encoded_stream_io.py @@ -107,6 +107,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -187,6 +188,7 @@ def SetDecodedStreamSize(self, decoded_stream_size): Raises: IOError: if the file-like object is already open. + OSError: if the file-like object is already open. ValueError: if the decoded stream size is invalid. """ if self._is_open: @@ -218,6 +220,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -292,6 +295,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -330,6 +334,7 @@ def get_offset(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -344,6 +349,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/encrypted_stream_io.py b/dfvfs/file_io/encrypted_stream_io.py index a74672e3..ea423144 100644 --- a/dfvfs/file_io/encrypted_stream_io.py +++ b/dfvfs/file_io/encrypted_stream_io.py @@ -73,6 +73,7 @@ def _GetDecrypter(self): Raises: IOError: if the decrypter cannot be initialized. + OSError: if the decrypter cannot be initialized. """ resolver.Resolver.key_chain.ExtractCredentialsFromPathSpec(self._path_spec) @@ -118,6 +119,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -200,6 +202,7 @@ def SetDecryptedStreamSize(self, decrypted_stream_size): Raises: IOError: if the file-like object is already open. + OSError: if the file-like object is already open. ValueError: if the decrypted stream size is invalid. """ if self._is_open: @@ -231,6 +234,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -305,6 +309,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -338,11 +343,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the decrypted stream. - Return: + Returns: int: current offset into the decrypted stream. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -357,6 +363,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/ewf_file_io.py b/dfvfs/file_io/ewf_file_io.py index a59cd859..ce586ab2 100644 --- a/dfvfs/file_io/ewf_file_io.py +++ b/dfvfs/file_io/ewf_file_io.py @@ -47,7 +47,7 @@ def _OpenFileObject(self, path_spec): path_spec (PathSpec): path specification. Returns: - FileIO: a file-like object or None. + pyewf.handle: a file-like object or None. Raises: PathSpecError: if the path specification is invalid. @@ -65,7 +65,7 @@ def _OpenFileObject(self, path_spec): # handle the file system abstraction dfvfs provides. segment_file_path_specs = ewf.EWFGlobPathSpec(file_system, path_spec) if not segment_file_path_specs: - return + return None if parent_path_spec.IsSystemLevel(): # Typically the file-like object cache should have room for 127 items. @@ -89,6 +89,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/fake_file_io.py b/dfvfs/file_io/fake_file_io.py index 4d3529da..acf8f65c 100644 --- a/dfvfs/file_io/fake_file_io.py +++ b/dfvfs/file_io/fake_file_io.py @@ -38,6 +38,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -73,6 +74,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -104,6 +106,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -123,8 +126,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. + Returns: + int: current offset into the file-like object. + Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -139,6 +146,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/file_io.py b/dfvfs/file_io/file_io.py index eb91fad2..f27fb9fa 100644 --- a/dfvfs/file_io/file_io.py +++ b/dfvfs/file_io/file_io.py @@ -10,6 +10,8 @@ class FileIO(object): """VFS file-like object interface.""" + # pylint: disable=redundant-returns-doc + def __init__(self, resolver_context): """Initializes a file-like object. @@ -27,6 +29,7 @@ def _Close(self): Raises: IOError: if the close failed. + OSError: if the close failed. """ @abc.abstractmethod @@ -40,6 +43,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -58,6 +62,7 @@ def open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object was already opened or the open failed. + OSError: if the file-like object was already opened or the open failed. PathSpecError: if the path specification is incorrect. ValueError: if the path specification or mode is invalid. """ @@ -83,6 +88,7 @@ def close(self): Raises: IOError: if the file-like object was not opened or the close failed. + OSError: if the file-like object was not opened or the close failed. """ if not self._is_open: raise IOError('Not opened.') @@ -115,6 +121,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ @abc.abstractmethod @@ -128,6 +135,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ # get_offset() is preferred above tell() by the libbfio layer used in libyal. @@ -135,11 +143,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ # Pythonesque alias for get_offset(). @@ -156,6 +165,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ def seekable(self): diff --git a/dfvfs/file_io/file_object_io.py b/dfvfs/file_io/file_object_io.py index 79a6073c..79c089bd 100644 --- a/dfvfs/file_io/file_object_io.py +++ b/dfvfs/file_io/file_object_io.py @@ -12,6 +12,8 @@ class FileObjectIO(file_io.FileIO): """Base class for file object-based file-like object.""" + # pylint: disable=redundant-returns-doc + def __init__(self, resolver_context, file_object=None): """Initializes a file-like object. @@ -49,6 +51,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -95,6 +98,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -113,6 +117,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -122,11 +127,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -143,6 +149,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/gzip_file_io.py b/dfvfs/file_io/gzip_file_io.py index 2fdd7467..e6062aa1 100644 --- a/dfvfs/file_io/gzip_file_io.py +++ b/dfvfs/file_io/gzip_file_io.py @@ -70,6 +70,9 @@ def _GetMemberForOffset(self, offset): offset (int): offset in the uncompressed data to find the containing member for. + Returns: + gzipfile.GzipMember: gzip file member or None if not available. + Raises: ValueError: if the provided offset is outside of the bounds of the uncompressed data. @@ -82,6 +85,8 @@ def _GetMemberForOffset(self, offset): if offset < end_offset: return member + return None + def seek(self, offset, whence=os.SEEK_SET): """Seeks to an offset within the file-like object. @@ -92,6 +97,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed or the file has not been opened. + OSError: if the seek failed or the file has not been opened. """ if not self._gzip_file_object: raise IOError('Not opened.') @@ -123,6 +129,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ data = b'' while ((size and len(data) < size) and @@ -139,11 +146,12 @@ def read(self, size=None): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._gzip_file_object: raise IOError('Not opened.') @@ -157,6 +165,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._gzip_file_object: raise IOError('Not opened.') @@ -178,6 +187,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ diff --git a/dfvfs/file_io/lvm_file_io.py b/dfvfs/file_io/lvm_file_io.py index 1343da21..15801dfd 100644 --- a/dfvfs/file_io/lvm_file_io.py +++ b/dfvfs/file_io/lvm_file_io.py @@ -41,6 +41,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -84,6 +85,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -100,6 +102,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -109,11 +112,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -123,8 +127,12 @@ def get_offset(self): def get_size(self): """Retrieves the size of the file-like object. + Returns: + int: size of the file-like object data. + Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/ntfs_file_io.py b/dfvfs/file_io/ntfs_file_io.py index 7960fe0d..8a9d7e9f 100644 --- a/dfvfs/file_io/ntfs_file_io.py +++ b/dfvfs/file_io/ntfs_file_io.py @@ -41,6 +41,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -93,6 +94,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -111,6 +113,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -123,11 +126,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -144,6 +148,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/os_file_io.py b/dfvfs/file_io/os_file_io.py index 6781b695..347b9d33 100644 --- a/dfvfs/file_io/os_file_io.py +++ b/dfvfs/file_io/os_file_io.py @@ -41,6 +41,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -117,6 +118,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -136,6 +138,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -151,11 +154,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -170,6 +174,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/qcow_file_io.py b/dfvfs/file_io/qcow_file_io.py index c5b89730..ad1aa664 100644 --- a/dfvfs/file_io/qcow_file_io.py +++ b/dfvfs/file_io/qcow_file_io.py @@ -20,7 +20,7 @@ def _OpenFileObject(self, path_spec): path_spec (PathSpec): path specification. Returns: - FileIO: a file-like object. + pyqcow.file: a file-like object. Raises: PathSpecError: if the path specification is incorrect. @@ -43,6 +43,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/raw_file_io.py b/dfvfs/file_io/raw_file_io.py index 547b7b96..bad7f881 100644 --- a/dfvfs/file_io/raw_file_io.py +++ b/dfvfs/file_io/raw_file_io.py @@ -47,7 +47,7 @@ def _OpenFileObject(self, path_spec): path_spec (PathSpec): path specification. Returns: - FileIO: a file-like object or None. + pysmraw.handle: a file-like object or None. Raises: PathSpecError: if the path specification is invalid. @@ -65,7 +65,7 @@ def _OpenFileObject(self, path_spec): # handle the file system abstraction dfvfs provides. segment_file_path_specs = raw.RawGlobPathSpec(file_system, path_spec) if not segment_file_path_specs: - return + return None if parent_path_spec.IsSystemLevel(): # Typically the file-like object cache should have room for 127 items. @@ -90,6 +90,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/sqlite_blob_file_io.py b/dfvfs/file_io/sqlite_blob_file_io.py index 0e918e8c..ecadc400 100644 --- a/dfvfs/file_io/sqlite_blob_file_io.py +++ b/dfvfs/file_io/sqlite_blob_file_io.py @@ -51,6 +51,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -163,6 +164,7 @@ def GetNumberOfRows(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._database_object: raise IOError('Not opened.') @@ -192,6 +194,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._database_object: raise IOError('Not opened.') @@ -221,6 +224,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._database_object: raise IOError('Not opened.') @@ -240,11 +244,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._database_object: raise IOError('Not opened.') @@ -259,6 +264,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._database_object: raise IOError('Not opened.') diff --git a/dfvfs/file_io/tar_file_io.py b/dfvfs/file_io/tar_file_io.py index 0558781e..da9bff5d 100644 --- a/dfvfs/file_io/tar_file_io.py +++ b/dfvfs/file_io/tar_file_io.py @@ -45,6 +45,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -91,6 +92,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -125,6 +127,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -144,11 +147,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -163,6 +167,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/tsk_file_io.py b/dfvfs/file_io/tsk_file_io.py index 354dee23..db1aaa31 100644 --- a/dfvfs/file_io/tsk_file_io.py +++ b/dfvfs/file_io/tsk_file_io.py @@ -45,6 +45,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -159,6 +160,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -198,6 +200,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -217,11 +220,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -236,6 +240,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/tsk_partition_file_io.py b/dfvfs/file_io/tsk_partition_file_io.py index 978d7f19..2c8e4680 100644 --- a/dfvfs/file_io/tsk_partition_file_io.py +++ b/dfvfs/file_io/tsk_partition_file_io.py @@ -36,6 +36,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ diff --git a/dfvfs/file_io/vhdi_file_io.py b/dfvfs/file_io/vhdi_file_io.py index 62fbdf7d..d5d1fccf 100644 --- a/dfvfs/file_io/vhdi_file_io.py +++ b/dfvfs/file_io/vhdi_file_io.py @@ -45,7 +45,7 @@ def _OpenFileObject(self, path_spec): path_spec (PathSpec): path specification. Returns: - A file-like object. + pyvhdi.file: a file-like object. Raises: PathSpecError: if the path specification is incorrect. @@ -139,6 +139,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/vmdk_file_io.py b/dfvfs/file_io/vmdk_file_io.py index 667ab8e5..e96ceffc 100644 --- a/dfvfs/file_io/vmdk_file_io.py +++ b/dfvfs/file_io/vmdk_file_io.py @@ -21,10 +21,11 @@ def _OpenFileObject(self, path_spec): path_spec (PathSpec): path specification. Returns: - FileIO: a file-like object. + pyvmdk.handle: a file-like object. Raises: IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. """ if not path_spec.HasParent(): @@ -112,6 +113,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/vshadow_file_io.py b/dfvfs/file_io/vshadow_file_io.py index 669f78d0..449a69e2 100644 --- a/dfvfs/file_io/vshadow_file_io.py +++ b/dfvfs/file_io/vshadow_file_io.py @@ -41,6 +41,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -89,6 +90,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -105,6 +107,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -114,11 +117,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -133,6 +137,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/file_io/zip_file_io.py b/dfvfs/file_io/zip_file_io.py index fca26a70..8bf6bb60 100644 --- a/dfvfs/file_io/zip_file_io.py +++ b/dfvfs/file_io/zip_file_io.py @@ -60,6 +60,7 @@ def _Open(self, path_spec=None, mode='rb'): Raises: AccessError: if the access to open the file was denied. IOError: if the file-like object could not be opened. + OSError: if the file-like object could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -93,6 +94,7 @@ def _AlignUncompressedDataOffset(self, uncompressed_data_offset): Raises: IOError: if the ZIP file could not be opened. + OSError: if the ZIP file could not be opened. """ if self._zip_ext_file: self._zip_ext_file.close() @@ -148,6 +150,7 @@ def read(self, size=None): Raises: IOError: if the read failed. + OSError: if the read failed. """ if not self._is_open: raise IOError('Not opened.') @@ -209,6 +212,7 @@ def seek(self, offset, whence=os.SEEK_SET): Raises: IOError: if the seek failed. + OSError: if the seek failed. """ if not self._is_open: raise IOError('Not opened.') @@ -230,11 +234,12 @@ def seek(self, offset, whence=os.SEEK_SET): def get_offset(self): """Retrieves the current offset into the file-like object. - Return: + Returns: int: current offset into the file-like object. Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') @@ -249,6 +254,7 @@ def get_size(self): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._is_open: raise IOError('Not opened.') diff --git a/dfvfs/helpers/file_system_searcher.py b/dfvfs/helpers/file_system_searcher.py index 1d256436..39e5bce3 100644 --- a/dfvfs/helpers/file_system_searcher.py +++ b/dfvfs/helpers/file_system_searcher.py @@ -124,13 +124,13 @@ def _CheckFileEntryType(self, file_entry): bool: True if the file entry matches the find specification, False if not or None if no file entry type specification is defined. """ - if self._file_entry_types: - return (self._CheckIsDevice(file_entry) or - self._CheckIsDirectory(file_entry) or - self._CheckIsFile(file_entry) or - self._CheckIsLink(file_entry) or - self._CheckIsPipe(file_entry) or - self._CheckIsSocket(file_entry)) + if not self._file_entry_types: + return None + + return ( + self._CheckIsDevice(file_entry) or self._CheckIsDirectory(file_entry) or + self._CheckIsFile(file_entry) or self._CheckIsLink(file_entry) or + self._CheckIsPipe(file_entry) or self._CheckIsSocket(file_entry)) def _CheckIsAllocated(self, file_entry): """Checks the is_allocated find specification. @@ -143,7 +143,7 @@ def _CheckIsAllocated(self, file_entry): not or None if no allocation specification is defined. """ if self._is_allocated is None: - return + return None return self._is_allocated == file_entry.IsAllocated() def _CheckIsDevice(self, file_entry): @@ -429,6 +429,7 @@ def _FindInFileEntry(self, file_entry, find_specs, search_depth): if match: yield file_entry.path_spec + # pylint: disable=singleton-comparison if location_match != False and not find_spec.AtMaximumDepth(search_depth): sub_find_specs.append(find_spec) diff --git a/dfvfs/helpers/source_scanner.py b/dfvfs/helpers/source_scanner.py index 77bbc39b..1cb8e44d 100644 --- a/dfvfs/helpers/source_scanner.py +++ b/dfvfs/helpers/source_scanner.py @@ -54,7 +54,7 @@ def GetSubNodeByLocation(self, location): location (str): location that should match the location of the path specification of a sub scan node. - Return: + Returns: SourceScanNode: sub scan node or None if not available. """ for sub_node in self.sub_nodes: @@ -62,6 +62,8 @@ def GetSubNodeByLocation(self, location): if location == sub_node_location: return sub_node + return None + def GetUnscannedSubNode(self): """Retrieves the first unscanned sub node. @@ -76,6 +78,8 @@ def GetUnscannedSubNode(self): if result: return result + return None + def IsSystemLevel(self): """Determines if the path specification is at system-level. @@ -226,8 +230,10 @@ def IsSourceTypeDirectory(self): bool: True if the source type is a directory, False if not or None if not set. """ - if self.source_type: - return self.source_type == definitions.SOURCE_TYPE_DIRECTORY + if not self.source_type: + return None + + return self.source_type == definitions.SOURCE_TYPE_DIRECTORY def IsSourceTypeFile(self): """Determines if the source type is a file. @@ -235,8 +241,10 @@ def IsSourceTypeFile(self): Returns: bool: True if the source type is a file, False if not or None if not set. """ - if self.source_type: - return self.source_type == definitions.SOURCE_TYPE_FILE + if not self.source_type: + return None + + return self.source_type == definitions.SOURCE_TYPE_FILE def LockScanNode(self, path_spec): """Marks a scan node as locked. @@ -278,7 +286,7 @@ def RemoveScanNode(self, path_spec): """ scan_node = self._scan_nodes.get(path_spec, None) if not scan_node: - return + return None if scan_node.sub_nodes: raise RuntimeError('Scan node has sub nodes.') @@ -370,7 +378,7 @@ def _ScanNode(self, scan_context, scan_node, auto_recurse=True): if system_level_file_entry.IsDirectory(): scan_context.SetSourceType(definitions.SOURCE_TYPE_DIRECTORY) - return + return None source_path_spec = self.ScanForStorageMediaImage(scan_node.path_spec) if source_path_spec: @@ -385,7 +393,7 @@ def _ScanNode(self, scan_context, scan_node, auto_recurse=True): definitions.SOURCE_TYPE_STORAGE_MEDIA_IMAGE) if not auto_recurse: - return + return None # In case we did not find a storage media image type we keep looking # since not all RAW storage media image naming schemas are known and @@ -422,14 +430,14 @@ def _ScanNode(self, scan_context, scan_node, auto_recurse=True): scan_context, scan_node, auto_recurse=auto_recurse) # We already have already scanned for the file systems. - return + return None - elif scan_node.type_indicator in ( + if scan_node.type_indicator in ( definitions.ENCRYPTED_VOLUME_TYPE_INDICATORS): self._ScanEncryptedVolumeNode(scan_context, scan_node) if not auto_recurse and scan_context.updated: - return + return None # Nothing new found. if not scan_context.updated: @@ -486,7 +494,7 @@ def _ScanNode(self, scan_context, scan_node, auto_recurse=True): if not scan_node.scanned: scan_node.scanned = True - return + return None def _ScanEncryptedVolumeNode(self, scan_context, scan_node): """Scans an encrypted volume node for supported formats. @@ -615,7 +623,7 @@ def ScanForFileSystem(self, source_path_spec): '{0!s}').format(exception)) if not type_indicators: - return + return None type_indicator = type_indicators[0] if len(type_indicators) > 1: @@ -671,7 +679,7 @@ def ScanForStorageMediaImage(self, source_path_spec): glob_results = None if not glob_results: - return + return None return raw_path_spec @@ -699,7 +707,7 @@ def ScanForVolumeSystem(self, source_path_spec): # It is technically possible to scan for VSS-in-VSS but makes no sense # to do so. if source_path_spec.type_indicator == definitions.TYPE_INDICATOR_VSHADOW: - return + return None # Check if we already have a volume system root path specification. if source_path_spec.type_indicator in ( @@ -716,7 +724,7 @@ def ScanForVolumeSystem(self, source_path_spec): '{0!s}').format(exception)) if not type_indicators: - return + return None if len(type_indicators) > 1: raise errors.BackEndError( @@ -725,7 +733,7 @@ def ScanForVolumeSystem(self, source_path_spec): if (type_indicators[0] == definitions.TYPE_INDICATOR_TSK_PARTITION and source_path_spec.type_indicator in [ definitions.TYPE_INDICATOR_TSK_PARTITION]): - return + return None if type_indicators[0] in definitions.VOLUME_SYSTEM_TYPE_INDICATORS: return path_spec_factory.Factory.NewPathSpec( diff --git a/dfvfs/helpers/volume_scanner.py b/dfvfs/helpers/volume_scanner.py index 96da988c..1bc2daaa 100644 --- a/dfvfs/helpers/volume_scanner.py +++ b/dfvfs/helpers/volume_scanner.py @@ -20,6 +20,8 @@ class VolumeScannerMediator(object): """Volume scanner mediator.""" + # pylint: disable=redundant-returns-doc + @abc.abstractmethod def GetPartitionIdentifiers(self, volume_system, volume_identifiers): """Retrieves partition identifiers. @@ -471,7 +473,7 @@ def OpenFile(self, windows_path): """ path_spec = self._path_resolver.ResolvePath(windows_path) if path_spec is None: - return + return None return self._file_system.GetFileObjectByPathSpec(path_spec) diff --git a/dfvfs/helpers/windows_path_resolver.py b/dfvfs/helpers/windows_path_resolver.py index f3283775..4a150f99 100644 --- a/dfvfs/helpers/windows_path_resolver.py +++ b/dfvfs/helpers/windows_path_resolver.py @@ -79,18 +79,20 @@ def _PathStripPrefix(self, path): if path.startswith('\\\\.\\') or path.startswith('\\\\?\\'): if len(path) < 7 or path[5] != ':' or path[6] != self._PATH_SEPARATOR: # Cannot handle a non-volume path. - return + return None + path = path[7:] elif path.startswith('\\\\'): # Cannot handle an UNC path. - return + return None elif len(path) >= 3 and path[1] == ':': # Check if the path is a Volume 'absolute' path. if path[2] != self._PATH_SEPARATOR: # Cannot handle a Volume 'relative' path. - return + return None + path = path[3:] elif path.startswith('\\'): @@ -98,7 +100,7 @@ def _PathStripPrefix(self, path): else: # Cannot handle a relative path. - return + return None return path @@ -241,7 +243,7 @@ def ResolvePath(self, path, expand_variables=True): path, expand_variables=expand_variables) if not location or not path_spec: - return + return None # Note that we don't want to set the keyword arguments when not used because # the path specification base class will check for unused keyword arguments diff --git a/dfvfs/lib/cpio.py b/dfvfs/lib/cpio.py index 245a580b..65b5a2c3 100644 --- a/dfvfs/lib/cpio.py +++ b/dfvfs/lib/cpio.py @@ -97,7 +97,7 @@ class CPIOArchiveFile(data_format.DataFormat): 'checksum') def __init__(self): - """Initializes the CPIO archive file object.""" + """Initializes a CPIO archive file.""" super(CPIOArchiveFile, self).__init__() self._file_entries = None self._file_object = None @@ -114,6 +114,9 @@ def _ReadFileEntry(self, file_object, file_offset): file_offset (int): offset of the data relative from the start of the file-like object. + Returns: + CPIOArchiveFileEntry: a file entry. + Raises: FileFormatError: if the file entry cannot be read. """ @@ -283,8 +286,9 @@ def GetFileEntryByPath(self, path): Returns: CPIOArchiveFileEntry: a CPIO archive file entry or None if not available. """ - if self._file_entries: - return self._file_entries.get(path, None) + if not self._file_entries: + return None + return self._file_entries.get(path, None) def Open(self, file_object): """Opens the CPIO archive file. @@ -294,6 +298,7 @@ def Open(self, file_object): Raises: IOError: if the file format signature is not supported. + OSError: if the file format signature is not supported. """ file_object.seek(0, os.SEEK_SET) signature_data = file_object.read(6) @@ -331,6 +336,7 @@ def ReadDataAtOffset(self, file_offset, size): Raises: IOError: if the read failed. + OSError: if the read failed. """ self._file_object.seek(file_offset, os.SEEK_SET) return self._file_object.read(size) diff --git a/dfvfs/lib/definitions.py b/dfvfs/lib/definitions.py index 85f439d1..89a0c31a 100644 --- a/dfvfs/lib/definitions.py +++ b/dfvfs/lib/definitions.py @@ -110,7 +110,7 @@ FORMAT_CATEGORY_STORAGE_MEDIA_IMAGE, FORMAT_CATEGORY_VOLUME_SYSTEM]) -# The source type defintions. +# The source type definitions. SOURCE_TYPE_DIRECTORY = 'directory' SOURCE_TYPE_FILE = 'file' SOURCE_TYPE_STORAGE_MEDIA_DEVICE = 'storage media device' diff --git a/dfvfs/lib/lvm.py b/dfvfs/lib/lvm.py index 4783a7d3..6d444033 100644 --- a/dfvfs/lib/lvm.py +++ b/dfvfs/lib/lvm.py @@ -11,7 +11,7 @@ def LVMPathSpecGetVolumeIndex(path_spec): path_spec (PathSpec): path specification. Returns: - int: volume index. + int: volume index or None if not available. """ volume_index = getattr(path_spec, 'volume_index', None) @@ -19,7 +19,7 @@ def LVMPathSpecGetVolumeIndex(path_spec): location = getattr(path_spec, 'location', None) if location is None or not location.startswith('/lvm'): - return + return None volume_index = None try: @@ -28,6 +28,6 @@ def LVMPathSpecGetVolumeIndex(path_spec): pass if volume_index is None or volume_index < 0: - return + return None return volume_index diff --git a/dfvfs/lib/sqlite_database.py b/dfvfs/lib/sqlite_database.py index d2a767e1..6048335a 100644 --- a/dfvfs/lib/sqlite_database.py +++ b/dfvfs/lib/sqlite_database.py @@ -42,6 +42,7 @@ def Close(self): Raises: IOError: if the close failed. + OSError: if the close failed. """ if self._connection: self._cursor = None @@ -52,7 +53,7 @@ def Close(self): # https://github.com/log2timeline/dfvfs/issues/92 try: os.remove(self._temp_file_path) - except (OSError, IOError): + except (IOError, OSError): pass self._temp_file_path = '' @@ -68,6 +69,7 @@ def GetNumberOfRows(self, table_name): Raises: IOError: if the file-like object has not been opened. + OSError: if the file-like object has not been opened. """ if not self._connection: raise IOError('Not opened.') @@ -102,6 +104,7 @@ def HasColumn(self, table_name, column_name): Raises: IOError: if the database file is not opened. + OSError: if the database file is not opened. """ if not self._connection: raise IOError('Not opened.') @@ -141,6 +144,7 @@ def HasTable(self, table_name): Raises: IOError: if the database file is not opened. + OSError: if the database file is not opened. """ if not self._connection: raise IOError('Not opened.') @@ -173,6 +177,7 @@ def Open(self, file_object): Raises: IOError: if the SQLite database signature does not match. + OSError: if the SQLite database signature does not match. ValueError: if the file-like object is invalid. """ if not file_object: diff --git a/dfvfs/lib/vshadow.py b/dfvfs/lib/vshadow.py index eb8bd14e..424d0323 100644 --- a/dfvfs/lib/vshadow.py +++ b/dfvfs/lib/vshadow.py @@ -9,6 +9,9 @@ def VShadowPathSpecGetStoreIndex(path_spec): Args: path_spec (PathSpec): path specification. + + Returns: + int: store index or None if not available. """ store_index = getattr(path_spec, 'store_index', None) @@ -16,7 +19,7 @@ def VShadowPathSpecGetStoreIndex(path_spec): location = getattr(path_spec, 'location', None) if location is None or not location.startswith('/vss'): - return + return None store_index = None try: @@ -25,6 +28,6 @@ def VShadowPathSpecGetStoreIndex(path_spec): pass if store_index is None or store_index < 0: - return + return None return store_index diff --git a/dfvfs/path/factory.py b/dfvfs/path/factory.py index 6778790b..2339c180 100644 --- a/dfvfs/path/factory.py +++ b/dfvfs/path/factory.py @@ -65,13 +65,16 @@ def GetProperties(cls, path_spec): Args: path_spec (PathSpec): path specification. + Returns: + dict[str, str]: path specification properties. + Raises: dict: path specification properties. """ properties = {} for property_name in cls.PROPERTY_NAMES: - # Note that we don't want to set the properties when not used. + # Note that we do not want to set the properties when not used. if hasattr(path_spec, property_name): properties[property_name] = getattr(path_spec, property_name) diff --git a/dfvfs/path/path_spec.py b/dfvfs/path/path_spec.py index 09e85788..2f2bf43e 100644 --- a/dfvfs/path/path_spec.py +++ b/dfvfs/path/path_spec.py @@ -13,6 +13,8 @@ class PathSpec(object): parent (PathSpec): parent path specification. """ + # pylint: disable=missing-raises-doc + _IS_SYSTEM_LEVEL = False def __init__(self, parent=None, **kwargs): diff --git a/dfvfs/resolver/cache.py b/dfvfs/resolver/cache.py index b05213c4..b680706e 100644 --- a/dfvfs/resolver/cache.py +++ b/dfvfs/resolver/cache.py @@ -142,7 +142,7 @@ def GetObject(self, identifier): """ cache_value = self._values.get(identifier, None) if not cache_value: - return + return None return cache_value.vfs_object diff --git a/dfvfs/resolver/context.py b/dfvfs/resolver/context.py index c1244c14..633c0330 100644 --- a/dfvfs/resolver/context.py +++ b/dfvfs/resolver/context.py @@ -107,7 +107,7 @@ def GetFileObjectReferenceCount(self, path_spec): """ cache_value = self._file_object_cache.GetCacheValue(path_spec.comparable) if not cache_value: - return + return None return cache_value.reference_count @@ -136,7 +136,7 @@ def GetFileSystemReferenceCount(self, path_spec): identifier = self._GetFileSystemCacheIdentifier(path_spec) cache_value = self._file_system_cache.GetCacheValue(identifier) if not cache_value: - return + return None return cache_value.reference_count diff --git a/dfvfs/resolver/resolver.py b/dfvfs/resolver/resolver.py index 7575867e..161ac441 100644 --- a/dfvfs/resolver/resolver.py +++ b/dfvfs/resolver/resolver.py @@ -160,8 +160,6 @@ def OpenFileSystem(cls, path_spec_object, resolver_context=None): try: file_system.Open(path_spec_object) - except (errors.AccessError, errors.PathSpecError): - raise except (IOError, ValueError) as exception: raise errors.BackEndError( 'Unable to open file system with error: {0:s}'.format(exception)) diff --git a/dfvfs/resolver_helpers/resolver_helper.py b/dfvfs/resolver_helpers/resolver_helper.py index 98b45d62..0cc60a4e 100644 --- a/dfvfs/resolver_helpers/resolver_helper.py +++ b/dfvfs/resolver_helpers/resolver_helper.py @@ -7,6 +7,8 @@ class ResolverHelper(object): """Resolver helper object interface.""" + # pylint: disable=missing-raises-doc,redundant-returns-doc,unused-argument + @property def type_indicator(self): """str: type indicator.""" @@ -16,7 +18,7 @@ def type_indicator(self): 'Invalid resolver helper missing type indicator.') return type_indicator - def NewFileObject(self, unused_resolver_context): + def NewFileObject(self, resolver_context): """Creates a new file-like object. Args: @@ -33,7 +35,7 @@ def NewFileObject(self, unused_resolver_context): # abstract methods, which should not be the the case. raise RuntimeError('Missing implemention to create file object.') - def NewFileSystem(self, unused_resolver_context): + def NewFileSystem(self, resolver_context): """Creates a new file system. Args: diff --git a/dfvfs/serializer/serializer.py b/dfvfs/serializer/serializer.py index 45eb51bd..094df917 100644 --- a/dfvfs/serializer/serializer.py +++ b/dfvfs/serializer/serializer.py @@ -3,16 +3,16 @@ from __future__ import unicode_literals -# Since abc does not seem to have an @abc.abstractclassmethod we're using -# @abc.abstractmethod instead and shutting up pylint about: -# E0213: Method should have "self" as first argument. -# pylint: disable=no-self-argument - import abc class PathSpecSerializer(object): - """Class that implements the path specification serializer interface.""" + """Path specification serializer interface.""" + + # Since abc does not seem to have an @abc.abstractclassmethod we're using + # @abc.abstractmethod instead and shutting up pylint about: + # E0213: Method should have "self" as first argument. + # pylint: disable=no-self-argument,redundant-returns-doc @abc.abstractmethod def ReadSerialized(cls, serialized): diff --git a/dfvfs/vfs/compressed_stream_file_system.py b/dfvfs/vfs/compressed_stream_file_system.py index 001f0724..09f0330a 100644 --- a/dfvfs/vfs/compressed_stream_file_system.py +++ b/dfvfs/vfs/compressed_stream_file_system.py @@ -11,21 +11,21 @@ class CompressedStreamFileSystem(root_only_file_system.RootOnlyFileSystem): - """Class that implements a compresses stream file system object.""" + """Compressed stream file system.""" TYPE_INDICATOR = definitions.TYPE_INDICATOR_COMPRESSED_STREAM def __init__(self, resolver_context): - """Initializes a file system object. + """Initializes a compressed stream file system. Args: - resolver_context: the resolver context (instance of resolver.Context). + resolver_context (Context): a resolver context. """ super(CompressedStreamFileSystem, self).__init__(resolver_context) self._compression_method = None def _Close(self): - """Closes the file system object. + """Closes the file system. Raises: IOError: if the close failed. @@ -33,15 +33,16 @@ def _Close(self): self._compression_method = None def _Open(self, path_spec, mode='rb'): - """Opens the file system object defined by path specification. + """Opens the file system defined by path specification. Args: - path_spec: a path specification (instance of PathSpec). - mode: optional file access mode. The default is 'rb' read-only binary. + path_spec (PathSpec): a path specification. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. - IOError: if the file system object could not be opened. + IOError: if the file system could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -60,10 +61,10 @@ def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - A file entry (instance of vfs.FileEntry) or None. + CompressedStreamFileEntry: a file entry or None if not available. """ return compressed_stream_file_entry.CompressedStreamFileEntry( self._resolver_context, self, path_spec, is_root=True, is_virtual=True) @@ -72,7 +73,7 @@ def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - A file entry (instance of vfs.FileEntry) or None. + CompressedStreamFileEntry: a file entry or None if not available. """ path_spec = compressed_stream_path_spec.CompressedStreamPathSpec( compression_method=self._compression_method, diff --git a/dfvfs/vfs/cpio_file_entry.py b/dfvfs/vfs/cpio_file_entry.py index 691d6298..d61b8a50 100644 --- a/dfvfs/vfs/cpio_file_entry.py +++ b/dfvfs/vfs/cpio_file_entry.py @@ -27,27 +27,26 @@ def _EntriesGenerator(self): """ location = getattr(self.path_spec, 'location', None) - if (location is None or - not location.startswith(self._file_system.PATH_SEPARATOR)): - return - - cpio_archive_file = self._file_system.GetCPIOArchiveFile() - for cpio_archive_file_entry in cpio_archive_file.GetFileEntries( - path_prefix=location[1:]): + if location and location.startswith(self._file_system.PATH_SEPARATOR): + cpio_archive_file = self._file_system.GetCPIOArchiveFile() + for cpio_archive_file_entry in cpio_archive_file.GetFileEntries( + path_prefix=location[1:]): - path = cpio_archive_file_entry.path - if not path: - continue + path = cpio_archive_file_entry.path + if not path: + continue - _, suffix = self._file_system.GetPathSegmentAndSuffix(location[1:], path) + _, suffix = self._file_system.GetPathSegmentAndSuffix( + location[1:], path) - # Ignore anything that is part of a sub directory or the directory itself. - if suffix or path == location: - continue + # Ignore anything that is part of a sub directory or the directory + # itself. + if suffix or path == location: + continue - path_spec_location = self._file_system.JoinPath([path]) - yield cpio_path_spec.CPIOPathSpec( - location=path_spec_location, parent=self.path_spec.parent) + path_spec_location = self._file_system.JoinPath([path]) + yield cpio_path_spec.CPIOPathSpec( + location=path_spec_location, parent=self.path_spec.parent) class CPIOFileEntry(file_entry.FileEntry): @@ -112,8 +111,9 @@ def _GetDirectory(self): Returns: CPIODirectory: a directory or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return CPIODirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return CPIODirectory(self._file_system, self.path_spec) def _GetLink(self): """Retrieves the link. @@ -159,6 +159,20 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + CPIOFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield CPIOFileEntry( + self._resolver_context, self._file_system, path_spec) + @property def name(self): """str: name of the file entry, which does not include the full path.""" @@ -174,19 +188,9 @@ def modification_time(self): """dfdatetime.DateTimeValues: modification time or None if not available.""" timestamp = getattr( self._cpio_archive_file_entry, 'modification_time', None) - if timestamp is not None: - return dfdatetime_posix_time.PosixTime(timestamp=timestamp) - - @property - def sub_file_entries(self): - """generator(CPIOFileEntry): sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield CPIOFileEntry( - self._resolver_context, self._file_system, path_spec) + if timestamp is None: + return None + return dfdatetime_posix_time.PosixTime(timestamp=timestamp) def GetCPIOArchiveFileEntry(self): """Retrieves the CPIO archive file entry object. @@ -207,11 +211,11 @@ def GetParentFileEntry(self): """ location = getattr(self.path_spec, 'location', None) if location is None: - return + return None parent_location = self._file_system.DirnamePath(location) if parent_location is None: - return + return None if parent_location == '': parent_location = self._file_system.PATH_SEPARATOR diff --git a/dfvfs/vfs/cpio_file_system.py b/dfvfs/vfs/cpio_file_system.py index ba2efd70..9cde5389 100644 --- a/dfvfs/vfs/cpio_file_system.py +++ b/dfvfs/vfs/cpio_file_system.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""The CPIO file system implementation.""" +"""The CPIO archive file system implementation.""" from __future__ import unicode_literals @@ -13,13 +13,13 @@ class CPIOFileSystem(file_system.FileSystem): - """Class that implements a file system object using CPIOArchiveFile.""" + """CPIO archive file system.""" LOCATION_ROOT = '/' TYPE_INDICATOR = definitions.TYPE_INDICATOR_CPIO def __init__(self, resolver_context, encoding='utf-8'): - """Initializes a file system object. + """Initializes a CPIO archive file system. Args: resolver_context (Context): resolver context. @@ -31,7 +31,7 @@ def __init__(self, resolver_context, encoding='utf-8'): self.encoding = encoding def _Close(self): - """Closes the file system object. + """Closes the file system. Raises: IOError: if the close failed. @@ -43,15 +43,16 @@ def _Close(self): self._file_object = None def _Open(self, path_spec, mode='rb'): - """Opens the file system object defined by path specification. + """Opens the file system defined by path specification. Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. - IOError: if the file system object could not be opened. + IOError: if the file system could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -76,16 +77,14 @@ def FileEntryExistsByPathSpec(self, path_spec): """Determines if a file entry for a path specification exists. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - Boolean indicating if the file entry exists. + bool: True if the file entry exists. """ location = getattr(path_spec, 'location', None) - - if (location is None or - not location.startswith(self.LOCATION_ROOT)): - return + if location is None or not location.startswith(self.LOCATION_ROOT): + return False if len(location) == 1: return True @@ -93,10 +92,10 @@ def FileEntryExistsByPathSpec(self, path_spec): return self._cpio_archive_file.FileEntryExistsByPath(location[1:]) def GetCPIOArchiveFile(self): - """Retrieves the CPIO archive file object. + """Retrieves the CPIO archive file. Returns: - The CPIO archvie file object (instance of cpio.CPIOArchiveFile). + CPIOArchiveFile: a CPIO archvie file. """ return self._cpio_archive_file @@ -120,7 +119,7 @@ def GetCPIOArchiveFileEntryByPathSpec(self, path_spec): raise errors.PathSpecError('Invalid location in path specification.') if len(location) == 1: - return + return None return self._cpio_archive_file.GetFileEntryByPath(location[1:]) @@ -128,17 +127,16 @@ def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - A file entry (instance of vfs.CPIOFileEntry) or None. + CPIOFileEntry: a file entry or None if not available. """ - cpio_archive_file_entry = None location = getattr(path_spec, 'location', None) if (location is None or not location.startswith(self.LOCATION_ROOT)): - return + return None if len(location) == 1: return cpio_file_entry.CPIOFileEntry( @@ -148,7 +146,8 @@ def GetFileEntryByPathSpec(self, path_spec): cpio_archive_file_entry = self._cpio_archive_file.GetFileEntryByPath( location[1:]) if cpio_archive_file_entry is None: - return + return None + return cpio_file_entry.CPIOFileEntry( self._resolver_context, self, path_spec, cpio_archive_file_entry=cpio_archive_file_entry) @@ -157,7 +156,7 @@ def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - A file entry (instance of vfs.FileEntry). + CPIOFileEntry: a file entry or None if not available. """ path_spec = cpio_path_spec.CPIOPathSpec( location=self.LOCATION_ROOT, parent=self._path_spec.parent) diff --git a/dfvfs/vfs/data_range_file_entry.py b/dfvfs/vfs/data_range_file_entry.py index 068f4694..e1493a01 100644 --- a/dfvfs/vfs/data_range_file_entry.py +++ b/dfvfs/vfs/data_range_file_entry.py @@ -14,10 +14,10 @@ class DataRangeFileEntry(root_only_file_entry.RootOnlyFileEntry): TYPE_INDICATOR = definitions.TYPE_INDICATOR_DATA_RANGE def _GetStat(self): - """Retrieves the stat object. + """Retrieves a stat object. Returns: - The stat object (instance of vfs.VFSStat). + VFSStat: a stat object. Raises: BackEndError: when the encoded stream is missing. diff --git a/dfvfs/vfs/data_range_file_system.py b/dfvfs/vfs/data_range_file_system.py index 43e3d5a0..58c1ae24 100644 --- a/dfvfs/vfs/data_range_file_system.py +++ b/dfvfs/vfs/data_range_file_system.py @@ -11,22 +11,22 @@ class DataRangeFileSystem(root_only_file_system.RootOnlyFileSystem): - """Class that implements a compresses stream file system object.""" + """Data range file system.""" TYPE_INDICATOR = definitions.TYPE_INDICATOR_DATA_RANGE def __init__(self, resolver_context): - """Initializes a file system object. + """Initializes a data range file system. Args: - resolver_context: the resolver context (instance of resolver.Context). + resolver_context (Context): a resolver context. """ super(DataRangeFileSystem, self).__init__(resolver_context) self._range_offset = None self._range_size = None def _Close(self): - """Closes the file system object. + """Closes the file system. Raises: IOError: if the close failed. @@ -35,15 +35,16 @@ def _Close(self): self._range_size = None def _Open(self, path_spec, mode='rb'): - """Opens the file system object defined by path specification. + """Opens the file system defined by path specification. Args: - path_spec: a path specification (instance of PathSpec). - mode: optional file access mode. The default is 'rb' read-only binary. + path_spec (PathSpec): a path specification. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. - IOError: if the file system object could not be opened. + IOError: if the file system could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -68,10 +69,10 @@ def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - A file entry (instance of vfs.FileEntry) or None. + DataRangeFileEntry: a file entry or None if not available. """ return data_range_file_entry.DataRangeFileEntry( self._resolver_context, self, path_spec, is_root=True, is_virtual=True) @@ -80,7 +81,7 @@ def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - A file entry (instance of vfs.FileEntry) or None. + DataRangeFileEntry: a file entry or None if not available. """ path_spec = data_range_path_spec.DataRangePathSpec( range_offset=self._range_offset, diff --git a/dfvfs/vfs/encoded_stream_file_system.py b/dfvfs/vfs/encoded_stream_file_system.py index 8c143e03..efdd32e3 100644 --- a/dfvfs/vfs/encoded_stream_file_system.py +++ b/dfvfs/vfs/encoded_stream_file_system.py @@ -11,21 +11,21 @@ class EncodedStreamFileSystem(root_only_file_system.RootOnlyFileSystem): - """Class that implements a compresses stream file system object.""" + """Encoded stream file system.""" TYPE_INDICATOR = definitions.TYPE_INDICATOR_ENCODED_STREAM def __init__(self, resolver_context): - """Initializes a file system object. + """Initializes an encoded file system. Args: - resolver_context: the resolver context (instance of resolver.Context). + resolver_context (Context): a resolver context. """ super(EncodedStreamFileSystem, self).__init__(resolver_context) self._encoding_method = None def _Close(self): - """Closes the file system object. + """Closes the file system. Raises: IOError: if the close failed. @@ -33,15 +33,16 @@ def _Close(self): self._encoding_method = None def _Open(self, path_spec, mode='rb'): - """Opens the file system object defined by path specification. + """Opens the file system defined by path specification. Args: - path_spec: a path specification (instance of PathSpec). - mode: optional file access mode. The default is 'rb' read-only binary. + path_spec (PathSpec): a path specification. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. - IOError: if the file system object could not be opened. + IOError: if the file system could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -60,10 +61,10 @@ def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - A file entry (instance of vfs.FileEntry) or None. + EncodedStreamFileEntry: a file entry or None if not available. """ return encoded_stream_file_entry.EncodedStreamFileEntry( self._resolver_context, self, path_spec, is_root=True, is_virtual=True) @@ -72,7 +73,7 @@ def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - A file entry (instance of vfs.FileEntry) or None. + EncodedStreamFileEntry: a file entry or None if not available. """ path_spec = encoded_stream_path_spec.EncodedStreamPathSpec( encoding_method=self._encoding_method, diff --git a/dfvfs/vfs/encrypted_stream_file_system.py b/dfvfs/vfs/encrypted_stream_file_system.py index fa24f10f..5af12cbb 100644 --- a/dfvfs/vfs/encrypted_stream_file_system.py +++ b/dfvfs/vfs/encrypted_stream_file_system.py @@ -12,21 +12,21 @@ class EncryptedStreamFileSystem(root_only_file_system.RootOnlyFileSystem): - """Class that implements a compresses stream file system object.""" + """Encrypted stream file system.""" TYPE_INDICATOR = definitions.TYPE_INDICATOR_ENCRYPTED_STREAM def __init__(self, resolver_context): - """Initializes a file system object. + """Initializes an encrypted file system. Args: - resolver_context: the resolver context (instance of resolver.Context). + resolver_context (Context): a resolver context. """ super(EncryptedStreamFileSystem, self).__init__(resolver_context) self._encryption_method = None def _Close(self): - """Closes the file system object. + """Closes the file system. Raises: IOError: if the close failed. @@ -34,15 +34,16 @@ def _Close(self): self._encryption_method = None def _Open(self, path_spec, mode='rb'): - """Opens the file system object defined by path specification. + """Opens the file system defined by path specification. Args: - path_spec: a path specification (instance of PathSpec). - mode: optional file access mode. The default is 'rb' read-only binary. + path_spec (PathSpec): a path specification. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. - IOError: if the file system object could not be opened. + IOError: if the file system could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -63,10 +64,10 @@ def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - A file entry (instance of vfs.FileEntry) or None. + EncryptedStreamFileEntry: a file entry or None if not available. """ return encrypted_stream_file_entry.EncryptedStreamFileEntry( self._resolver_context, self, path_spec, is_root=True, is_virtual=True) @@ -75,7 +76,7 @@ def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - A file entry (instance of vfs.FileEntry) or None. + EncryptedStreamFileEntry: a file entry or None if not available. """ path_spec = encrypted_stream_path_spec.EncryptedStreamPathSpec( encryption_method=self._encryption_method, diff --git a/dfvfs/vfs/fake_file_entry.py b/dfvfs/vfs/fake_file_entry.py index 984d2277..346a6de2 100644 --- a/dfvfs/vfs/fake_file_entry.py +++ b/dfvfs/vfs/fake_file_entry.py @@ -24,25 +24,24 @@ def _EntriesGenerator(self): FakePathSpec: a path specification. """ location = getattr(self.path_spec, 'location', None) - if location is None: - return - - paths = self._file_system.GetPaths() + if location is not None: + paths = self._file_system.GetPaths() - for path in iter(paths.keys()): - # Determine if the start of the path is similar to the location string. - # If not the file the path refers to is not in the same directory. - if not path or not path.startswith(location): - continue + for path in iter(paths.keys()): + # Determine if the start of the path is similar to the location string. + # If not the file the path refers to is not in the same directory. + if not path or not path.startswith(location): + continue - _, suffix = self._file_system.GetPathSegmentAndSuffix(location, path) + _, suffix = self._file_system.GetPathSegmentAndSuffix(location, path) - # Ignore anything that is part of a sub directory or the directory itself. - if suffix or path == location: - continue + # Ignore anything that is part of a sub directory or the directory + # itself. + if suffix or path == location: + continue - path_spec_location = self._file_system.JoinPath([path]) - yield fake_path_spec.FakePathSpec(location=path_spec_location) + path_spec_location = self._file_system.JoinPath([path]) + yield fake_path_spec.FakePathSpec(location=path_spec_location) class FakeFileEntry(file_entry.FileEntry): @@ -76,8 +75,9 @@ def _GetDirectory(self): Returns: FakeDirectory: a directory or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return FakeDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return FakeDirectory(self._file_system, self.path_spec) def _GetStat(self): """Retrieves information about the file entry. @@ -96,6 +96,19 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + FakeFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield self._file_system.GetFileEntryByPathSpec(path_spec) + @property def access_time(self): """dfdatetime.DateTimeValues: access time or None if not available.""" @@ -132,16 +145,6 @@ def name(self): self._name = self._file_system.BasenamePath(location) return self._name - @property - def sub_file_entries(self): - """generator[FakeFileEntry]: sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield self._file_system.GetFileEntryByPathSpec(path_spec) - def GetFileObject(self, data_stream_name=''): """Retrieves the file-like object. @@ -154,16 +157,17 @@ def GetFileObject(self, data_stream_name=''): Raises: IOError: if the file entry is not a file. + OSError: if the file entry is not a file. """ if not self.IsFile(): raise IOError('Cannot open non-file.') if data_stream_name: - return + return None location = getattr(self.path_spec, 'location', None) if location is None: - return + return None file_data = self._file_system.GetDataByPath(location) file_object = fake_file_io.FakeFile(self._resolver_context, file_data) @@ -178,11 +182,11 @@ def GetParentFileEntry(self): """ location = getattr(self.path_spec, 'location', None) if location is None: - return + return None parent_location = self._file_system.DirnamePath(location) if parent_location is None: - return + return None if parent_location == '': parent_location = self._file_system.PATH_SEPARATOR diff --git a/dfvfs/vfs/fake_file_system.py b/dfvfs/vfs/fake_file_system.py index 30252042..8b2536cf 100644 --- a/dfvfs/vfs/fake_file_system.py +++ b/dfvfs/vfs/fake_file_system.py @@ -18,10 +18,10 @@ class FakeFileSystem(file_system.FileSystem): TYPE_INDICATOR = definitions.TYPE_INDICATOR_FAKE def __init__(self, resolver_context): - """Initializes a file system object. + """Initializes a file system. Args: - resolver_context (Context): resolver context. + resolver_context (Context): a resolver context. """ super(FakeFileSystem, self).__init__(resolver_context) self._paths = {} @@ -29,7 +29,7 @@ def __init__(self, resolver_context): '/', file_entry_type=definitions.FILE_ENTRY_TYPE_DIRECTORY) def _Close(self): - """Closes the file system object. + """Closes the file system. Raises: IOError: if the close failed. @@ -37,15 +37,16 @@ def _Close(self): return def _Open(self, path_spec, mode='rb'): - """Opens the file system object defined by path specification. + """Opens the file system defined by path specification. Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. - IOError: if the file system object could not be opened. + IOError: if the file system could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -129,14 +130,14 @@ def GetFileEntryByPath(self, path): path (str): path of the file entry. Returns: - FileEntry: a file entry or None if not available. + FakeFileEntry: a file entry or None if not available. """ if path is None: - return + return None file_entry_type, _ = self._paths.get(path, (None, None)) if not file_entry_type: - return + return None path_spec = fake_path_spec.FakePathSpec(location=path) return fake_file_entry.FakeFileEntry( @@ -150,7 +151,7 @@ def GetFileEntryByPathSpec(self, path_spec): path_spec (PathSpec): path specification. Returns: - FileEntry: a file entry or None if not available. + FakeFileEntry: a file entry or None if not available. """ location = getattr(path_spec, 'location', None) return self.GetFileEntryByPath(location) @@ -167,7 +168,7 @@ def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - FileEntry: a file entry or None if not available. + FakeFileEntry: a file entry or None if not available. """ path_spec = fake_path_spec.FakePathSpec(location=self.LOCATION_ROOT) return self.GetFileEntryByPathSpec(path_spec) diff --git a/dfvfs/vfs/file_entry.py b/dfvfs/vfs/file_entry.py index 0670bb87..1a658f4a 100644 --- a/dfvfs/vfs/file_entry.py +++ b/dfvfs/vfs/file_entry.py @@ -18,6 +18,8 @@ class Attribute(object): """VFS attribute interface.""" + # pylint: disable=missing-raises-doc + @property def type_indicator(self): """str: type indicator.""" @@ -73,8 +75,8 @@ def _EntriesGenerator(self): Since a directory can contain a vast number of entries using a generator is more memory efficient. - Yields: - PathSpec: path specification. + Returns: + generator[PathSpec]: path specification generator. """ return iter(()) @@ -95,6 +97,8 @@ class FileEntry(object): path_spec (PathSpec): path specification. """ + # pylint: disable=missing-raises-doc,redundant-returns-doc,redundant-yields-doc + def __init__( self, resolver_context, file_system, path_spec, is_root=False, is_virtual=False): @@ -227,6 +231,14 @@ def _GetStat(self): return stat_object + @abc.abstractmethod + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + FileEntry: a sub file entry. + """ + @property def access_time(self): """dfdatetime.DateTimeValues: access time or None if not available.""" @@ -290,9 +302,10 @@ def number_of_sub_file_entries(self): # We cannot use len(self._directory.entries) since entries is a generator. return sum(1 for path_spec in self._directory.entries) - @abc.abstractproperty + @property def sub_file_entries(self): """generator[FileEntry]: sub file entries.""" + return self._GetSubFileEntries() @property def type_indicator(self): @@ -308,7 +321,7 @@ def GetDataStream(self, name, case_sensitive=True): Args: name (str): name of the data stream. - case_sentitive (Optional[bool]): True if the name is case sensitive. + case_sensitive (Optional[bool]): True if the name is case sensitive. Returns: DataStream: a data stream or None if not available. @@ -375,7 +388,7 @@ def GetSubFileEntryByName(self, name, case_sensitive=True): Args: name (str): name of the file entry. - case_sentitive (Optional[bool]): True if the name is case sensitive. + case_sensitive (Optional[bool]): True if the name is case sensitive. Returns: FileEntry: a file entry or None if not available. @@ -408,7 +421,7 @@ def HasDataStream(self, name, case_sensitive=True): Args: name (str): name of the data stream. - case_sentitive (Optional[bool]): True if the name is case sensitive. + case_sensitive (Optional[bool]): True if the name is case sensitive. Returns: bool: True if the file entry has the data stream. diff --git a/dfvfs/vfs/file_system.py b/dfvfs/vfs/file_system.py index e64e19b1..a9715868 100644 --- a/dfvfs/vfs/file_system.py +++ b/dfvfs/vfs/file_system.py @@ -9,6 +9,8 @@ class FileSystem(object): """VFS file system interface.""" + # pylint: disable=missing-raises-doc,redundant-returns-doc + LOCATION_ROOT = '/' PATH_SEPARATOR = '/' @@ -47,7 +49,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): a path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. @@ -75,6 +78,7 @@ def Close(self): Raises: IOError: if the file system object was not opened or the close failed. + OSError: if the file system object was not opened or the close failed. """ if not self._is_open: raise IOError('Not opened.') @@ -106,7 +110,8 @@ def DirnamePath(self, path): if path.endswith(self.PATH_SEPARATOR): path = path[:-1] if not path: - return + return None + dirname, _, _ = path.rpartition(self.PATH_SEPARATOR) return dirname @@ -131,9 +136,11 @@ def GetDataStreamByPathSpec(self, path_spec): DataStream: a data stream or None if not available. """ file_entry = self.GetFileEntryByPathSpec(path_spec) - if file_entry: - data_stream_name = getattr(path_spec, 'data_stream', None) - return file_entry.GetDataStream(data_stream_name) + if not file_entry: + return None + + data_stream_name = getattr(path_spec, 'data_stream', None) + return file_entry.GetDataStream(data_stream_name) @abc.abstractmethod def GetFileEntryByPathSpec(self, path_spec): @@ -156,8 +163,10 @@ def GetFileObjectByPathSpec(self, path_spec): FileIO: a file-like object or None if not available. """ file_entry = self.GetFileEntryByPathSpec(path_spec) - if file_entry: - return file_entry.GetFileObject() + if not file_entry: + return None + + return file_entry.GetFileObject() def GetPathSegmentAndSuffix(self, base_path, path): """Determines the path segment and suffix of the path. @@ -224,11 +233,13 @@ def Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): a path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. IOError: if the file system object was already opened or the open failed. + OSError: if the file system object was already opened or the open failed. PathSpecError: if the path specification is incorrect. ValueError: if the path specification or mode is invalid. """ diff --git a/dfvfs/vfs/gzip_file_entry.py b/dfvfs/vfs/gzip_file_entry.py index 4a8942a4..5c798e42 100644 --- a/dfvfs/vfs/gzip_file_entry.py +++ b/dfvfs/vfs/gzip_file_entry.py @@ -74,5 +74,6 @@ def _GetStat(self): def modification_time(self): """dfdatetime.DateTimeValues: modification time or None if not available.""" timestamps = self._gzip_file.modification_times - if timestamps: - return dfdatetime_posix_time.PosixTime(timestamp=timestamps[0]) + if not timestamps: + return None + return dfdatetime_posix_time.PosixTime(timestamp=timestamps[0]) diff --git a/dfvfs/vfs/lvm_file_entry.py b/dfvfs/vfs/lvm_file_entry.py index b29f4161..14162feb 100644 --- a/dfvfs/vfs/lvm_file_entry.py +++ b/dfvfs/vfs/lvm_file_entry.py @@ -22,21 +22,20 @@ def _EntriesGenerator(self): Yields: LVMPathSpec: a path specification. """ - # Only the virtual root file has directory entries. volume_index = getattr(self.path_spec, 'volume_index', None) - if volume_index is not None: - return - location = getattr(self.path_spec, 'location', None) - if location is None or location != self._file_system.LOCATION_ROOT: - return - vslvm_volume_group = self._file_system.GetLVMVolumeGroup() + # Only the virtual root file has directory entries. + if (volume_index is None and location is not None and + location == self._file_system.LOCATION_ROOT): + vslvm_volume_group = self._file_system.GetLVMVolumeGroup() - for volume_index in range(0, vslvm_volume_group.number_of_logical_volumes): - yield lvm_path_spec.LVMPathSpec( - location='/lvm{0:d}'.format(volume_index + 1), - parent=self.path_spec.parent, volume_index=volume_index) + for volume_index in range( + 0, vslvm_volume_group.number_of_logical_volumes): + location = '/lvm{0:d}'.format(volume_index + 1) + yield lvm_path_spec.LVMPathSpec( + location=location, parent=self.path_spec.parent, + volume_index=volume_index) class LVMFileEntry(file_entry.FileEntry): @@ -83,8 +82,9 @@ def _GetDirectory(self): Returns: LVMDirectory: a directory or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return LVMDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return LVMDirectory(self._file_system, self.path_spec) def _GetStat(self): """Retrieves information about the file entry. @@ -99,6 +99,19 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + LVMFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield LVMFileEntry(self._resolver_context, self._file_system, path_spec) + # TODO: implement creation_time property after implementing # vslvm_logical_volume.get_creation_time_as_integer() @@ -117,16 +130,6 @@ def name(self): self._name = '' return self._name - @property - def sub_file_entries(self): - """generator[LVMFileEntry]: sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield LVMFileEntry(self._resolver_context, self._file_system, path_spec) - def GetLVMLogicalVolume(self): """Retrieves the LVM logical volume. @@ -143,6 +146,6 @@ def GetParentFileEntry(self): """ volume_index = lvm.LVMPathSpecGetVolumeIndex(self.path_spec) if volume_index is None: - return + return None return self._file_system.GetRootFileEntry() diff --git a/dfvfs/vfs/lvm_file_system.py b/dfvfs/vfs/lvm_file_system.py index 821f7e84..01ec4aa0 100644 --- a/dfvfs/vfs/lvm_file_system.py +++ b/dfvfs/vfs/lvm_file_system.py @@ -48,7 +48,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. @@ -95,8 +96,8 @@ def FileEntryExistsByPathSpec(self, path_spec): location = getattr(path_spec, 'location', None) return location is not None and location == self.LOCATION_ROOT - return (volume_index >= 0 and - volume_index < self._vslvm_volume_group.number_of_logical_volumes) + return ( + 0 <= volume_index < self._vslvm_volume_group.number_of_logical_volumes) def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. @@ -114,16 +115,17 @@ def GetFileEntryByPathSpec(self, path_spec): if volume_index is None: location = getattr(path_spec, 'location', None) if location is None or location != self.LOCATION_ROOT: - return + return None + return lvm_file_entry.LVMFileEntry( self._resolver_context, self, path_spec, is_root=True, is_virtual=True) if (volume_index < 0 or volume_index >= self._vslvm_volume_group.number_of_logical_volumes): - return - return lvm_file_entry.LVMFileEntry( - self._resolver_context, self, path_spec) + return None + + return lvm_file_entry.LVMFileEntry(self._resolver_context, self, path_spec) def GetLVMLogicalVolumeByPathSpec(self, path_spec): """Retrieves a LVM logical volume for a path specification. @@ -135,8 +137,9 @@ def GetLVMLogicalVolumeByPathSpec(self, path_spec): pyvslvm.logical_volume: a LVM logical volume or None if not available. """ volume_index = lvm.LVMPathSpecGetVolumeIndex(path_spec) - if volume_index is not None: - return self._vslvm_volume_group.get_logical_volume(volume_index) + if volume_index is None: + return None + return self._vslvm_volume_group.get_logical_volume(volume_index) def GetLVMVolumeGroup(self): """Retrieves the LVM volume group. diff --git a/dfvfs/vfs/ntfs_file_entry.py b/dfvfs/vfs/ntfs_file_entry.py index a1c4ced0..afda8f48 100644 --- a/dfvfs/vfs/ntfs_file_entry.py +++ b/dfvfs/vfs/ntfs_file_entry.py @@ -207,31 +207,32 @@ def _EntriesGenerator(self): fsntfs_file_entry = self._file_system.GetNTFSFileEntryByPathSpec( self.path_spec) except errors.PathSpecError: - return + fsntfs_file_entry = None - location = getattr(self.path_spec, 'location', None) + if fsntfs_file_entry: + location = getattr(self.path_spec, 'location', None) - for fsntfs_sub_file_entry in fsntfs_file_entry.sub_file_entries: - directory_entry = fsntfs_sub_file_entry.name + for fsntfs_sub_file_entry in fsntfs_file_entry.sub_file_entries: + directory_entry = fsntfs_sub_file_entry.name - # Ignore references to self or parent. - if directory_entry in ('.', '..'): - continue + # Ignore references to self or parent. + if directory_entry in ('.', '..'): + continue - file_reference = fsntfs_sub_file_entry.file_reference - directory_entry_mft_entry = ( - file_reference & _FILE_REFERENCE_MFT_ENTRY_BITMASK) + file_reference = fsntfs_sub_file_entry.file_reference + directory_entry_mft_entry = ( + file_reference & _FILE_REFERENCE_MFT_ENTRY_BITMASK) - if location == self._file_system.PATH_SEPARATOR: - directory_entry = self._file_system.JoinPath([directory_entry]) - else: - directory_entry = self._file_system.JoinPath([ - location, directory_entry]) + if location == self._file_system.PATH_SEPARATOR: + directory_entry = self._file_system.JoinPath([directory_entry]) + else: + directory_entry = self._file_system.JoinPath([ + location, directory_entry]) - yield ntfs_path_spec.NTFSPathSpec( - location=directory_entry, - mft_attribute=fsntfs_sub_file_entry.name_attribute_index, - mft_entry=directory_entry_mft_entry, parent=self.path_spec.parent) + yield ntfs_path_spec.NTFSPathSpec( + location=directory_entry, + mft_attribute=fsntfs_sub_file_entry.name_attribute_index, + mft_entry=directory_entry_mft_entry, parent=self.path_spec.parent) class NTFSFileEntry(file_entry.FileEntry): @@ -322,8 +323,9 @@ def _GetDirectory(self): Returns: NTFSDirectory: directory or None if not available. """ - if self._fsntfs_file_entry.number_of_sub_file_entries > 0: - return NTFSDirectory(self._file_system, self.path_spec) + if self._fsntfs_file_entry.number_of_sub_file_entries == 0: + return None + return NTFSDirectory(self._file_system, self.path_spec) def _GetLink(self): """Retrieves the link. @@ -378,11 +380,28 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + NTFSFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield NTFSFileEntry( + self._resolver_context, self._file_system, path_spec) + def _IsLink(self, file_attribute_flags): """Determines if a file entry is a link. Args: file_attribute_flags (int): file attribute flags. + + Returns: + bool: True if a file entry is a link, false otherwise. """ return bool( file_attribute_flags & pyfsntfs.file_attribute_flags.REPARSE_POINT) @@ -423,17 +442,6 @@ def modification_time(self): timestamp = self._fsntfs_file_entry.get_modification_time_as_integer() return dfdatetime_filetime.Filetime(timestamp=timestamp) - @property - def sub_file_entries(self): - """generator(NTFSFileEntry): sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield NTFSFileEntry( - self._resolver_context, self._file_system, path_spec) - def GetFileObject(self, data_stream_name=''): """Retrieves the file-like object. @@ -446,7 +454,7 @@ def GetFileObject(self, data_stream_name=''): """ if (not data_stream_name and not self._fsntfs_file_entry.has_default_data_stream()): - return + return None # Make sure to make the changes on a copy of the path specification, so we # do not alter self.path_spec. @@ -465,7 +473,7 @@ def GetLinkedFileEntry(self): """ link = self._GetLink() if not link: - return + return None # TODO: is there a way to determine the MFT entry here? link_mft_entry = None @@ -512,7 +520,7 @@ def GetParentFileEntry(self): self._fsntfs_file_entry.get_parent_file_reference()) if parent_file_reference is None: - return + return None parent_mft_entry = ( parent_file_reference & _FILE_REFERENCE_MFT_ENTRY_BITMASK) diff --git a/dfvfs/vfs/ntfs_file_system.py b/dfvfs/vfs/ntfs_file_system.py index 46ce6b32..8cca6cdf 100644 --- a/dfvfs/vfs/ntfs_file_system.py +++ b/dfvfs/vfs/ntfs_file_system.py @@ -49,7 +49,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. @@ -139,7 +140,7 @@ def GetFileEntryByPathSpec(self, path_spec): raise errors.BackEndError(exception) if fsntfs_file_entry is None: - return + return None return ntfs_file_entry.NTFSFileEntry( self._resolver_context, self, path_spec, diff --git a/dfvfs/vfs/os_file_entry.py b/dfvfs/vfs/os_file_entry.py index ef6fde92..2a18dd18 100644 --- a/dfvfs/vfs/os_file_entry.py +++ b/dfvfs/vfs/os_file_entry.py @@ -36,33 +36,31 @@ def _EntriesGenerator(self): BackEndError: if the directory could not be listed. """ location = getattr(self.path_spec, 'location', None) - if location is None: - return - - # Windows will raise WindowsError, which can be caught by OSError, - # if the process has not access to list the directory. The os.access() - # function cannot be used since it will return true even when os.listdir() - # fails. - try: - for directory_entry in os.listdir(location): - directory_entry_location = self._file_system.JoinPath([ - location, directory_entry]) - yield os_path_spec.OSPathSpec(location=directory_entry_location) - - except OSError as exception: - if exception.errno == errno.EACCES: - exception_string = str(exception) - if not isinstance(exception_string, py2to3.UNICODE_TYPE): - exception_string = py2to3.UNICODE_TYPE( - exception_string, errors='replace') - - raise errors.AccessError( - 'Access to directory denied with error: {0:s}'.format( - exception_string)) - else: - raise errors.BackEndError( - 'Unable to list directory: {0:s} with error: {1:s}'.format( - location, exception)) + if location is not None: + # Windows will raise WindowsError, which can be caught by OSError, + # if the process has not access to list the directory. The os.access() + # function cannot be used since it will return true even when os.listdir() + # fails. + try: + for directory_entry in os.listdir(location): + directory_entry_location = self._file_system.JoinPath([ + location, directory_entry]) + yield os_path_spec.OSPathSpec(location=directory_entry_location) + + except OSError as exception: + if exception.errno == errno.EACCES: + exception_string = str(exception) + if not isinstance(exception_string, py2to3.UNICODE_TYPE): + exception_string = py2to3.UNICODE_TYPE( + exception_string, errors='replace') + + raise errors.AccessError( + 'Access to directory denied with error: {0:s}'.format( + exception_string)) + else: + raise errors.BackEndError( + 'Unable to list directory: {0:s} with error: {1:s}'.format( + location, exception)) class OSFileEntry(file_entry.FileEntry): @@ -149,8 +147,9 @@ def _GetDirectory(self): Returns: OSDirectory: a directory object or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return OSDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return OSDirectory(self._file_system, self.path_spec) def _GetLink(self): """Retrieves the link.""" @@ -193,6 +192,19 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + OSFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield OSFileEntry(self._resolver_context, self._file_system, path_spec) + @property def access_time(self): """dfdatetime.DateTimeValues: access time or None if not available.""" @@ -237,16 +249,6 @@ def modification_time(self): timestamp = int(self._stat_info.st_mtime) return dfdatetime_posix_time.PosixTime(timestamp=timestamp) - @property - def sub_file_entries(self): - """generator[OSFileEntry]: sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield OSFileEntry(self._resolver_context, self._file_system, path_spec) - def GetLinkedFileEntry(self): """Retrieves the linked file entry, for example for a symbolic link. @@ -255,7 +257,7 @@ def GetLinkedFileEntry(self): """ link = self._GetLink() if not link: - return + return None path_spec = os_path_spec.OSPathSpec(location=link) return OSFileEntry(self._resolver_context, self._file_system, path_spec) @@ -268,11 +270,11 @@ def GetParentFileEntry(self): """ location = getattr(self.path_spec, 'location', None) if location is None: - return + return None parent_location = self._file_system.DirnamePath(location) if parent_location is None: - return + return None if parent_location == '': parent_location = self._file_system.PATH_SEPARATOR diff --git a/dfvfs/vfs/os_file_system.py b/dfvfs/vfs/os_file_system.py index 9da2bdfe..47bb3469 100644 --- a/dfvfs/vfs/os_file_system.py +++ b/dfvfs/vfs/os_file_system.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""The operating system file system implementation.""" +"""The file system implementation that is provided by the operating system.""" from __future__ import unicode_literals @@ -17,7 +17,7 @@ class OSFileSystem(file_system.FileSystem): - """Class that implements an operating system file system object.""" + """File system provided by the operating system.""" if platform.system() == 'Windows': PATH_SEPARATOR = '\\' @@ -27,7 +27,7 @@ class OSFileSystem(file_system.FileSystem): TYPE_INDICATOR = definitions.TYPE_INDICATOR_OS def _Close(self): - """Closes the file system object. + """Closes the file system. Raises: IOError: if the close failed. @@ -35,15 +35,16 @@ def _Close(self): return def _Open(self, path_spec, mode='rb'): - """Opens the file system object defined by path specification. + """Opens the file system defined by path specification. Args: - path_spec: a path specification (instance of PathSpec). - mode: optional file access mode. The default is 'rb' read-only binary. + path_spec (PathSpec): a path specification. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. - IOError: if the file system object could not be opened. + IOError: if the file system could not be opened. PathSpecError: if the path specification is incorrect. ValueError: if the path specification is invalid. """ @@ -55,10 +56,10 @@ def FileEntryExistsByPathSpec(self, path_spec): """Determines if a file entry for a path specification exists. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - Boolean indicating if the file entry exists. + bool: True if the file entry exists, false otherwise. """ location = getattr(path_spec, 'location', None) @@ -94,20 +95,20 @@ def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - A file entry (instance of vfs.FileEntry) or None. + OSFileEntry: a file entry or None if not available. """ if not self.FileEntryExistsByPathSpec(path_spec): - return + return None return os_file_entry.OSFileEntry(self._resolver_context, self, path_spec) def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - A file entry (instance of vfs.FileEntry) or None. + OSFileEntry: a file entry or None if not available. """ if platform.system() == 'Windows': # Return the root with the drive letter of the volume the current @@ -119,7 +120,7 @@ def GetRootFileEntry(self): location = '/' if not os.path.exists(location): - return + return None path_spec = os_path_spec.OSPathSpec(location=location) return self.GetFileEntryByPathSpec(path_spec) @@ -128,11 +129,10 @@ def JoinPath(self, path_segments): """Joins the path segments into a path. Args: - path_segments: a list of path segments. + path_segments (list[str]): path segments. Returns: - A string containing the joined path segments prefixed with the path - separator. + str: joined path segments prefixed with the path separator. """ # For paths on Windows we need to make sure to handle the first path # segment correctly. diff --git a/dfvfs/vfs/root_only_file_entry.py b/dfvfs/vfs/root_only_file_entry.py index fd585f0f..86c3800f 100644 --- a/dfvfs/vfs/root_only_file_entry.py +++ b/dfvfs/vfs/root_only_file_entry.py @@ -9,20 +9,25 @@ class RootOnlyFileEntry(file_entry.FileEntry): """Root only file system file entry.""" + # pylint: disable=redundant-returns-doc + def _GetDirectory(self): """Retrieves a directory. Returns: Directory: a directory or None if not available. """ - return + return None + + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Returns: + generator[FileEntry]: sub file entries. + """ + return iter(()) @property def name(self): """str: name of the file entry, without the full path.""" return '' - - @property - def sub_file_entries(self): - """generator[FileEntry]: sub file entries.""" - return iter(()) diff --git a/dfvfs/vfs/root_only_file_system.py b/dfvfs/vfs/root_only_file_system.py index 46fff56a..19cfa4fe 100644 --- a/dfvfs/vfs/root_only_file_system.py +++ b/dfvfs/vfs/root_only_file_system.py @@ -12,6 +12,8 @@ class RootOnlyFileSystem(file_system.FileSystem): """Root only file system object.""" + # pylint: disable=redundant-returns-doc + def _Close(self): """Closes the file system object. @@ -25,7 +27,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. diff --git a/dfvfs/vfs/sqlite_blob_file_entry.py b/dfvfs/vfs/sqlite_blob_file_entry.py index c3464d29..7731e9da 100644 --- a/dfvfs/vfs/sqlite_blob_file_entry.py +++ b/dfvfs/vfs/sqlite_blob_file_entry.py @@ -37,31 +37,27 @@ def _EntriesGenerator(self): BackEndError: if the directory could not be listed. """ table_name = getattr(self.path_spec, 'table_name', None) - if table_name is None: - return - column_name = getattr(self.path_spec, 'column_name', None) - if column_name is None: - return - - if self._number_of_entries is None: - # Open the first entry to determine how many entries we have. - # TODO: change this when there is a move this to a central temp file - # manager. https://github.com/log2timeline/dfvfs/issues/92 - path_spec = sqlite_blob_path_spec.SQLiteBlobPathSpec( - table_name=table_name, column_name=column_name, row_index=0, - parent=self.path_spec.parent) - - sub_file_entry = self._file_system.GetFileEntryByPathSpec(path_spec) - if not file_entry: - self._number_of_entries = 0 - else: - self._number_of_entries = sub_file_entry.GetNumberOfRows() - for row_index in range(0, self._number_of_entries): - yield sqlite_blob_path_spec.SQLiteBlobPathSpec( - table_name=table_name, column_name=column_name, row_index=row_index, - parent=self.path_spec.parent) + if table_name and column_name: + if self._number_of_entries is None: + # Open the first entry to determine how many entries we have. + # TODO: change this when there is a move this to a central temp file + # manager. https://github.com/log2timeline/dfvfs/issues/92 + path_spec = sqlite_blob_path_spec.SQLiteBlobPathSpec( + table_name=table_name, column_name=column_name, row_index=0, + parent=self.path_spec.parent) + + sub_file_entry = self._file_system.GetFileEntryByPathSpec(path_spec) + if not file_entry: + self._number_of_entries = 0 + else: + self._number_of_entries = sub_file_entry.GetNumberOfRows() + + for row_index in range(0, self._number_of_entries): + yield sqlite_blob_path_spec.SQLiteBlobPathSpec( + table_name=table_name, column_name=column_name, row_index=row_index, + parent=self.path_spec.parent) class SQLiteBlobFileEntry(file_entry.FileEntry): @@ -99,8 +95,9 @@ def _GetDirectory(self): Returns: SQLiteBlobDirectory: a directory or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return SQLiteBlobDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return SQLiteBlobDirectory(self._file_system, self.path_spec) def _GetStat(self): """Retrieves the stat object. @@ -126,6 +123,20 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + SQLiteBlobFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield SQLiteBlobFileEntry( + self._resolver_context, self._file_system, path_spec) + @property def name(self): """str: name of the file entry, which does not include the full path.""" @@ -148,17 +159,6 @@ def name(self): return '' - @property - def sub_file_entries(self): - """generator(SQLiteBlobFileEntry): sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield SQLiteBlobFileEntry( - self._resolver_context, self._file_system, path_spec) - def GetNumberOfRows(self): """Retrieves the number of rows in the table. @@ -189,7 +189,7 @@ def GetParentFileEntry(self): """ # If the file entry is a sub entry, return the SQLite blob directory. if self._is_virtual: - return + return None path_spec = sqlite_blob_path_spec.SQLiteBlobPathSpec( table_name=self.path_spec.table_name, diff --git a/dfvfs/vfs/sqlite_blob_file_system.py b/dfvfs/vfs/sqlite_blob_file_system.py index 39ae4c6a..9c604b73 100644 --- a/dfvfs/vfs/sqlite_blob_file_system.py +++ b/dfvfs/vfs/sqlite_blob_file_system.py @@ -41,7 +41,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. diff --git a/dfvfs/vfs/tar_file_entry.py b/dfvfs/vfs/tar_file_entry.py index 06b8e560..5269aa13 100644 --- a/dfvfs/vfs/tar_file_entry.py +++ b/dfvfs/vfs/tar_file_entry.py @@ -26,54 +26,51 @@ def _EntriesGenerator(self): """ location = getattr(self.path_spec, 'location', None) - if (location is None or - not location.startswith(self._file_system.PATH_SEPARATOR)): - return + if location and location.startswith(self._file_system.PATH_SEPARATOR): + # The TAR info name does not have the leading path separator as + # the location string does. + tar_path = location[1:] - # The TAR info name does not have the leading path separator as - # the location string does. - tar_path = location[1:] + # Set of top level sub directories that have been yielded. + processed_directories = set() - # Set of top level sub directories that have been yielded. - processed_directories = set() + tar_file = self._file_system.GetTARFile() + for tar_info in iter(tar_file.getmembers()): + path = tar_info.name - tar_file = self._file_system.GetTARFile() - for tar_info in iter(tar_file.getmembers()): - path = tar_info.name - - # Determine if the start of the TAR info name is similar to - # the location string. If not the file TAR info refers to is not in - # the same directory. - if not path or not path.startswith(tar_path): - continue - - # Ignore the directory itself. - if path == tar_path: - continue - - path_segment, suffix = self._file_system.GetPathSegmentAndSuffix( - tar_path, path) - if not path_segment: - continue - - # Sometimes the TAR file lacks directories, therefore we will - # provide virtual ones. - if suffix: - path_spec_location = self._file_system.JoinPath([ - location, path_segment]) - is_directory = True - - else: - path_spec_location = self._file_system.JoinPath([path]) - is_directory = tar_info.isdir() - - if is_directory: - if path_spec_location in processed_directories: + # Determine if the start of the TAR info name is similar to + # the location string. If not the file TAR info refers to is not in + # the same directory. + if not path or not path.startswith(tar_path): + continue + + # Ignore the directory itself. + if path == tar_path: + continue + + path_segment, suffix = self._file_system.GetPathSegmentAndSuffix( + tar_path, path) + if not path_segment: continue - processed_directories.add(path_spec_location) - yield tar_path_spec.TARPathSpec( - location=path_spec_location, parent=self.path_spec.parent) + # Sometimes the TAR file lacks directories, therefore we will + # provide virtual ones. + if suffix: + path_spec_location = self._file_system.JoinPath([ + location, path_segment]) + is_directory = True + + else: + path_spec_location = self._file_system.JoinPath([path]) + is_directory = tar_info.isdir() + + if is_directory: + if path_spec_location in processed_directories: + continue + processed_directories.add(path_spec_location) + + yield tar_path_spec.TARPathSpec( + location=path_spec_location, parent=self.path_spec.parent) class TARFileEntry(file_entry.FileEntry): @@ -126,8 +123,9 @@ def _GetDirectory(self): Returns: TARDirectory: a directory or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return TARDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return TARDirectory(self._file_system, self.path_spec) def _GetLink(self): """Retrieves the link. @@ -174,27 +172,12 @@ def _GetStat(self): return stat_object - @property - def name(self): - """str: name of the file entry, which does not include the full path.""" - path = getattr(self.path_spec, 'location', None) - if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): - try: - path = path.decode(self._file_system.encoding) - except UnicodeDecodeError: - path = None - return self._file_system.BasenamePath(path) + def _GetSubFileEntries(self): + """Retrieves sub file entries. - @property - def modification_time(self): - """dfdatetime.DateTimeValues: modification time or None if not available.""" - timestamp = getattr(self._tar_info, 'mtime', None) - if timestamp is not None: - return dfdatetime_posix_time.PosixTime(timestamp=timestamp) - - @property - def sub_file_entries(self): - """generator(TARFileEntry): sub file entries.""" + Yields: + TARFileEntry: a sub file entry. + """ tar_file = self._file_system.GetTARFile() if self._directory is None: @@ -215,6 +198,25 @@ def sub_file_entries(self): yield TARFileEntry( self._resolver_context, self._file_system, path_spec, **kwargs) + @property + def name(self): + """str: name of the file entry, which does not include the full path.""" + path = getattr(self.path_spec, 'location', None) + if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): + try: + path = path.decode(self._file_system.encoding) + except UnicodeDecodeError: + path = None + return self._file_system.BasenamePath(path) + + @property + def modification_time(self): + """dfdatetime.DateTimeValues: modification time or None if not available.""" + timestamp = getattr(self._tar_info, 'mtime', None) + if timestamp is None: + return None + return dfdatetime_posix_time.PosixTime(timestamp=timestamp) + def GetParentFileEntry(self): """Retrieves the parent file entry. @@ -223,11 +225,11 @@ def GetParentFileEntry(self): """ location = getattr(self.path_spec, 'location', None) if location is None: - return + return None parent_location = self._file_system.DirnamePath(location) if parent_location is None: - return + return None if parent_location == '': parent_location = self._file_system.PATH_SEPARATOR @@ -262,7 +264,7 @@ def GetTARInfo(self): raise errors.PathSpecError('Invalid location in path specification.') if len(location) == 1: - return + return None tar_file = self._file_system.GetTARFile() try: diff --git a/dfvfs/vfs/tar_file_system.py b/dfvfs/vfs/tar_file_system.py index 23380940..315415c7 100644 --- a/dfvfs/vfs/tar_file_system.py +++ b/dfvfs/vfs/tar_file_system.py @@ -53,7 +53,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. @@ -125,7 +126,7 @@ def GetFileEntryByPathSpec(self, path_spec): TARFileEntry: file entry or None. """ if not self.FileEntryExistsByPathSpec(path_spec): - return + return None location = getattr(path_spec, 'location', None) @@ -181,7 +182,7 @@ def GetTARInfoByPathSpec(self, path_spec): raise errors.PathSpecError('Invalid location in path specification.') if len(location) == 1: - return + return None try: return self._tar_file.getmember(location[1:]) diff --git a/dfvfs/vfs/tsk_file_entry.py b/dfvfs/vfs/tsk_file_entry.py index 460d355c..56294139 100644 --- a/dfvfs/vfs/tsk_file_entry.py +++ b/dfvfs/vfs/tsk_file_entry.py @@ -6,11 +6,11 @@ import copy import decimal -import pytsk3 - from dfdatetime import definitions as dfdatetime_definitions from dfdatetime import interface as dfdatetime_interface +import pytsk3 + from dfvfs.lib import definitions from dfvfs.lib import errors from dfvfs.path import tsk_path_spec @@ -227,7 +227,7 @@ 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. + bool: True if the data stream is the default data stream, false if not. """ if not self._tsk_attribute or not self._file_system: return True @@ -237,7 +237,7 @@ def IsDefault(self): return attribute_type in ( pytsk3.TSK_FS_ATTR_TYPE_HFS_DEFAULT, pytsk3.TSK_FS_ATTR_TYPE_HFS_DATA) - elif self._file_system.IsNTFS(): + if self._file_system.IsNTFS(): return not bool(self.name) return True @@ -464,8 +464,8 @@ def __init__( self.entry_type = definitions.FILE_ENTRY_TYPE_DIRECTORY elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_LNK: self.entry_type = definitions.FILE_ENTRY_TYPE_LINK - elif (tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_CHR or - tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_BLK): + elif tsk_fs_meta_type in ( + pytsk3.TSK_FS_META_TYPE_CHR, pytsk3.TSK_FS_META_TYPE_BLK): self.entry_type = definitions.FILE_ENTRY_TYPE_DEVICE elif tsk_fs_meta_type == pytsk3.TSK_FS_META_TYPE_FIFO: self.entry_type = definitions.FILE_ENTRY_TYPE_PIPE @@ -549,8 +549,9 @@ def _GetDirectory(self): Returns: TSKDirectory: directory or None. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return TSKDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return TSKDirectory(self._file_system, self.path_spec) def _GetLink(self): """Retrieves the link. @@ -633,6 +634,19 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + TSKFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield TSKFileEntry(self._resolver_context, self._file_system, path_spec) + def _GetTimeValue(self, name): """Retrieves a date and time value. @@ -662,11 +676,11 @@ def _TSKFileTimeCopyToStatTimeTuple(self, tsk_file, time_value): time_value (str): name of the time value. Returns: - tuple containing: - int: POSIX timestamp in seconds. None on error, or if the file system - does not include the requested timestamp. - int: remainder in 100 nano seconds. None on error, or if the file system - does not support sub-second precision. + tuple[int, int]: number of seconds since 1970-01-01 00:00:00 and fraction + of second in 100 nano seconds intervals. The number of seconds is None + on error, or if the file system does not include the requested + timestamp. The fraction of second is None on error, or if the file + system does not support sub-second precision. Raises: BackEndError: if the TSK File .info, .info.meta or info.fs_info @@ -730,6 +744,7 @@ def deletion_time(self): return self._GetTimeValue('dtime') + # pylint: disable=missing-return-doc,missing-return-type-doc @property def name(self): """str: name of the file entry, which does not include the full path. @@ -766,16 +781,6 @@ def modification_time(self): return self._GetTimeValue('mtime') - @property - def sub_file_entries(self): - """generator(TSKFileEntry): sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield TSKFileEntry(self._resolver_context, self._file_system, path_spec) - def GetFileObject(self, data_stream_name=''): """Retrieves the file-like object. diff --git a/dfvfs/vfs/tsk_file_system.py b/dfvfs/vfs/tsk_file_system.py index 2ea750fe..a7037bfe 100644 --- a/dfvfs/vfs/tsk_file_system.py +++ b/dfvfs/vfs/tsk_file_system.py @@ -130,7 +130,7 @@ def GetFileEntryByPathSpec(self, path_spec): pass if tsk_file is None: - return + return None # TODO: is there a way to determine the parent inode number here? return tsk_file_entry.TSKFileEntry( @@ -189,7 +189,7 @@ def GetRootInode(self): # we need to check if the attribute exists and has a value other # than None if getattr(self._tsk_file_system, 'info', None) is None: - return + return None # Note that because pytsk3.TSK_FS_INFO does not explicitly define # root_inum we need to check if the attribute exists and has a value diff --git a/dfvfs/vfs/tsk_partition_file_entry.py b/dfvfs/vfs/tsk_partition_file_entry.py index 79b4fc3a..4a6b56aa 100644 --- a/dfvfs/vfs/tsk_partition_file_entry.py +++ b/dfvfs/vfs/tsk_partition_file_entry.py @@ -22,43 +22,39 @@ def _EntriesGenerator(self): Yields: TSKPartitionPathSpec: a path specification. """ - # Only the virtual root file has directory entries. + location = getattr(self.path_spec, 'location', None) part_index = getattr(self.path_spec, 'part_index', None) start_offset = getattr(self.path_spec, 'start_offset', None) - if part_index is not None or start_offset is not None: - return - - location = getattr(self.path_spec, 'location', None) - if location is None or location != self._file_system.LOCATION_ROOT: - return - - tsk_volume = self._file_system.GetTSKVolume() - bytes_per_sector = tsk_partition.TSKVolumeGetBytesPerSector(tsk_volume) - part_index = 0 - partition_index = 0 + # Only the virtual root file has directory entries. + if (part_index is None and start_offset is None and + location is not None and location == self._file_system.LOCATION_ROOT): + tsk_volume = self._file_system.GetTSKVolume() + bytes_per_sector = tsk_partition.TSKVolumeGetBytesPerSector(tsk_volume) + part_index = 0 + partition_index = 0 - # pytsk3 does not handle the Volume_Info iterator correctly therefore - # the explicit list is needed to prevent the iterator terminating too - # soon or looping forever. - for tsk_vs_part in list(tsk_volume): - kwargs = {} + # pytsk3 does not handle the Volume_Info iterator correctly therefore + # the explicit list is needed to prevent the iterator terminating too + # soon or looping forever. + for tsk_vs_part in list(tsk_volume): + kwargs = {} - if tsk_partition.TSKVsPartIsAllocated(tsk_vs_part): - partition_index += 1 - kwargs['location'] = '/p{0:d}'.format(partition_index) + if tsk_partition.TSKVsPartIsAllocated(tsk_vs_part): + partition_index += 1 + kwargs['location'] = '/p{0:d}'.format(partition_index) - kwargs['part_index'] = part_index - part_index += 1 + kwargs['part_index'] = part_index + part_index += 1 - start_sector = tsk_partition.TSKVsPartGetStartSector(tsk_vs_part) + start_sector = tsk_partition.TSKVsPartGetStartSector(tsk_vs_part) - if start_sector is not None: - kwargs['start_offset'] = start_sector * bytes_per_sector + if start_sector is not None: + kwargs['start_offset'] = start_sector * bytes_per_sector - kwargs['parent'] = self.path_spec.parent + kwargs['parent'] = self.path_spec.parent - yield tsk_partition_path_spec.TSKPartitionPathSpec(**kwargs) + yield tsk_partition_path_spec.TSKPartitionPathSpec(**kwargs) class TSKPartitionFileEntry(file_entry.FileEntry): @@ -111,8 +107,9 @@ def _GetDirectory(self): Returns: TSKPartitionDirectory: a directory or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return TSKPartitionDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return TSKPartitionDirectory(self._file_system, self.path_spec) def _GetStat(self): """Retrieves the stat object. @@ -146,6 +143,20 @@ def _GetStat(self): return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + TSKPartitionFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield TSKPartitionFileEntry( + self._resolver_context, self._file_system, path_spec) + @property def name(self): """str: name of the file entry, which does not include the full path.""" @@ -159,17 +170,7 @@ def name(self): self._name = '' return self._name - @property - def sub_file_entries(self): - """generator(TSKPartitionFileEntry): sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield TSKPartitionFileEntry( - self._resolver_context, self._file_system, path_spec) - + # pylint: disable=redundant-returns-doc def GetParentFileEntry(self): """Retrieves the parent file entry. @@ -177,7 +178,7 @@ def GetParentFileEntry(self): TSKPartitionFileEntry: parent file entry or None if not available. """ # TODO: implement https://github.com/log2timeline/dfvfs/issues/76. - return + return None def GetTSKVsPart(self): """Retrieves the TSK volume system part. diff --git a/dfvfs/vfs/tsk_partition_file_system.py b/dfvfs/vfs/tsk_partition_file_system.py index c9d4167c..705cd0d9 100644 --- a/dfvfs/vfs/tsk_partition_file_system.py +++ b/dfvfs/vfs/tsk_partition_file_system.py @@ -25,7 +25,7 @@ def __init__(self, resolver_context): """Initializes a file system object. Args: - resolver_context: the resolver context (instance of resolver.Context). + resolver_context (Context): a resolver context. """ super(TSKPartitionFileSystem, self).__init__(resolver_context) self._file_object = None @@ -46,8 +46,9 @@ def _Open(self, path_spec, mode='rb'): """Opens the file system object defined by path specification. Args: - path_spec: a path specification (instance of PathSpec). - mode: optional file access mode. The default is 'rb' read-only binary. + path_spec (PathSpec): a path specification. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. @@ -76,10 +77,10 @@ def FileEntryExistsByPathSpec(self, path_spec): """Determines if a file entry for a path specification exists. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - Boolean indicating if the file entry exists. + bool: True if the file entry exists or false otherwise. """ tsk_vs_part, _ = tsk_partition.GetTSKVsPartByPathSpec( self._tsk_volume, path_spec) @@ -96,10 +97,10 @@ def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. Args: - path_spec: a path specification (instance of PathSpec). + path_spec (PathSpec): a path specification. Returns: - A file entry (instance of vfs.TSKPartitionFileEntry) or None. + TSKPartitionFileEntry: a file entry or None of not available. """ tsk_vs_part, partition_index = tsk_partition.GetTSKVsPartByPathSpec( self._tsk_volume, path_spec) @@ -110,7 +111,8 @@ def GetFileEntryByPathSpec(self, path_spec): # but should have a location. if tsk_vs_part is None: if location is None or location != self.LOCATION_ROOT: - return + return None + return tsk_partition_file_entry.TSKPartitionFileEntry( self._resolver_context, self, path_spec, is_root=True, is_virtual=True) @@ -125,7 +127,7 @@ def GetRootFileEntry(self): """Retrieves the root file entry. Returns: - A file entry (instance of vfs.FileEntry). + TSKPartitionFileEntry: a file entry or None of not available. """ path_spec = tsk_partition_path_spec.TSKPartitionPathSpec( location=self.LOCATION_ROOT, parent=self._path_spec.parent) @@ -135,6 +137,6 @@ def GetTSKVolume(self): """Retrieves the TSK volume object. Returns: - The TSK volume object (instance of pytsk3.Volume_Info). + pytsk3.Volume_Info: a TSK volume object. """ return self._tsk_volume diff --git a/dfvfs/vfs/vshadow_file_entry.py b/dfvfs/vfs/vshadow_file_entry.py index 49bc15be..94cdb772 100644 --- a/dfvfs/vfs/vshadow_file_entry.py +++ b/dfvfs/vfs/vshadow_file_entry.py @@ -24,21 +24,18 @@ def _EntriesGenerator(self): Yields: VShadowPathSpec: a path specification. """ - # Only the virtual root file has directory entries. - store_index = getattr(self.path_spec, 'store_index', None) - if store_index is not None: - return - location = getattr(self.path_spec, 'location', None) - if location is None or location != self._file_system.LOCATION_ROOT: - return + store_index = getattr(self.path_spec, 'store_index', None) - vshadow_volume = self._file_system.GetVShadowVolume() + # Only the virtual root file has directory entries. + if (store_index is None and location is not None and + location == self._file_system.LOCATION_ROOT): + vshadow_volume = self._file_system.GetVShadowVolume() - for store_index in range(0, vshadow_volume.number_of_stores): - yield vshadow_path_spec.VShadowPathSpec( - location='/vss{0:d}'.format(store_index + 1), - store_index=store_index, parent=self.path_spec.parent) + for store_index in range(0, vshadow_volume.number_of_stores): + yield vshadow_path_spec.VShadowPathSpec( + location='/vss{0:d}'.format(store_index + 1), + store_index=store_index, parent=self.path_spec.parent) class VShadowFileEntry(file_entry.FileEntry): @@ -86,8 +83,9 @@ def _GetDirectory(self): Returns: VShadowDirectory: a directory None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return VShadowDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return VShadowDirectory(self._file_system, self.path_spec) def _GetStat(self): """Retrieves information about the file entry. @@ -108,12 +106,28 @@ def _GetStat(self): # The root file entry is virtual and should have type directory. return stat_object + def _GetSubFileEntries(self): + """Retrieves sub file entries. + + Yields: + VShadowFileEntry: a sub file entry. + """ + if self._directory is None: + self._directory = self._GetDirectory() + + if self._directory: + for path_spec in self._directory.entries: + yield VShadowFileEntry( + self._resolver_context, self._file_system, path_spec) + @property def creation_time(self): """dfdatetime.DateTimeValues: creation time or None if not available.""" - if self._vshadow_store is not None: - timestamp = self._vshadow_store.get_creation_time_as_integer() - return dfdatetime_filetime.Filetime(timestamp=timestamp) + if self._vshadow_store is None: + return None + + timestamp = self._vshadow_store.get_creation_time_as_integer() + return dfdatetime_filetime.Filetime(timestamp=timestamp) @property def name(self): @@ -130,17 +144,6 @@ def name(self): self._name = '' return self._name - @property - def sub_file_entries(self): - """generator[FileEntry]: sub file entries.""" - if self._directory is None: - self._directory = self._GetDirectory() - - if self._directory: - for path_spec in self._directory.entries: - yield VShadowFileEntry( - self._resolver_context, self._file_system, path_spec) - def GetParentFileEntry(self): """Retrieves the parent file entry. @@ -149,7 +152,7 @@ def GetParentFileEntry(self): """ store_index = vshadow.VShadowPathSpecGetStoreIndex(self.path_spec) if store_index is None: - return + return None return self._file_system.GetRootFileEntry() diff --git a/dfvfs/vfs/vshadow_file_system.py b/dfvfs/vfs/vshadow_file_system.py index 6feb8c14..a0f63a1e 100644 --- a/dfvfs/vfs/vshadow_file_system.py +++ b/dfvfs/vfs/vshadow_file_system.py @@ -47,7 +47,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): path specification. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. @@ -89,8 +90,7 @@ def FileEntryExistsByPathSpec(self, path_spec): location = getattr(path_spec, 'location', None) return location is not None and location == self.LOCATION_ROOT - return (store_index >= 0 and - store_index < self._vshadow_volume.number_of_stores) + return 0 <= store_index < self._vshadow_volume.number_of_stores def GetFileEntryByPathSpec(self, path_spec): """Retrieves a file entry for a path specification. @@ -108,13 +108,15 @@ def GetFileEntryByPathSpec(self, path_spec): if store_index is None: location = getattr(path_spec, 'location', None) if location is None or location != self.LOCATION_ROOT: - return + return None + return vshadow_file_entry.VShadowFileEntry( self._resolver_context, self, path_spec, is_root=True, is_virtual=True) if store_index < 0 or store_index >= self._vshadow_volume.number_of_stores: - return + return None + return vshadow_file_entry.VShadowFileEntry( self._resolver_context, self, path_spec) @@ -138,8 +140,10 @@ def GetVShadowStoreByPathSpec(self, path_spec): pyvshadow.store: a VSS store or None if not available. """ store_index = vshadow.VShadowPathSpecGetStoreIndex(path_spec) - if store_index is not None: - return self._vshadow_volume.get_store(store_index) + if store_index is None: + return None + + return self._vshadow_volume.get_store(store_index) def GetVShadowVolume(self): """Retrieves a VSS volume. diff --git a/dfvfs/vfs/zip_file_entry.py b/dfvfs/vfs/zip_file_entry.py index 884276b2..c8f997d6 100644 --- a/dfvfs/vfs/zip_file_entry.py +++ b/dfvfs/vfs/zip_file_entry.py @@ -26,57 +26,54 @@ def _EntriesGenerator(self): """ location = getattr(self.path_spec, 'location', None) - if (location is None or - not location.startswith(self._file_system.PATH_SEPARATOR)): - return + if location and location.startswith(self._file_system.PATH_SEPARATOR): + # The zip_info filename does not have the leading path separator + # as the location string does. + zip_path = location[1:] - # The zip_info filename does not have the leading path separator - # as the location string does. - zip_path = location[1:] + # Set of top level sub directories that have been yielded. + processed_directories = set() - # Set of top level sub directories that have been yielded. - processed_directories = set() + zip_file = self._file_system.GetZipFile() + for zip_info in zip_file.infolist(): + path = getattr(zip_info, 'filename', None) + if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): + try: + path = path.decode(self._file_system.encoding) + except UnicodeDecodeError: + path = None + + if not path or not path.startswith(zip_path): + continue - zip_file = self._file_system.GetZipFile() - for zip_info in zip_file.infolist(): - path = getattr(zip_info, 'filename', None) - if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): - try: - path = path.decode(self._file_system.encoding) - except UnicodeDecodeError: - path = None - - if not path or not path.startswith(zip_path): - continue - - # Ignore the directory itself. - if path == zip_path: - continue - - path_segment, suffix = self._file_system.GetPathSegmentAndSuffix( - zip_path, path) - if not path_segment: - continue - - # Some times the ZIP file lacks directories, therefore we will - # provide virtual ones. - if suffix: - path_spec_location = self._file_system.JoinPath([ - location, path_segment]) - is_directory = True - else: - path_spec_location = self._file_system.JoinPath([path]) - is_directory = path.endswith('/') - - if is_directory: - if path_spec_location in processed_directories: + # Ignore the directory itself. + if path == zip_path: + continue + + path_segment, suffix = self._file_system.GetPathSegmentAndSuffix( + zip_path, path) + if not path_segment: continue - processed_directories.add(path_spec_location) - # Restore / at end path to indicate a directory. - path_spec_location += self._file_system.PATH_SEPARATOR - yield zip_path_spec.ZipPathSpec( - location=path_spec_location, parent=self.path_spec.parent) + # Some times the ZIP file lacks directories, therefore we will + # provide virtual ones. + if suffix: + path_spec_location = self._file_system.JoinPath([ + location, path_segment]) + is_directory = True + else: + path_spec_location = self._file_system.JoinPath([path]) + is_directory = path.endswith('/') + + if is_directory: + if path_spec_location in processed_directories: + continue + processed_directories.add(path_spec_location) + # Restore / at end path to indicate a directory. + path_spec_location += self._file_system.PATH_SEPARATOR + + yield zip_path_spec.ZipPathSpec( + location=path_spec_location, parent=self.path_spec.parent) class ZipFileEntry(file_entry.FileEntry): @@ -136,8 +133,9 @@ def _GetDirectory(self): Returns: ZipDirectory: a directory or None if not available. """ - if self.entry_type == definitions.FILE_ENTRY_TYPE_DIRECTORY: - return ZipDirectory(self._file_system, self.path_spec) + if self.entry_type != definitions.FILE_ENTRY_TYPE_DIRECTORY: + return None + return ZipDirectory(self._file_system, self.path_spec) def _GetStat(self): """Retrieves information about the file entry. @@ -170,27 +168,12 @@ def _GetStat(self): return stat_object - @property - def name(self): - """str: name of the file entry, without the full path.""" - path = getattr(self.path_spec, 'location', None) - if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): - try: - path = path.decode(self._file_system.encoding) - except UnicodeDecodeError: - path = None - return self._file_system.BasenamePath(path) - - @property - def modification_time(self): - """dfdatetime.DateTimeValues: modification time or None if not available.""" - if self._zip_info is not None: - time_elements = getattr(self._zip_info, 'date_time', None) - return dfdatetime_time_elements.TimeElements(time_elements) + def _GetSubFileEntries(self): + """Retrieves sub file entries. - @property - def sub_file_entries(self): - """generator[ZipFileEntry]: sub file entries.""" + Yields: + ZipFileEntry: a sub file entry. + """ if self._directory is None: self._directory = self._GetDirectory() @@ -210,6 +193,26 @@ def sub_file_entries(self): yield ZipFileEntry( self._resolver_context, self._file_system, path_spec, **kwargs) + @property + def name(self): + """str: name of the file entry, without the full path.""" + path = getattr(self.path_spec, 'location', None) + if path is not None and not isinstance(path, py2to3.UNICODE_TYPE): + try: + path = path.decode(self._file_system.encoding) + except UnicodeDecodeError: + path = None + return self._file_system.BasenamePath(path) + + @property + def modification_time(self): + """dfdatetime.DateTimeValues: modification time or None if not available.""" + if self._zip_info is None: + return None + + time_elements = getattr(self._zip_info, 'date_time', None) + return dfdatetime_time_elements.TimeElements(time_elements) + def GetParentFileEntry(self): """Retrieves the parent file entry. @@ -218,11 +221,11 @@ def GetParentFileEntry(self): """ location = getattr(self.path_spec, 'location', None) if location is None: - return + return None parent_location = self._file_system.DirnamePath(location) if parent_location is None: - return + return None parent_path_spec = getattr(self.path_spec, 'parent', None) @@ -258,7 +261,7 @@ def GetZipInfo(self): raise errors.PathSpecError('Invalid location in path specification.') if len(location) == 1: - return + return None zip_file = self._file_system.GetZipFile() try: diff --git a/dfvfs/vfs/zip_file_system.py b/dfvfs/vfs/zip_file_system.py index 2e5a28e4..e51891f8 100644 --- a/dfvfs/vfs/zip_file_system.py +++ b/dfvfs/vfs/zip_file_system.py @@ -27,7 +27,7 @@ def __init__(self, resolver_context, encoding='utf-8'): """Initializes a file system. Args: - resolver_context: the resolver context (instance of resolver.Context). + resolver_context (Context): a resolver context. encoding (Optional[str]): encoding of the file entry name. """ super(ZipFileSystem, self).__init__(resolver_context) @@ -52,7 +52,8 @@ def _Open(self, path_spec, mode='rb'): Args: path_spec (PathSpec): path specification of the file system. - mode (Optional[str]): file access mode. + mode (Optional[str]): file access mode. The default is 'rb' which + represents read-only binary. Raises: AccessError: if the access to open the file was denied. @@ -119,7 +120,7 @@ def GetFileEntryByPathSpec(self, path_spec): ZipFileEntry: a file entry or None. """ if not self.FileEntryExistsByPathSpec(path_spec): - return + return None location = getattr(path_spec, 'location', None) @@ -176,3 +177,5 @@ def GetZipInfoByPathSpec(self, path_spec): if len(location) > 1: return self._zip_file.getinfo(location[1:]) + + return None diff --git a/dfvfs/volume/volume_system.py b/dfvfs/volume/volume_system.py index 90ff1474..b5999b3f 100644 --- a/dfvfs/volume/volume_system.py +++ b/dfvfs/volume/volume_system.py @@ -127,7 +127,7 @@ def GetAttribute(self, identifier): self._is_parsed = True if identifier not in self._attributes: - return + return None return self._attributes[identifier] @@ -222,8 +222,10 @@ def GetSectionByIndex(self, section_index): self._Parse() self._is_parsed = True - if section_index >= 0 and section_index < len(self._sections): - return self._sections[section_index] + if section_index < 0 or section_index >= len(self._sections): + return None + + return self._sections[section_index] def GetVolumeByIdentifier(self, volume_identifier): """Retrieves a specific volume based on the identifier. @@ -254,9 +256,11 @@ def GetVolumeByIndex(self, volume_index): self._Parse() self._is_parsed = True - if volume_index >= 0 and volume_index < len(self._volume_identifiers): - volume_identifier = self._volume_identifiers[volume_index] - return self._volumes[volume_identifier] + if volume_index < 0 or volume_index >= len(self._volume_identifiers): + return None + + volume_identifier = self._volume_identifiers[volume_index] + return self._volumes[volume_identifier] @abc.abstractmethod def Open(self, path_spec): diff --git a/examples/list_file_entries.py b/examples/list_file_entries.py index ee5912fe..52ebe1f0 100644 --- a/examples/list_file_entries.py +++ b/examples/list_file_entries.py @@ -65,12 +65,12 @@ def _GetHumanReadableSize(self, size): magnitude_1024 += 1 size_string_1000 = None - if magnitude_1000 > 0 and magnitude_1000 <= 7: + if 0 <= magnitude_1000 <= 7: size_string_1000 = '{0:.1f}{1:s}'.format( size_1000, self._UNITS_1000[magnitude_1000]) size_string_1024 = None - if magnitude_1024 > 0 and magnitude_1024 <= 7: + if 0 <= magnitude_1024 <= 7: size_string_1024 = '{0:.1f}{1:s}'.format( size_1024, self._UNITS_1024[magnitude_1024]) diff --git a/examples/recursive_hasher.py b/examples/recursive_hasher.py index b14766c5..43a899af 100644 --- a/examples/recursive_hasher.py +++ b/examples/recursive_hasher.py @@ -194,12 +194,12 @@ def _FormatHumanReadableSize(self, size): magnitude_1024 += 1 size_string_1000 = None - if magnitude_1000 > 0 and magnitude_1000 <= 7: + if 0 <= magnitude_1000 <= 7: size_string_1000 = '{0:.1f}{1:s}'.format( size_1000, self._UNITS_1000[magnitude_1000]) size_string_1024 = None - if magnitude_1024 > 0 and magnitude_1024 <= 7: + if 0 <= magnitude_1024 <= 7: size_string_1024 = '{0:.1f}{1:s}'.format( size_1024, self._UNITS_1024[magnitude_1024]) @@ -550,10 +550,10 @@ def _CalculateHashDataStream(self, file_entry, data_stream_name): 'Unable to open path specification:\n{0:s}' 'with error: {1!s}').format( file_entry.path_spec.comparable, exception)) - return + return None if not file_object: - return + return None try: data = file_object.read(self._READ_BUFFER_SIZE) @@ -565,7 +565,7 @@ def _CalculateHashDataStream(self, file_entry, data_stream_name): 'Unable to read from path specification:\n{0:s}' 'with error: {1!s}').format( file_entry.path_spec.comparable, exception)) - return + return None finally: file_object.close() diff --git a/examples/source_analyzer.py b/examples/source_analyzer.py index 6b28d2d5..fffbbe30 100644 --- a/examples/source_analyzer.py +++ b/examples/source_analyzer.py @@ -18,18 +18,17 @@ class SourceAnalyzer(object): - """Class that recursively calculates message digest hashes of files.""" + """Analyzer to recursively check for volumes and file systems.""" # Class constant that defines the default read buffer size. _READ_BUFFER_SIZE = 32768 def __init__(self, auto_recurse=True): - """Initializes the source analyzer object. + """Initializes a source analyzer. Args: - auto_recurse: optional boolean value to indicate if the scan should - automatically recurse as far as possible. The default - is True. + auto_recurse (Optional[bool]): True if the scan should automatically + recurse as far as possible. """ super(SourceAnalyzer, self).__init__() self._auto_recurse = auto_recurse @@ -41,7 +40,7 @@ def _EncodeString(self, string): """Encodes a string in the preferred encoding. Returns: - A byte string containing the encoded string. + bytes: encoded string. """ try: # Note that encode() will first convert string into a Unicode string @@ -67,10 +66,9 @@ def _PromptUserForEncryptedVolumeCredential( """Prompts the user to provide a credential for an encrypted volume. Args: - scan_context: the source scanner context (instance of - SourceScannerContext). - locked_scan_node: the locked scan node (instance of SourceScanNode). - output_writer: the output writer (instance of StdoutWriter). + scan_context (SourceScannerContext): the source scanner context. + locked_scan_node (SourceScanNode): the locked scan node. + output_writer (StdoutWriter): the output writer. """ credentials = credentials_manager.CredentialsManager.GetCredentials( locked_scan_node.path_spec) @@ -134,13 +132,13 @@ def Analyze(self, source_path, output_writer): """Analyzes the source. Args: - source_path: the source path. - output_writer: the output writer (instance of StdoutWriter). + source_path (str): the source path. + output_writer (StdoutWriter): the output writer. Raises: RuntimeError: if the source path does not exists, or if the source path - is not a file or directory, or if the format of or within - the source file is not supported. + is not a file or directory, or if the format of or within the source + file is not supported. """ if not os.path.exists(source_path): raise RuntimeError('No such source: {0:s}.'.format(source_path)) @@ -185,13 +183,13 @@ def Analyze(self, source_path, output_writer): class StdoutWriter(object): - """Class that defines a stdout output writer.""" + """Stdout output writer.""" def Open(self): """Opens the output writer object. Returns: - A boolean containing True if successful or False if not. + bool: True if open was successful or False if not. """ return True @@ -203,7 +201,7 @@ def WriteLine(self, line): """Writes a line of text to stdout. Args: - line: line of text without a new line indicator. + line (str): line of text without a new line indicator. """ print(line) @@ -211,9 +209,8 @@ def WriteScanContext(self, scan_context, scan_step=None): """Writes the source scanner context to stdout. Args: - scan_context: the source scanner context (instance of - SourceScannerContext). - scan_step: optional integer indicating the scan step. + scan_context (SourceScannerContext): the source scanner context. + scan_step (Optional[int]): the scan step, where None represents no step. """ if scan_step is not None: print('Scan step: {0:d}'.format(scan_step)) @@ -229,9 +226,8 @@ def WriteScanNode(self, scan_node, indentation=''): """Writes the source scanner node to stdout. Args: - scan_node: the scan node (instance of SourceScanNode). - indentation: optional indentation string. - scan_step: optional integer indicating the scan step. + scan_node (SourceScanNode): the scan node. + indentation (Optional[str]): indentation. """ if not scan_node: return @@ -265,7 +261,7 @@ def WriteString(self, string): """Writes a string of text to stdout. Args: - line: string of text. + string (str): string of text. """ print(string, end='') @@ -274,16 +270,16 @@ def Main(): """The main program function. Returns: - A boolean containing True if successful or False if not. + bool: True if successful or False if not. """ argument_parser = argparse.ArgumentParser(description=( 'Calculates a message digest hash for every file in a directory or ' 'storage media image.')) argument_parser.add_argument( - 'source', nargs='?', action='store', metavar='image.raw', - default=None, help=('path of the directory or filename of a storage ' - 'media image containing the file.')) + 'source', nargs='?', action='store', metavar='image.raw', default=None, + help=('path of the directory or filename of a storage media image ' + 'containing the file.')) argument_parser.add_argument( '--no-auto-recurse', '--no_auto_recurse', dest='no_auto_recurse', diff --git a/tests/analyzer/analyzer.py b/tests/analyzer/analyzer.py index b3d8874d..935e4cab 100644 --- a/tests/analyzer/analyzer.py +++ b/tests/analyzer/analyzer.py @@ -27,13 +27,14 @@ class TestAnalyzerHelper(analyzer_helper.AnalyzerHelper): TYPE_INDICATOR = 'test' - def AnalyzeFileObject(self, unused_file_object): + # pylint: disable=redundant-returns-doc,unused-argument + def AnalyzeFileObject(self, file_object): """Retrieves the format specification. This is the fall through implementation that raises a RuntimeError. Args: - unused_file_object (FileIO): file-like object. + file_object (FileIO): file-like object. Returns: str: type indicator if the file-like object contains a supported format @@ -43,7 +44,7 @@ def AnalyzeFileObject(self, unused_file_object): class AnalyzerTest(shared_test_lib.BaseTestCase): - """Tests for the format analyzer.""" + """Format analyzer tests.""" # pylint: disable=protected-access diff --git a/tests/compression/manager.py b/tests/compression/manager.py index f667056f..b2ece148 100644 --- a/tests/compression/manager.py +++ b/tests/compression/manager.py @@ -19,21 +19,20 @@ class TestDecompressor(decompressor.Decompressor): COMPRESSION_METHOD = 'test' - def Decompress(self, unused_compressed_data): + def Decompress(self, compressed_data): """Decompresses the compressed data. Args: - compressed_data: a byte string containing the compressed data. + compressed_data (bytes): compressed data. Returns: - A tuple containing a byte string of the uncompressed data and - the remaining compressed data. + tuple(bytes, bytes): uncompressed data and remaining compressed data. """ return b'', b'' class CompressionManagerTest(shared_test_lib.BaseTestCase): - """Tests for the compression manager.""" + """Compression manager tests.""" def testDecompressorRegistration(self): """Tests the DeregisterDecompressor and DeregisterDecompressor functions.""" diff --git a/tests/encoding/manager.py b/tests/encoding/manager.py index 0c34c5a7..424c2ac9 100644 --- a/tests/encoding/manager.py +++ b/tests/encoding/manager.py @@ -19,21 +19,20 @@ class TestDecoder(decoder.Decoder): ENCODING_METHOD = 'test' - def Decode(self, unused_encoded_data): + def Decode(self, encoded_data): """Decode the encoded data. Args: - encoded_data: a byte string containing the encoded data. + encoded_data (byte): encoded data. Returns: - A tuple containing a byte string of the decoded data and - the remaining encoded data. + tuple(bytes, bytes): decoded data and remaining encoded data. """ return b'', b'' class EncodingManagerTest(shared_test_lib.BaseTestCase): - """Class to test the encoding manager.""" + """Encoding manager tests.""" def testDecoderRegistration(self): """Tests the DeregisterDecoder and DeregisterDecoder functions.""" diff --git a/tests/encryption/manager.py b/tests/encryption/manager.py index 7ed7234c..98f9f2e1 100644 --- a/tests/encryption/manager.py +++ b/tests/encryption/manager.py @@ -15,25 +15,25 @@ class TestDecrypter(decrypter.Decrypter): - """Class that implements a test decrypter.""" + """Test decrypter.""" ENCRYPTION_METHOD = 'test' - def Decrypt(self, unused_encrypted_data): + def Decrypt(self, encrypted_data): """Decrypt the encrypted data. Args: - encrypted_data: a byte string containing the encrypted data. + encrypted_data (bytes): the encrypted data. Returns: - A tuple containing a byte string of the decrypted data and - the remaining encrypted data. + tuple[bytes, bytes]: byte string of the decrypted data and the remaining + encrypted data. """ return b'', b'' class EncryptionManagerTest(shared_test_lib.BaseTestCase): - """Class to test the encryption manager.""" + """Encryption manager tests.""" def testDecrypterRegistration(self): """Tests the DeregisterDecrypter and DeregisterDecrypter functions.""" diff --git a/tests/end-to-end.py b/tests/end-to-end.py index 3fa43d5c..8f375862 100755 --- a/tests/end-to-end.py +++ b/tests/end-to-end.py @@ -59,6 +59,8 @@ class TestCase(object): easily run on different input files. """ + # pylint: disable=redundant-returns-doc + NAME = None def __init__( @@ -185,7 +187,7 @@ def GetTestCaseObject( test_results_path, debug_output=debug_output) if not test_case_object: - return + return None cls._test_case_objects[name] = test_case_object @@ -446,6 +448,8 @@ def RunTests(self): class ExampleScriptTestCase(TestCase): """Common functionality for example script-based test cases.""" + # pylint: disable=redundant-returns-doc + def _CompareOutputFile(self, test_definition, temp_directory): """Compares the output file with a reference output file. diff --git a/tests/helpers/volume_scanner.py b/tests/helpers/volume_scanner.py index 383d782a..065f5a5d 100644 --- a/tests/helpers/volume_scanner.py +++ b/tests/helpers/volume_scanner.py @@ -25,7 +25,7 @@ class TestVolumeScannerMediator(volume_scanner.VolumeScannerMediator): _BDE_PASSWORD = 'bde-TEST' - def GetPartitionIdentifiers(self, unused_volume_system, volume_identifiers): + def GetPartitionIdentifiers(self, volume_system, volume_identifiers): """Retrieves partition identifiers. This method can be used to prompt the user to provide partition identifiers. @@ -42,7 +42,7 @@ def GetPartitionIdentifiers(self, unused_volume_system, volume_identifiers): """ return volume_identifiers - def GetVSSStoreIdentifiers(self, unused_volume_system, volume_identifiers): + def GetVSSStoreIdentifiers(self, volume_system, volume_identifiers): """Retrieves VSS store identifiers. This method can be used to prompt the user to provide VSS store identifiers. @@ -62,8 +62,7 @@ def GetVSSStoreIdentifiers(self, unused_volume_system, volume_identifiers): for volume_identifier in volume_identifiers] def UnlockEncryptedVolume( - self, source_scanner_object, scan_context, locked_scan_node, - unused_credentials): + self, source_scanner_object, scan_context, locked_scan_node, credentials): """Unlocks an encrypted volume. This method can be used to prompt the user to provide encrypted volume diff --git a/tests/lib/raw.py b/tests/lib/raw.py index e1001ff2..fb6f1ae0 100644 --- a/tests/lib/raw.py +++ b/tests/lib/raw.py @@ -23,7 +23,6 @@ def _BuildFileFakeFileSystem( """Builds a fake file system containing storage media RAW segment files. Args: - filename (str): filename of the first segment file with extension. segment_filenames (list[str]): segment filenames. segment_file_path_specs (list[PathSpec]): resulting segment file path specifications. diff --git a/tests/resolver_helpers/test_lib.py b/tests/resolver_helpers/test_lib.py index 571ecc3d..7dfe0368 100644 --- a/tests/resolver_helpers/test_lib.py +++ b/tests/resolver_helpers/test_lib.py @@ -12,20 +12,22 @@ class TestResolverHelper(resolver_helper.ResolverHelper): """Test resolver helper.""" + # pylint: disable=redundant-returns-doc,unused-argument + TYPE_INDICATOR = 'TEST' def __init__(self, **kwargs): - """Initializes the resolver helper object.""" + """Initializes the test resolver helper.""" super(TestResolverHelper, self).__init__(parent=None, **kwargs) - def NewFileObject(self, unused_resolver_context): + def NewFileObject(self, resolver_context): """Creates a new file-like object. Args: resolver_context (Context): resolver context. Returns: - FileIO: file-like object. + FileIO: file-like object, which is None for testing. """ return @@ -41,7 +43,7 @@ def _TestNewFileObject(self, resolver_helper_object): """Tests the NewFileObject function. Args: - resolver_context (Context): resolver context. + resolver_helper_object (ResolverHelper): resolver helper. """ file_object = resolver_helper_object.NewFileObject(self._resolver_context) @@ -51,7 +53,7 @@ def _TestNewFileSystem(self, resolver_helper_object): """Tests the NewFileSystem function. Args: - resolver_context (Context): resolver context. + resolver_helper_object (ResolverHelper): resolver helper. """ file_system = resolver_helper_object.NewFileSystem(self._resolver_context) @@ -61,7 +63,7 @@ def _TestNewFileSystemRaisesRuntimeError(self, resolver_helper_object): """Tests the NewFileSystem function raises a RuntimeError. Args: - resolver_context (Context): resolver context. + resolver_helper_object (ResolverHelper): resolver helper. """ with self.assertRaises(RuntimeError): resolver_helper_object.NewFileSystem(self._resolver_context) @@ -70,7 +72,7 @@ def _TestOpenFileObject(self, resolver_helper_object, path_spec): """Tests the OpenFileObject function. Args: - resolver_context (Context): resolver context. + resolver_helper_object (ResolverHelper): resolver helper. path_spec (PathSpec): path specification. """ file_object = resolver_helper_object.OpenFileObject( diff --git a/tests/test_lib.py b/tests/test_lib.py index d761058e..a88e6ee2 100644 --- a/tests/test_lib.py +++ b/tests/test_lib.py @@ -42,12 +42,11 @@ class BaseTestCase(unittest.TestCase): maxDiff = None def _assertSubFileEntries(self, file_entry, expected_sub_file_entry_names): - """Helper function that asserts the sub file entries have the - expected names. + """Asserts that sub file entries have match the expected names. Args: file_entry (FileEntry): file entry. - sub_file_entry_names (list[str]): sub file entry names. + expected_sub_file_entry_names (list[str]): expected sub file entry names. """ self.assertEqual( file_entry.number_of_sub_file_entries, diff --git a/tests/vfs/tsk_partition_file_entry.py b/tests/vfs/tsk_partition_file_entry.py index 63a9365c..b29dcd21 100644 --- a/tests/vfs/tsk_partition_file_entry.py +++ b/tests/vfs/tsk_partition_file_entry.py @@ -17,7 +17,7 @@ @shared_test_lib.skipUnlessHasTestFile(['tsk_volume_system.raw']) class TSKPartitionFileEntryTest(shared_test_lib.BaseTestCase): - """The unit test for the TSK partition file entry object.""" + """TSK partition file entry tests.""" def setUp(self): """Sets up the needed objects used throughout the test.""" diff --git a/utils/dependencies.py b/utils/dependencies.py index 7e8e7636..29379494 100644 --- a/utils/dependencies.py +++ b/utils/dependencies.py @@ -312,6 +312,7 @@ def _PrintCheckDependencyStatus( result (bool): True if the Python module is available and conforms to the minimum required version, False otherwise. status_message (str): status message. + verbose_output (Optional[bool]): True if output should be verbose. """ if not result or dependency.is_optional: if dependency.is_optional: