Repository: SerenityOS/serenity
File: Kernel/FileSystem/Ext2FS/Inode.cpp (C++)

Code before:
u64 Ext2FSInode::size() const
{
    if (Kernel::is_regular_file(m_raw_inode.i_mode) && ((u32)fs().get_features_readonly() & (u32)Ext2FS::FeaturesReadOnly::FileSize64bits))
        return static_cast<u64>(m_raw_inode.i_dir_acl) << 32 | m_raw_inode.i_size;
    return m_raw_inode.i_size;
}

InodeMetadata Ext2FSInode::metadata() const
{
    MutexLocker locker(m_inode_lock);
    InodeMetadata metadata;
    metadata.inode = identifier();
    metadata.size = size();
    metadata.mode = m_raw_inode.i_mode;
    metadata.uid = inode_uid(m_raw_inode);
    metadata.gid = inode_gid(m_raw_inode);
    metadata.link_count = m_raw_inode.i_links_count;

    auto decode_time_with_extra = [](u32 const& time, u32 const& time_extra) {
        time_t seconds = decode_seconds_with_extra(time, time_extra);
        u32 nanoseconds = decode_nanoseconds_from_extra(time_extra);
        return UnixDateTime::from_unix_timespec({ .tv_sec = seconds, .tv_nsec = nanoseconds });
    };

    u64 usable_size = fs().usable_inode_size(m_raw_inode);
    if (__builtin_offsetof(ext2_inode_large, i_atime_extra) + sizeof(m_raw_inode.i_atime_extra) <= usable_size)
        metadata.atime = decode_time_with_extra(m_raw_inode.i_atime, m_raw_inode.i_atime_extra);
    else
        metadata.atime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_atime));

    if (__builtin_offsetof(ext2_inode_large, i_mtime_extra) + sizeof(m_raw_inode.i_mtime_extra) <= usable_size)
        metadata.mtime = decode_time_with_extra(m_raw_inode.i_mtime, m_raw_inode.i_mtime_extra);
    else
        metadata.mtime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_mtime));

    // NOTE: There's no i_dtime_extra, so we use i_ctime_extra to approximate the right epoch for metadata.dtime.
    if (__builtin_offsetof(ext2_inode_large, i_ctime_extra) + sizeof(m_raw_inode.i_ctime_extra) <= usable_size) {
        time_t ctime_seconds = decode_seconds_with_extra(m_raw_inode.i_ctime, m_raw_inode.i_ctime_extra);
        u32 ctime_nanoseconds = decode_nanoseconds_from_extra(m_raw_inode.i_ctime_extra);

        metadata.ctime = UnixDateTime::from_unix_timespec({ .tv_sec = ctime_seconds, .tv_nsec = ctime_nanoseconds });
        metadata.dtime = UnixDateTime::from_seconds_since_epoch(decode_seconds_with_extra(m_raw_inode.i_dtime, m_raw_inode.i_ctime_extra));
    } else {
        metadata.ctime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_ctime));
        metadata.dtime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_dtime));
    }

    metadata.block_size = fs().logical_block_size();
    metadata.block_count = m_raw_inode.i_blocks;

    if (Kernel::is_character_device(m_raw_inode.i_mode) || Kernel::is_block_device(m_raw_inode.i_mode)) {

Review comment (suggestion):
Anything that includes `<Kernel/Library/MiniStdLib.h>` should be able to use `offsetof` instead of having to use the "ugly" `__builtin_offsetof` builtin. (I don't know why we currently use `__builtin_offsetof` in so many places)

Code after:
u64 Ext2FSInode::size() const
{
    if (Kernel::is_regular_file(m_raw_inode.i_mode) && ((u32)fs().get_features_readonly() & (u32)Ext2FS::FeaturesReadOnly::FileSize64bits))
        return static_cast<u64>(m_raw_inode.i_dir_acl) << 32 | m_raw_inode.i_size;
    return m_raw_inode.i_size;
}

InodeMetadata Ext2FSInode::metadata() const
{
    MutexLocker locker(m_inode_lock);
    InodeMetadata metadata;
    metadata.inode = identifier();
    metadata.size = size();
    metadata.mode = m_raw_inode.i_mode;
    metadata.uid = inode_uid(m_raw_inode);
    metadata.gid = inode_gid(m_raw_inode);
    metadata.link_count = m_raw_inode.i_links_count;

    auto decode_time_with_extra = [](u32 const& time, u32 const& time_extra) {
        time_t seconds = decode_seconds_with_extra(time, time_extra);
        u32 nanoseconds = decode_nanoseconds_from_extra(time_extra);
        return UnixDateTime::from_unix_timespec({ .tv_sec = seconds, .tv_nsec = nanoseconds });
    };

    u64 usable_size = fs().usable_inode_size(m_raw_inode);
    if (offsetof(ext2_inode_large, i_atime_extra) + sizeof(m_raw_inode.i_atime_extra) <= usable_size)
        metadata.atime = decode_time_with_extra(m_raw_inode.i_atime, m_raw_inode.i_atime_extra);
    else
        metadata.atime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_atime));

    if (offsetof(ext2_inode_large, i_mtime_extra) + sizeof(m_raw_inode.i_mtime_extra) <= usable_size)
        metadata.mtime = decode_time_with_extra(m_raw_inode.i_mtime, m_raw_inode.i_mtime_extra);
    else
        metadata.mtime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_mtime));

    // NOTE: There's no i_dtime_extra, so we use i_ctime_extra to approximate the right epoch for metadata.dtime.
    if (offsetof(ext2_inode_large, i_ctime_extra) + sizeof(m_raw_inode.i_ctime_extra) <= usable_size) {
        time_t ctime_seconds = decode_seconds_with_extra(m_raw_inode.i_ctime, m_raw_inode.i_ctime_extra);
        u32 ctime_nanoseconds = decode_nanoseconds_from_extra(m_raw_inode.i_ctime_extra);

        metadata.ctime = UnixDateTime::from_unix_timespec({ .tv_sec = ctime_seconds, .tv_nsec = ctime_nanoseconds });
        metadata.dtime = UnixDateTime::from_seconds_since_epoch(decode_seconds_with_extra(m_raw_inode.i_dtime, m_raw_inode.i_ctime_extra));
    } else {
        metadata.ctime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_ctime));
        metadata.dtime = UnixDateTime::from_seconds_since_epoch(static_cast<i32>(m_raw_inode.i_dtime));
    }

    metadata.block_size = fs().logical_block_size();
    metadata.block_count = m_raw_inode.i_blocks;

    if (Kernel::is_character_device(m_raw_inode.i_mode) || Kernel::is_block_device(m_raw_inode.i_mode)) {