From 5bd67ea07d9d8f44fc5ba50f5d4a8683b36f923b Mon Sep 17 00:00:00 2001 From: Miauwkeru Date: Tue, 3 Sep 2024 12:39:51 +0000 Subject: [PATCH 1/5] Add birthtime_ns and nr of blocks and blocksize to btrfs stat output --- dissect/target/filesystems/btrfs.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/dissect/target/filesystems/btrfs.py b/dissect/target/filesystems/btrfs.py index 8d6fa0c6a..f55d84c50 100644 --- a/dissect/target/filesystems/btrfs.py +++ b/dissect/target/filesystems/btrfs.py @@ -71,6 +71,10 @@ def __init__(self, fs: BtrfsFilesystem, subvol: Optional[str] = None, subvolid: else: self.subvolume = self.btrfs.default_subvolume + # Calculate the blocks availlable on the device + self.sector_size = self.btrfs.sector_size + self.blocks = self.btrfs.sb.total_bytes // self.sector_size + def get(self, path: str) -> FilesystemEntry: return BtrfsFilesystemEntry(self, path, self._get_node(path)) @@ -153,7 +157,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, @@ -173,8 +177,13 @@ def lstat(self) -> fsutil.stat_result: st_info.st_atime_ns = entry.atime_ns st_info.st_mtime_ns = entry.mtime_ns st_info.st_ctime_ns = entry.ctime_ns + st_info.st_birthtime_ns = entry.otime_ns # Btrfs has a birth time, called otime st_info.st_birthtime = entry.otime.timestamp() + # Add block information of the filesystem + st_info.st_blksize = self.fs.sector_size + st_info.st_blocks = self.fs.blocks + return st_info From 809321b1a56d67574ccc355f75dee45652e9fd34 Mon Sep 17 00:00:00 2001 From: Miauwkeru Date: Thu, 5 Sep 2024 14:42:00 +0000 Subject: [PATCH 2/5] Get blocks for filesystem entry --- dissect/target/filesystems/btrfs.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/dissect/target/filesystems/btrfs.py b/dissect/target/filesystems/btrfs.py index f55d84c50..60debcfec 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 @@ -71,10 +72,6 @@ def __init__(self, fs: BtrfsFilesystem, subvol: Optional[str] = None, subvolid: else: self.subvolume = self.btrfs.default_subvolume - # Calculate the blocks availlable on the device - self.sector_size = self.btrfs.sector_size - self.blocks = self.btrfs.sb.total_bytes // self.sector_size - def get(self, path: str) -> FilesystemEntry: return BtrfsFilesystemEntry(self, path, self._get_node(path)) @@ -183,7 +180,7 @@ def lstat(self) -> fsutil.stat_result: st_info.st_birthtime = entry.otime.timestamp() # Add block information of the filesystem - st_info.st_blksize = self.fs.sector_size - st_info.st_blocks = self.fs.blocks + st_info.st_blksize = entry.btrfs.sector_size + st_info.st_blocks = math.ceil(entry.size / st_info.st_blksize) return st_info From a04c1799c34c4cbf12366b888d273badfb588968 Mon Sep 17 00:00:00 2001 From: Miauwkeru Date: Mon, 9 Sep 2024 10:51:59 +0000 Subject: [PATCH 3/5] Add test for file blocksize calculation --- tests/filesystems/test_btrfs.py | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 tests/filesystems/test_btrfs.py diff --git a/tests/filesystems/test_btrfs.py b/tests/filesystems/test_btrfs.py new file mode 100644 index 000000000..bbd878367 --- /dev/null +++ b/tests/filesystems/test_btrfs.py @@ -0,0 +1,33 @@ +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(), None) + entry.btrfs = Mock(sector_size=sector_size) + timestamp = c_btrfs.btrfs_timespec() + entry.inode = c_btrfs.btrfs_inode_item( + size=filesize, atime=timestamp, ctime=timestamp, otime=timestamp, mtime=timestamp + ) + + fs_entry = BtrfsFilesystemEntry(Mock(alt_seperator="/"), "unknown_path", entry) + + stat_info = fs_entry.lstat() + + assert stat_info.st_birthtime_ns == 0 + assert stat_info.st_blksize == sector_size + assert stat_info.st_blocks == expected_blocks From 1ed41cb1f9bfa0c7345897e4ee1fb77604437044 Mon Sep 17 00:00:00 2001 From: Miauwkeru Date: Thu, 12 Sep 2024 07:41:53 +0000 Subject: [PATCH 4/5] Resolve review comments --- dissect/target/filesystems/btrfs.py | 2 +- tests/filesystems/test_btrfs.py | 31 ++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/dissect/target/filesystems/btrfs.py b/dissect/target/filesystems/btrfs.py index 60debcfec..ae9754fbc 100644 --- a/dissect/target/filesystems/btrfs.py +++ b/dissect/target/filesystems/btrfs.py @@ -174,10 +174,10 @@ def lstat(self) -> fsutil.stat_result: st_info.st_atime_ns = entry.atime_ns st_info.st_mtime_ns = entry.mtime_ns st_info.st_ctime_ns = entry.ctime_ns - st_info.st_birthtime_ns = entry.otime_ns # 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 diff --git a/tests/filesystems/test_btrfs.py b/tests/filesystems/test_btrfs.py index bbd878367..dddcf0a53 100644 --- a/tests/filesystems/test_btrfs.py +++ b/tests/filesystems/test_btrfs.py @@ -17,17 +17,42 @@ ids=["lower", "equal", "greater"], ) def test_stat_information_file_blocksize(sector_size: int, filesize: int, expected_blocks: int) -> None: - entry = INode(Mock(), None) + entry = INode(Mock(), 42) entry.btrfs = Mock(sector_size=sector_size) timestamp = c_btrfs.btrfs_timespec() entry.inode = c_btrfs.btrfs_inode_item( - size=filesize, atime=timestamp, ctime=timestamp, otime=timestamp, mtime=timestamp + mode=0o777, + nlink=0, + uid=1000, + gid=1000, + size=filesize, + atime=timestamp, + ctime=timestamp, + otime=timestamp, + mtime=timestamp, ) - fs_entry = BtrfsFilesystemEntry(Mock(alt_seperator="/"), "unknown_path", entry) + 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 From 3cb44c2ac06923ca9c7cde795301e71b73f39f11 Mon Sep 17 00:00:00 2001 From: Miauwkeru Date: Thu, 12 Sep 2024 08:48:09 +0000 Subject: [PATCH 5/5] fix linting --- tests/filesystems/test_btrfs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/filesystems/test_btrfs.py b/tests/filesystems/test_btrfs.py index dddcf0a53..eecc3f0de 100644 --- a/tests/filesystems/test_btrfs.py +++ b/tests/filesystems/test_btrfs.py @@ -44,7 +44,6 @@ def test_stat_information_file_blocksize(sector_size: int, filesize: int, expect 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