diff --git a/dissect/target/filesystems/btrfs.py b/dissect/target/filesystems/btrfs.py index 8d6fa0c6a..ae9754fbc 100644 --- a/dissect/target/filesystems/btrfs.py +++ b/dissect/target/filesystems/btrfs.py @@ -1,5 +1,6 @@ from __future__ import annotations +import math from typing import BinaryIO, Iterator, Optional, Union import dissect.btrfs as btrfs @@ -153,7 +154,7 @@ def lstat(self) -> fsutil.stat_result: node = self.entry.inode # mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime - st_info = st_info = fsutil.stat_result( + st_info = fsutil.stat_result( [ entry.mode, entry.inum, @@ -176,5 +177,10 @@ def lstat(self) -> fsutil.stat_result: # Btrfs has a birth time, called otime st_info.st_birthtime = entry.otime.timestamp() + st_info.st_birthtime_ns = entry.otime_ns + + # Add block information of the filesystem + st_info.st_blksize = entry.btrfs.sector_size + st_info.st_blocks = math.ceil(entry.size / st_info.st_blksize) return st_info diff --git a/tests/filesystems/test_btrfs.py b/tests/filesystems/test_btrfs.py new file mode 100644 index 000000000..eecc3f0de --- /dev/null +++ b/tests/filesystems/test_btrfs.py @@ -0,0 +1,57 @@ +from unittest.mock import Mock + +import pytest +from dissect.btrfs.btrfs import INode +from dissect.btrfs.c_btrfs import c_btrfs + +from dissect.target.filesystems.btrfs import BtrfsFilesystemEntry + + +@pytest.mark.parametrize( + "sector_size, filesize, expected_blocks", + [ + (0x1000, 0x343, 0x1), + (0x1000, 0x1000, 0x1), + (0x1000, 0x1001, 0x2), + ], + ids=["lower", "equal", "greater"], +) +def test_stat_information_file_blocksize(sector_size: int, filesize: int, expected_blocks: int) -> None: + entry = INode(Mock(), 42) + entry.btrfs = Mock(sector_size=sector_size) + timestamp = c_btrfs.btrfs_timespec() + entry.inode = c_btrfs.btrfs_inode_item( + mode=0o777, + nlink=0, + uid=1000, + gid=1000, + size=filesize, + atime=timestamp, + ctime=timestamp, + otime=timestamp, + mtime=timestamp, + ) + + fs_entry = BtrfsFilesystemEntry(Mock(), "some/path", entry) + + stat_info = fs_entry.lstat() + + assert stat_info.st_mode == 0o777 + assert stat_info.st_ino == 42 + assert stat_info.st_dev == 0 + assert stat_info.st_nlink == 0 + assert stat_info.st_uid == 1000 + assert stat_info.st_gid == 1000 + assert stat_info.st_size == filesize + + assert stat_info.st_atime == 0.0 + assert stat_info.st_atime_ns == 0 + assert stat_info.st_mtime == 0.0 + assert stat_info.st_mtime_ns == 0 + assert stat_info.st_ctime == 0.0 + assert stat_info.st_ctime_ns == 0 + assert stat_info.st_birthtime_ns == 0 + assert stat_info.st_birthtime_ns == 0 + + assert stat_info.st_blksize == sector_size + assert stat_info.st_blocks == expected_blocks