Skip to content

Commit

Permalink
Add blksize, nblocks, and birthtime_ns to stats (#917)
Browse files Browse the repository at this point in the history
  • Loading branch information
twiggler authored Oct 31, 2024
1 parent c9b4aa1 commit 041d41d
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 0 deletions.
7 changes: 7 additions & 0 deletions dissect/target/filesystems/ffs.py
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,12 @@ def lstat(self) -> fsutil.stat_result:
]
)

# Note: stat on linux always returns the default block size of 4096
# We are returning the actual block size of the filesystem, as on BSD
st_info.st_blksize = self.fs.ffs.block_size
# Note: st_blocks * 512 can be lower than st_blksize because FFS employs fragments
st_info.st_blocks = self.entry.nblocks

# Set the nanosecond resolution separately
st_info.st_atime_ns = self.entry.atime_ns
st_info.st_mtime_ns = self.entry.mtime_ns
Expand All @@ -134,5 +140,6 @@ def lstat(self) -> fsutil.stat_result:
# FFS2 has a birth time, FFS1 does not
if btime := self.entry.btime:
st_info.st_birthtime = btime.timestamp()
st_info.st_birthtime_ns = self.entry.btime_ns

return st_info
67 changes: 67 additions & 0 deletions tests/filesystems/test_ffs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from datetime import datetime
from typing import Iterator
from unittest.mock import Mock, patch

import pytest

from dissect.target.filesystems.ffs import FfsFilesystem, FfsFilesystemEntry

NANOSECONDS_IN_SECOND = 1_000_000_000


@pytest.fixture
def ffs_fs() -> Iterator[FfsFilesystem]:
with patch("dissect.ffs.ffs.FFS"):
ffs_fs = FfsFilesystem(Mock())
ffs_fs.ffs.block_size = 32 * 1024
yield ffs_fs


@pytest.fixture
def ffs_fs_entry(ffs_fs: FfsFilesystem) -> Iterator[FfsFilesystemEntry]:
atime = datetime(2024, 10, 1, 12, 0, 0)
mtime = datetime(2024, 10, 2, 12, 0, 0)
ctime = datetime(2024, 10, 3, 12, 0, 0)
btime = datetime(2024, 10, 4, 12, 0, 0)

raw_inode = Mock(di_uid=1000, di_nlink=1, di_guid=999, di_size=165002)
inode = Mock(
mode=0o100664,
inum=4,
inode=raw_inode,
nblocks=323,
atime=atime,
atime_ns=atime.timestamp() * NANOSECONDS_IN_SECOND,
mtime=mtime,
mtime_ns=mtime.timestamp() * NANOSECONDS_IN_SECOND,
ctime=ctime,
ctime_ns=ctime.timestamp() * NANOSECONDS_IN_SECOND,
btime=btime,
btime_ns=btime.timestamp() * NANOSECONDS_IN_SECOND,
is_file=lambda: True,
is_dir=lambda: False,
is_symlink=lambda: False,
)

entry = FfsFilesystemEntry(ffs_fs, "/some_file", inode)
yield entry


def test_jffs2_stat(ffs_fs_entry: FfsFilesystemEntry) -> None:
stat = ffs_fs_entry.stat()

entry = ffs_fs_entry.entry
assert stat.st_mode == entry.mode
assert stat.st_ino == entry.inum
assert stat.st_dev == id(ffs_fs_entry.fs)
assert stat.st_nlink == entry.inode.di_nlink
assert stat.st_uid == entry.inode.di_uid
assert stat.st_gid == entry.inode.di_gid
assert stat.st_size == entry.inode.di_size
assert stat.st_atime == entry.atime.timestamp()
assert stat.st_mtime == entry.mtime.timestamp()
assert stat.st_ctime == entry.ctime.timestamp()
assert stat.st_birthtime == entry.btime.timestamp()
assert stat.st_birthtime_ns == entry.btime_ns
assert stat.st_blksize == 32 * 1024
assert stat.st_blocks == 323

0 comments on commit 041d41d

Please sign in to comment.