Skip to content

Commit

Permalink
Handle symlink target distributed over muliple extents
Browse files Browse the repository at this point in the history
  • Loading branch information
twiggler committed Oct 14, 2024
1 parent eec7ae6 commit f65cd0b
Showing 1 changed file with 11 additions and 5 deletions.
16 changes: 11 additions & 5 deletions dissect/xfs/xfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ def walk_extents(self, fsb: int) -> Iterator[tuple[int, int, int, int]]:
def walk_agi(self) -> Iterator[c_xfs.xfs_inobt_rec]:
yield from self.xfs.walk_agi(self.agi.agi_root, self.num)

def walk_tree(self, fsb: int, magic: list[int] | None = None, small: bool = False):
def walk_tree(self, fsb: int, magic: list[int] | None = None, small: bool = False) -> Iterator[bytes]:
agnum, blknum = fsb_to_bb(fsb, self.sb.sb_agblklog)
block = agnum * self.xfs.sb.sb_agblocks + blknum

Expand All @@ -248,7 +248,7 @@ def __init__(
filename: str | None = None,
filetype: int | None = None,
parent: INode | None = None,
):
) -> None:
self.ag = ag
self.xfs = ag.xfs
self.inum = inum + (ag.num << ag._inum_bits)
Expand Down Expand Up @@ -325,10 +325,16 @@ def link(self) -> str:

if not self._link:
if self.inode.di_format != c_xfs.xfs_dinode_fmt.XFS_DINODE_FMT_LOCAL and self.xfs.version == 5:
# Almost always, symlinks (max size of 1024) fit within a block. If the block size if 512, we might
# need three blocks. These three blocks could theoretially be distributed over multiple extents.
# Linux kernel handles this by using sl_offset to piece the symlink back together.
# As this edge case of an edge case is very unlikely, it is unsupported until we observe it.
if len(self.dataruns()) > 1:
raise NotImplementedError(f"{self!r} has a symlink distributed over multiple extents")

Check warning on line 333 in dissect/xfs/xfs.py

View check run for this annotation

Codecov / codecov/patch

dissect/xfs/xfs.py#L333

Added line #L333 was not covered by tests

# We do not use open because for non-resident symlinks self.size does not include the symlink header
runs = self.dataruns()
symlink_size = c_xfs.xfs_dsymlink_hdr.size + self.size
fh = RunlistStream(self.xfs.fh, runs, symlink_size, self.xfs.block_size)
symlink_size = len(c_xfs.xfs_dsymlink_hdr) + self.size
fh = RunlistStream(self.xfs.fh, self.dataruns(), symlink_size, self.xfs.block_size)

header = c_xfs.xfs_dsymlink_hdr(fh)
if header.sl_magic != c_xfs.XFS_SYMLINK_MAGIC:
Expand Down

0 comments on commit f65cd0b

Please sign in to comment.