From ef28b08e9a05a1c0e07f95f8bb7b910fd38d49d9 Mon Sep 17 00:00:00 2001 From: Roel de Jong <12800443+twiggler@users.noreply.github.com> Date: Thu, 17 Oct 2024 14:05:02 +0200 Subject: [PATCH 1/2] Support block size and number of blocks in stat output --- dissect/target/filesystems/jffs.py | 5 ++++ tests/filesystems/test_jffs2.py | 47 ++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 tests/filesystems/test_jffs2.py diff --git a/dissect/target/filesystems/jffs.py b/dissect/target/filesystems/jffs.py index c6e2a4819..8d1e91551 100644 --- a/dissect/target/filesystems/jffs.py +++ b/dissect/target/filesystems/jffs.py @@ -119,4 +119,9 @@ def lstat(self) -> fsutil.stat_result: ] ) + # JFFS2 block size is a function of the "erase size" of the underlying flash device. + # Linux stat reports the default block size, which is defined as 4k in libc. + st_info.st_blksize = 4096 + st_info.st_blocks = (node.isize + 511) // 512 if node.isize else 0 + return st_info diff --git a/tests/filesystems/test_jffs2.py b/tests/filesystems/test_jffs2.py new file mode 100644 index 000000000..fee7845a5 --- /dev/null +++ b/tests/filesystems/test_jffs2.py @@ -0,0 +1,47 @@ +from datetime import datetime +from typing import Iterator +from unittest.mock import Mock, patch +import pytest + +from dissect.target.filesystems.jffs import JFFSFilesystem, JFFSFilesystemEntry + + +@pytest.fixture +def jffs_fs() -> Iterator[JFFSFilesystem]: + with patch("dissect.jffs.jffs2.JFFS2"): + jffs_fs = JFFSFilesystem(Mock()) + yield jffs_fs + + +@pytest.fixture +def jffs_fs_entry(jffs_fs: JFFSFilesystem) -> Iterator[JFFSFilesystemEntry]: + raw_inode = Mock(uid=1000, guid=999, isize=165002) + inode = Mock( + mode=33204, + inum=4, + inode=raw_inode, + atime=datetime(2024, 10, 1, 12, 0, 0), + mtime=datetime(2024, 10, 2, 12, 0, 0), + ctime=datetime(2024, 10, 3, 12, 0, 0), + ) + + entry = JFFSFilesystemEntry(jffs_fs, "/some_file", inode) + yield entry + + +def test_jffs2(jffs_fs: JFFSFilesystem, jffs_fs_entry: JFFSFilesystemEntry) -> None: + stat = jffs_fs_entry.stat() + + entry = jffs_fs_entry.entry + assert stat.st_mode == entry.mode + assert stat.st_ino == entry.inum + assert stat.st_dev == id(jffs_fs) + assert stat.st_nlink == 1 + assert stat.st_uid == entry.inode.uid + assert stat.st_gid == entry.inode.gid + assert stat.st_size == entry.inode.isize + assert stat.st_atime == entry.atime.timestamp() + assert stat.st_mtime == entry.mtime.timestamp() + assert stat.st_ctime == entry.ctime.timestamp() + assert stat.st_blksize == 4096 + assert stat.st_blocks == 323 From 7543c0d1237d9dc6ce3fecb4a79668dac0762741 Mon Sep 17 00:00:00 2001 From: Roel de Jong <12800443+twiggler@users.noreply.github.com> Date: Thu, 17 Oct 2024 17:37:13 +0200 Subject: [PATCH 2/2] Return 0 blocks for symlinks and directories --- dissect/target/filesystems/jffs.py | 2 +- tests/filesystems/test_jffs2.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dissect/target/filesystems/jffs.py b/dissect/target/filesystems/jffs.py index 8d1e91551..2d0122940 100644 --- a/dissect/target/filesystems/jffs.py +++ b/dissect/target/filesystems/jffs.py @@ -122,6 +122,6 @@ def lstat(self) -> fsutil.stat_result: # JFFS2 block size is a function of the "erase size" of the underlying flash device. # Linux stat reports the default block size, which is defined as 4k in libc. st_info.st_blksize = 4096 - st_info.st_blocks = (node.isize + 511) // 512 if node.isize else 0 + st_info.st_blocks = (node.isize + 511) // 512 if self.is_file() else 0 return st_info diff --git a/tests/filesystems/test_jffs2.py b/tests/filesystems/test_jffs2.py index fee7845a5..c3fbc90f9 100644 --- a/tests/filesystems/test_jffs2.py +++ b/tests/filesystems/test_jffs2.py @@ -1,6 +1,7 @@ from datetime import datetime from typing import Iterator from unittest.mock import Mock, patch + import pytest from dissect.target.filesystems.jffs import JFFSFilesystem, JFFSFilesystemEntry