I am working on small ext2 filesystem image manipulation tool (like listing directories, adding and extracting files without the need to mount it).
I've just came into a problem with Unix timestamp fields. They are all 32 bit in ext filesystems. As we know, 32 bit Unix timestamps won't work after year 2038 anymore. Most software can easily deal with this problem by just changing definition of time_t to 64 bit. But it is not that easy for filesystems. They need to be compatible with existing implementations yet they need to be updated from time to time. How exactly ext filesystems do that? Particularly fields like s_mtime
, s_wtime
, s_lastcheck
, i_atime
, i_ctime
, i_mtime
and i_dtime
.
If you look at ext4's inode structure, you'll see:
struct ext4_inode {
...
__le32 i_ctime; /* Inode Change time */
...
__le32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
...
};
You won't find i_ctime_extra
being used (*sigh*). Instead, you'll find:
#define EXT4_INODE_GET_XTIME(xtime, inode, raw_inode) \
do { \
(inode)->xtime.tv_sec = (signed)le32_to_cpu((raw_inode)->xtime); \
if (EXT4_FITS_IN_INODE(raw_inode, EXT4_I(inode), xtime ## _extra)) { \
ext4_decode_extra_time(&(inode)->xtime, \
raw_inode->xtime ## _extra); \
} \
else \
(inode)->xtime.tv_nsec = 0; \
} while (0)
#define EXT4_EINODE_GET_XTIME(xtime, einode, raw_inode) \
do { \
if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime)) \
(einode)->xtime.tv_sec = \
(signed)le32_to_cpu((raw_inode)->xtime); \
else \
(einode)->xtime.tv_sec = 0; \
if (EXT4_FITS_IN_INODE(raw_inode, einode, xtime ## _extra)) \
ext4_decode_extra_time(&(einode)->xtime, \
raw_inode->xtime ## _extra); \
else \
(einode)->xtime.tv_nsec = 0; \
} while (0)
And if you look at usages, you'll see that in-memory, a 64 bit integer is used, the separation only exists on disk.