Skip to content

Commit

Permalink
Merge branch 'main' into fix/strip-translated-file-path
Browse files Browse the repository at this point in the history
  • Loading branch information
Poeloe authored Nov 19, 2024
2 parents 6ab17b8 + d6eb12e commit fad3cae
Show file tree
Hide file tree
Showing 71 changed files with 2,122 additions and 532 deletions.
2 changes: 1 addition & 1 deletion dissect/target/container.py
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ def open(item: Union[list, str, BinaryIO, Path], *args, **kwargs):
log.info("Failed to import %s", container)
log.debug("", exc_info=e)
except Exception as e:
raise ContainerError(f"Failed to open container {item}", cause=e)
raise ContainerError(f"Failed to open container {item}") from e
finally:
if first_fh_opened:
first_fh.close()
Expand Down
11 changes: 6 additions & 5 deletions dissect/target/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

import os
import sys
import traceback
Expand All @@ -7,13 +9,12 @@
class Error(Exception):
"""Generic dissect.target error"""

def __init__(self, message=None, cause=None, extra=None):
def __init__(self, message: str | None = None, extra: list[Exception] | None = None):
if extra:
exceptions = "\n\n".join(["".join(traceback.format_exception_only(type(e), e)) for e in extra])
message = f"{message}\n\nAdditionally, the following exceptions occurred:\n\n{exceptions}"

super().__init__(message)
self.__cause__ = cause
self.__extra__ = extra


Expand Down Expand Up @@ -72,15 +73,15 @@ class PluginNotFoundError(PluginError):
"""Plugin cannot be found."""


class FileNotFoundError(FilesystemError):
class FileNotFoundError(FilesystemError, FileNotFoundError):
"""The requested path could not be found."""


class IsADirectoryError(FilesystemError):
class IsADirectoryError(FilesystemError, IsADirectoryError):
"""The entry is a directory."""


class NotADirectoryError(FilesystemError):
class NotADirectoryError(FilesystemError, NotADirectoryError):
"""The entry is not a directory."""


Expand Down
4 changes: 2 additions & 2 deletions dissect/target/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -1142,7 +1142,7 @@ def get(self, path: str, relentry: Optional[FilesystemEntry] = None) -> Filesyst
try:
return entry.top.get(fsutil.join(*parts[i:], alt_separator=self.alt_separator))
except FilesystemError as e:
raise FileNotFoundError(full_path, cause=e)
raise FileNotFoundError(full_path) from e
else:
raise FileNotFoundError(full_path)

Expand Down Expand Up @@ -1715,7 +1715,7 @@ def open(fh: BinaryIO, *args, **kwargs) -> Filesystem:
log.info("Failed to import %s", filesystem)
log.debug("", exc_info=e)
except Exception as e:
raise FilesystemError(f"Failed to open filesystem for {fh}", cause=e)
raise FilesystemError(f"Failed to open filesystem for {fh}") from e
finally:
fh.seek(offset)

Expand Down
8 changes: 4 additions & 4 deletions dissect/target/filesystems/btrfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,13 @@ def _get_node(self, path: str, node: Optional[btrfs.INode] = None) -> btrfs.INod
try:
return self.subvolume.get(path, node)
except btrfs.FileNotFoundError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e
except btrfs.NotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except btrfs.NotASymlinkError as e:
raise NotASymlinkError(path, cause=e)
raise NotASymlinkError(path) from e
except btrfs.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class BtrfsFilesystemEntry(FilesystemEntry):
Expand Down
8 changes: 4 additions & 4 deletions dissect/target/filesystems/extfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ def _get_node(self, path: str, node: Optional[extfs.INode] = None) -> extfs.INod
try:
return self.extfs.get(path, node)
except extfs.FileNotFoundError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e
except extfs.NotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except extfs.NotASymlinkError as e:
raise NotASymlinkError(path, cause=e)
raise NotASymlinkError(path) from e
except extfs.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class ExtFilesystemEntry(FilesystemEntry):
Expand Down
38 changes: 22 additions & 16 deletions dissect/target/filesystems/fat.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import datetime
import math
import stat
from typing import BinaryIO, Iterator, Optional, Union

Expand Down Expand Up @@ -41,11 +42,11 @@ def _get_entry(
try:
return self.fatfs.get(path, dirent=entry)
except fat_exc.FileNotFoundError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e
except fat_exc.NotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except fat_exc.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class FatFilesystemEntry(FilesystemEntry):
Expand Down Expand Up @@ -100,16 +101,21 @@ def stat(self, follow_symlinks: bool = True) -> fsutil.stat_result:
def lstat(self) -> fsutil.stat_result:
"""Return the stat information of the given path, without resolving links."""
# mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime
st_info = [
(stat.S_IFDIR if self.is_dir() else stat.S_IFREG) | 0o777,
self.entry.cluster,
id(self.fs),
1,
0,
0,
self.entry.size,
self.entry.atime.replace(tzinfo=self.fs.tzinfo).timestamp(),
self.entry.mtime.replace(tzinfo=self.fs.tzinfo).timestamp(),
self.entry.ctime.replace(tzinfo=self.fs.tzinfo).timestamp(),
]
return fsutil.stat_result(st_info)
st_info = fsutil.stat_result(
[
(stat.S_IFDIR if self.is_dir() else stat.S_IFREG) | 0o777,
self.entry.cluster,
id(self.fs),
1,
0,
0,
self.entry.size,
self.entry.atime.replace(tzinfo=self.fs.tzinfo).timestamp(),
self.entry.mtime.replace(tzinfo=self.fs.tzinfo).timestamp(),
self.entry.ctime.replace(tzinfo=self.fs.tzinfo).timestamp(),
]
)

st_info.st_blocks = math.ceil(self.entry.size / self.entry.fs.cluster_size)
st_info.st_blksize = self.entry.fs.cluster_size
return st_info
15 changes: 11 additions & 4 deletions dissect/target/filesystems/ffs.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ def _get_node(self, path: str, node: Optional[ffs.INode] = None) -> ffs.INode:
try:
return self.ffs.get(path, node)
except ffs.FileNotFoundError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e
except ffs.NotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except ffs.NotASymlinkError as e:
raise NotASymlinkError(path, cause=e)
raise NotASymlinkError(path) from e
except ffs.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class FfsFilesystemEntry(FilesystemEntry):
Expand Down Expand Up @@ -126,6 +126,12 @@ def lstat(self) -> fsutil.stat_result:
]
)

# Note: stat on linux always returns the default block size of 4096
# We are returning the actual block size of the filesystem, as on BSD
st_info.st_blksize = self.fs.ffs.block_size
# Note: st_blocks * 512 can be lower than st_blksize because FFS employs fragments
st_info.st_blocks = self.entry.nblocks

# Set the nanosecond resolution separately
st_info.st_atime_ns = self.entry.atime_ns
st_info.st_mtime_ns = self.entry.mtime_ns
Expand All @@ -134,5 +140,6 @@ def lstat(self) -> fsutil.stat_result:
# FFS2 has a birth time, FFS1 does not
if btime := self.entry.btime:
st_info.st_birthtime = btime.timestamp()
st_info.st_birthtime_ns = self.entry.btime_ns

return st_info
14 changes: 7 additions & 7 deletions dissect/target/filesystems/jffs.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ def _get_node(self, path: str, node: Optional[jffs2.INode] = None) -> jffs2.INod
try:
return self.jffs2.get(path, node)
except jffs2.FileNotFoundError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e
except jffs2.NotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except jffs2.NotASymlinkError as e:
raise NotASymlinkError(path, cause=e)
raise NotASymlinkError(path) from e
except jffs2.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class JFFSFilesystemEntry(FilesystemEntry):
Expand Down Expand Up @@ -76,13 +76,13 @@ def scandir(self) -> Iterator[FilesystemEntry]:
entry_path = fsutil.join(self.path, name, alt_separator=self.fs.alt_separator)
yield JFFSFilesystemEntry(self.fs, entry_path, entry)

def is_dir(self, follow_symlinks: bool = False) -> bool:
def is_dir(self, follow_symlinks: bool = True) -> bool:
try:
return self._resolve(follow_symlinks).entry.is_dir()
except FilesystemError:
return False

def is_file(self, follow_symlinks: bool = False) -> bool:
def is_file(self, follow_symlinks: bool = True) -> bool:
try:
return self._resolve(follow_symlinks).entry.is_file()
except FilesystemError:
Expand All @@ -97,7 +97,7 @@ def readlink(self) -> str:

return self.entry.link

def stat(self, follow_symlinks: bool = False) -> fsutil.stat_result:
def stat(self, follow_symlinks: bool = True) -> fsutil.stat_result:
return self._resolve(follow_symlinks).lstat()

def lstat(self) -> fsutil.stat_result:
Expand Down
8 changes: 4 additions & 4 deletions dissect/target/filesystems/ntfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,12 @@ def _get_record(self, path: str, root: Optional[MftRecord] = None) -> MftRecord:
try:
path = path.rsplit(":", maxsplit=1)[0]
return self.ntfs.mft.get(path, root=root)
except NtfsFileNotFoundError:
raise FileNotFoundError(path)
except NtfsFileNotFoundError as e:
raise FileNotFoundError(path) from e
except NtfsNotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except NtfsError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class NtfsFilesystemEntry(FilesystemEntry):
Expand Down
6 changes: 3 additions & 3 deletions dissect/target/filesystems/smb.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ def _get_entry(self, path: str) -> SharedFile:
except SessionError as e:
if e.error == STATUS_NOT_A_DIRECTORY:
# STATUS_NOT_A_DIRECTORY
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
else:
# 0xC000000F is STATUS_NO_SUCH_FILE, but everything else should raise a FileNotFoundError anyway
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e

if len(result) != 1:
raise FileNotFoundError(path)
Expand Down Expand Up @@ -106,7 +106,7 @@ def open(self) -> SmbStream:
try:
return SmbStream(self.fs.conn, self.fs.share_name, self.path, self.entry.get_filesize())
except SessionError as e:
raise FilesystemError(f"Failed to open file: {self.path}", cause=e)
raise FilesystemError(f"Failed to open file: {self.path}") from e

def is_dir(self, follow_symlinks: bool = True) -> bool:
try:
Expand Down
8 changes: 4 additions & 4 deletions dissect/target/filesystems/squashfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,13 @@ def _get_node(self, path: str, node: Optional[INode] = None) -> INode:
try:
return self.squashfs.get(path, node)
except exceptions.FileNotFoundError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e
except exceptions.NotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except exceptions.NotASymlinkError as e:
raise NotASymlinkError(path, cause=e)
raise NotASymlinkError(path) from e
except exceptions.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class SquashFSFilesystemEntry(FilesystemEntry):
Expand Down
8 changes: 4 additions & 4 deletions dissect/target/filesystems/vmfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,13 @@ def _get_node(self, path: str, node: Optional[FileDescriptor] = None) -> FileDes
try:
return self.vmfs.get(path, node)
except vmfs.FileNotFoundError as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e
except vmfs.NotADirectoryError as e:
raise NotADirectoryError(path, cause=e)
raise NotADirectoryError(path) from e
except vmfs.NotASymlinkError as e:
raise NotASymlinkError(path, cause=e)
raise NotASymlinkError(path) from e
except vmfs.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class VmfsFilesystemEntry(FilesystemEntry):
Expand Down
14 changes: 7 additions & 7 deletions dissect/target/filesystems/xfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ def get(self, path: str) -> FilesystemEntry:
def _get_node(self, path: str, node: Optional[xfs.INode] = None) -> xfs.INode:
try:
return self.xfs.get(path, node)
except xfs.FileNotFoundError:
raise FileNotFoundError(path)
except xfs.NotADirectoryError:
raise NotADirectoryError(path)
except xfs.NotASymlinkError:
raise NotASymlinkError(path)
except xfs.FileNotFoundError as e:
raise FileNotFoundError(path) from e
except xfs.NotADirectoryError as e:
raise NotADirectoryError(path) from e
except xfs.NotASymlinkError as e:
raise NotASymlinkError(path) from e
except xfs.Error as e:
raise FileNotFoundError(path, cause=e)
raise FileNotFoundError(path) from e


class XfsFilesystemEntry(FilesystemEntry):
Expand Down
Loading

0 comments on commit fad3cae

Please sign in to comment.