diff --git a/sys/fs/ext2fs/ext2_inode_cnv.c b/sys/fs/ext2fs/ext2_inode_cnv.c --- a/sys/fs/ext2fs/ext2_inode_cnv.c +++ b/sys/fs/ext2fs/ext2_inode_cnv.c @@ -94,7 +94,24 @@ } #endif /* EXT2FS_PRINT_EXTENTS */ -#define XTIME_TO_NSEC(x) ((le32toh(x) & EXT3_NSEC_MASK) >> 2) +static void +ext2_decode_extra_time(ext_time_t *sec, int32_t *nsec, uint32_t extra) +{ + if (extra & htole32(EXT3_EPOCH_MASK)) + *sec += (uint64_t)(le32toh(extra) & EXT3_EPOCH_MASK) << 32; + + *nsec = (le32toh(extra) & EXT3_NSEC_MASK) >> EXT3_EPOCH_BITS; +} + +static uint32_t +ext2_encode_extra_time(int64_t sec, int32_t nsec) +{ + uint32_t extra; + + extra = ((sec - (int32_t)sec) >> 32) & EXT3_EPOCH_MASK; + + return (htole32(extra | (nsec << EXT3_EPOCH_BITS))); +} /* * raw ext2 inode LE to host inode conversion @@ -141,15 +158,19 @@ ip->i_size = le32toh(ei->e2di_size); if (S_ISREG(ip->i_mode)) ip->i_size |= (uint64_t)le32toh(ei->e2di_size_high) << 32; - ip->i_atime = le32toh(ei->e2di_atime); - ip->i_mtime = le32toh(ei->e2di_mtime); - ip->i_ctime = le32toh(ei->e2di_ctime); + ip->i_atime = (signed)le32toh(ei->e2di_atime); + ip->i_mtime = (signed)le32toh(ei->e2di_mtime); + ip->i_ctime = (signed)le32toh(ei->e2di_ctime); if (E2DI_HAS_XTIME(ip)) { - ip->i_atimensec = XTIME_TO_NSEC(ei->e2di_atime_extra); - ip->i_mtimensec = XTIME_TO_NSEC(ei->e2di_mtime_extra); - ip->i_ctimensec = XTIME_TO_NSEC(ei->e2di_ctime_extra); - ip->i_birthtime = le32toh(ei->e2di_crtime); - ip->i_birthnsec = XTIME_TO_NSEC(ei->e2di_crtime_extra); + ext2_decode_extra_time(&ip->i_atime, &ip->i_atimensec, + ei->e2di_atime_extra); + ext2_decode_extra_time(&ip->i_mtime, &ip->i_mtimensec, + ei->e2di_mtime_extra); + ext2_decode_extra_time(&ip->i_ctime, &ip->i_ctimensec, + ei->e2di_ctime_extra); + ip->i_birthtime = (signed)le32toh(ei->e2di_crtime); + ext2_decode_extra_time(&ip->i_birthtime, &ip->i_birthnsec, + ei->e2di_crtime_extra); } ip->i_flags = 0; ei_flags_host = le32toh(ei->e2di_flags); @@ -185,8 +206,6 @@ return (ext2_ei_csum_verify(ip, ei)); } -#define NSEC_TO_XTIME(t) (htole32((t << 2) & EXT3_NSEC_MASK)) - /* * inode to raw ext2 LE inode conversion */ @@ -212,11 +231,16 @@ ei->e2di_dtime = htole32(le16toh(ei->e2di_nlink) ? 0 : le32toh(ei->e2di_mtime)); if (E2DI_HAS_XTIME(ip)) { - ei->e2di_ctime_extra = NSEC_TO_XTIME(ip->i_ctimensec); - ei->e2di_mtime_extra = NSEC_TO_XTIME(ip->i_mtimensec); - ei->e2di_atime_extra = NSEC_TO_XTIME(ip->i_atimensec); + ei->e2di_ctime_extra = ext2_encode_extra_time(ip->i_ctime, + ip->i_ctimensec); + ei->e2di_mtime_extra = ext2_encode_extra_time(ip->i_mtime, + ip->i_mtimensec); + ei->e2di_atime_extra = ext2_encode_extra_time(ip->i_atime, + ip->i_atimensec); ei->e2di_crtime = htole32(ip->i_birthtime); - ei->e2di_crtime_extra = NSEC_TO_XTIME(ip->i_birthnsec); + ei->e2di_crtime_extra = ext2_encode_extra_time(ip->i_birthtime, + ip->i_birthnsec); + } /* Keep these in host endian for a while since they change a lot */ ei->e2di_flags = 0; diff --git a/sys/fs/ext2fs/inode.h b/sys/fs/ext2fs/inode.h --- a/sys/fs/ext2fs/inode.h +++ b/sys/fs/ext2fs/inode.h @@ -62,6 +62,7 @@ typedef uint32_t e2fs_daddr_t; typedef int64_t e2fs_lbn_t; typedef int64_t e4fs_daddr_t; +typedef int64_t ext_time_t; /* * The inode is used to describe each active (or recently active) file in the @@ -99,10 +100,10 @@ uint32_t i_gid; /* File group. */ uint64_t i_size; /* File byte count. */ uint64_t i_blocks; /* Blocks actually held. */ - int32_t i_atime; /* Last access time. */ - int32_t i_mtime; /* Last modified time. */ - int32_t i_ctime; /* Last inode change time. */ - int32_t i_birthtime; /* Inode creation time. */ + ext_time_t i_atime; /* Last access time. */ + ext_time_t i_mtime; /* Last modified time. */ + ext_time_t i_ctime; /* Last inode change time. */ + ext_time_t i_birthtime; /* Inode creation time. */ int32_t i_mtimensec; /* Last modified time. */ int32_t i_atimensec; /* Last access time. */ int32_t i_ctimensec; /* Last inode change time. */