Skip to content

Commit f65cd0b

Browse files
committed
Handle symlink target distributed over muliple extents
1 parent eec7ae6 commit f65cd0b

File tree

1 file changed

+11
-5
lines changed

1 file changed

+11
-5
lines changed

dissect/xfs/xfs.py

+11-5
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ def walk_extents(self, fsb: int) -> Iterator[tuple[int, int, int, int]]:
230230
def walk_agi(self) -> Iterator[c_xfs.xfs_inobt_rec]:
231231
yield from self.xfs.walk_agi(self.agi.agi_root, self.num)
232232

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

@@ -248,7 +248,7 @@ def __init__(
248248
filename: str | None = None,
249249
filetype: int | None = None,
250250
parent: INode | None = None,
251-
):
251+
) -> None:
252252
self.ag = ag
253253
self.xfs = ag.xfs
254254
self.inum = inum + (ag.num << ag._inum_bits)
@@ -325,10 +325,16 @@ def link(self) -> str:
325325

326326
if not self._link:
327327
if self.inode.di_format != c_xfs.xfs_dinode_fmt.XFS_DINODE_FMT_LOCAL and self.xfs.version == 5:
328+
# Almost always, symlinks (max size of 1024) fit within a block. If the block size if 512, we might
329+
# need three blocks. These three blocks could theoretially be distributed over multiple extents.
330+
# Linux kernel handles this by using sl_offset to piece the symlink back together.
331+
# As this edge case of an edge case is very unlikely, it is unsupported until we observe it.
332+
if len(self.dataruns()) > 1:
333+
raise NotImplementedError(f"{self!r} has a symlink distributed over multiple extents")
334+
328335
# We do not use open because for non-resident symlinks self.size does not include the symlink header
329-
runs = self.dataruns()
330-
symlink_size = c_xfs.xfs_dsymlink_hdr.size + self.size
331-
fh = RunlistStream(self.xfs.fh, runs, symlink_size, self.xfs.block_size)
336+
symlink_size = len(c_xfs.xfs_dsymlink_hdr) + self.size
337+
fh = RunlistStream(self.xfs.fh, self.dataruns(), symlink_size, self.xfs.block_size)
332338

333339
header = c_xfs.xfs_dsymlink_hdr(fh)
334340
if header.sl_magic != c_xfs.XFS_SYMLINK_MAGIC:

0 commit comments

Comments
 (0)