Source code for surfactant.fileinfo

# Copyright 2023 Lawrence Livermore National Security, LLC
# See the top-level LICENSE file for details.
#
# SPDX-License-Identifier: MIT
import os
import stat
import sys
from hashlib import md5, sha1, sha256


[docs] def get_file_info(filename): """Get information about a file. Args: filename (str): Name of file. Returns: Optional[dict]: Dictionary that contains info about the file. """ try: fstats = os.stat(filename) except (FileNotFoundError, PermissionError): return None filehidden = False # stat.UF_HIDDEN (file shouldn't be shown in GUI macOS 10.5+) if hasattr(fstats, "st_flags"): filehidden = bool(fstats.st_flags & stat.UF_HIDDEN) # stat.FILE_ATTRIBUTE_HIDDEN (shouldn't be shown on Windows) if hasattr(fstats, "st_file_attributes"): filehidden = bool(fstats.st_file_attributes & stat.FILE_ATTRIBUTE_HIDDEN) # Should consider if symlinks on Linux/macOS/Windows, or reparse points on Windows need to be recognized and handled # lstat() does not follow symbolic links # fstats.st_reparse_tag from os.lstat() # stat.IO_REPARSE_TAG_SYMLINK # stat.IO_REPARSE_TAG_MOUNT_POINT return { "size": fstats.st_size, "accesstime": fstats.st_atime, "modifytime": fstats.st_mtime, "createtime": fstats.st_ctime, "filemode": stat.filemode(fstats.st_mode), "filehidden": filehidden, }
[docs] def calc_file_hashes(filename): """Calculate hashes for a file specified. Args: filename (str): Name of file. Returns: Optional[dict]: Dictionary with the sha256, sha1, and md5 hashes of the file. """ sha256_hash = sha256() sha1_hash = sha1() # hashlib.md5 usedforsecurity flag was added in Python 3.9 if sys.version_info >= (3, 9): # avoid error with FIPS-compliant OpenSSL library builds complaining about md5 md5_hash = md5(usedforsecurity=False) else: md5_hash = md5() b = bytearray(4096) mv = memoryview(b) try: with open(filename, "rb", buffering=0) as f: while n := f.readinto(mv): sha256_hash.update(mv[:n]) sha1_hash.update(mv[:n]) md5_hash.update(mv[:n]) except (FileNotFoundError, PermissionError): return None return { "sha256": sha256_hash.hexdigest(), "sha1": sha1_hash.hexdigest(), "md5": md5_hash.hexdigest(), }
[docs] def sha256sum(filename): """Calculate sha256 hash for the file specified. May throw a FileNotFound or PermissionError exception. Args: filename (str): Name of file. Returns: Optional[str]: The sha256 hash of the file. Raises: FileNotFoundError: If the given filename could not be found. PermissionError: If the given filename could not be read. """ h = sha256() with open(filename, "rb") as f: # Reading is buffered by default (https://docs.python.org/3/library/functions.html#open) chunk = f.read(h.block_size) while chunk: h.update(chunk) chunk = f.read(h.block_size) return h.hexdigest()