[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <EB4554C6-B186-4180-99BF-EA966FCB3D0A@dilger.ca>
Date: Mon, 1 Apr 2024 15:29:56 -0600
From: Andreas Dilger <adilger@...ger.ca>
To: tytso@....edu
Cc: linux-ext4@...r.kernel.org
Subject: Re: [PATCH] misc: add 2038 timestamp support
On Sep 26, 2023, at 11:40 PM, Andreas Dilger <adilger@...ger.ca> wrote:
>
> The ext4 kernel code implemented support for s_mtime_hi,
> s_wtime_hi, and related timestamp fields to avoid timestamp
> overflow in 2038, but similar handling is not in e2fsprogs.
Hi Ted,
I'm just going through some of my branches in e2fsprogs. and I
see this one is marked as "accepted" in Patchwork, but has not
been landed to a branch (maint, master, next). Not that it is
urgent, but you know how people keep old e2fsprogs around for
a long time, and 14 years is no longer that the far in the future.
Cheers, Andreas
>
> Add helper macros for the superblock _hi timestamp fields
> ext2fs_super_tstamp_get() and ext2fs_super_tstamp_set().
>
> Add helper macro for inode _extra timestamp fields
> ext2fs_inode_xtime_get() and ext2fs_inode_xtime_set().
>
> Add helper macro ext2fs_actual_inode_size() to avoid open
> coding the i_extra_isize check in multiple places.
>
> Remove inode_time_to_string() since this is unused once callers
> change to time_to_string(ext2fs_inode_xtime_get()) directly.
>
> Fix inode_includes() macro to properly wrap "inode" parameter,
> and rename to ext2fs_inode_includes() to avoid potential name
> clashes. Use this to check inode field inclusion in debugfs
> instead of bare constants for inode field offsets.
>
> Use these interfaces to access timestamps in debugfs, e2fsck,
> libext2fs, fuse2fs, tune2fs, and e2undo.
>
> Signed-off-by: Andreas Dilger <adilger@...ger.ca>
> ---
> debugfs/debugfs.c | 69 +++++++++++++++++++++++------------------
> debugfs/debugfs.h | 1 -
> debugfs/journal.c | 7 +++--
> debugfs/set_fields.c | 32 ++++++++++++-------
> debugfs/util.c | 8 -----
> e2fsck/message.c | 2 +-
> e2fsck/pass1.c | 16 +++++-----
> e2fsck/pass3.c | 8 +++--
> e2fsck/super.c | 16 +++++-----
> e2fsck/unix.c | 2 +-
> lib/e2p/ls.c | 28 +++++++----------
> lib/ext2fs/bb_inode.c | 11 ++++---
> lib/ext2fs/closefs.c | 2 +-
> lib/ext2fs/ext2_fs.h | 6 ++--
> lib/ext2fs/ext2fs.h | 52 +++++++++++++++++++++++++++++++
> lib/ext2fs/initialize.c | 3 +-
> lib/ext2fs/inode.c | 16 +++++-----
> lib/ext2fs/mkjournal.c | 5 ++-
> lib/ext2fs/orphan.c | 7 +++--
> lib/ext2fs/res_gdt.c | 5 ++-
> lib/ext2fs/swapfs.c | 16 +++++-----
> lib/support/mkquota.c | 2 +-
> lib/support/plausible.c | 9 ++----
> lib/support/quotaio.c | 7 +++--
> misc/create_inode.c | 20 +++++++-----
> misc/e2undo.c | 6 ++--
> misc/findsuper.c | 7 ++---
> misc/fuse2fs.c | 8 ++---
> misc/tune2fs.c | 6 ++--
> 29 files changed, 231 insertions(+), 146 deletions(-)
>
> diff --git a/debugfs/debugfs.c b/debugfs/debugfs.c
> index 9b6321dc..96551173 100644
> --- a/debugfs/debugfs.c
> +++ b/debugfs/debugfs.c
> @@ -831,11 +831,13 @@ void internal_dump_inode(FILE *out, const char *prefix,
> char frag, fsize;
> int os = current_fs->super->s_creator_os;
> struct ext2_inode_large *large_inode;
> - int is_large_inode = 0;
> + size_t inode_size;
>
> - if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
> - is_large_inode = 1;
> large_inode = (struct ext2_inode_large *) inode;
> + if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
> + inode_size = ext2fs_inode_actual_size(large_inode);
> + else
> + inode_size = EXT2_GOOD_OLD_INODE_SIZE;
>
> if (LINUX_S_ISDIR(inode->i_mode)) i_type = "directory";
> else if (LINUX_S_ISREG(inode->i_mode)) i_type = "regular";
> @@ -848,7 +850,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
> fprintf(out, "%sInode: %u Type: %s ", prefix, inode_num, i_type);
> fprintf(out, "%sMode: 0%03o Flags: 0x%x\n",
> prefix, inode->i_mode & 07777, inode->i_flags);
> - if (is_large_inode && large_inode->i_extra_isize >= 24) {
> + if (ext2fs_inode_includes(inode_size, i_version_hi)) {
> fprintf(out, "%sGeneration: %u Version: 0x%08x:%08x\n",
> prefix, inode->i_generation, large_inode->i_version_hi,
> inode->osd1.linux1.l_i_version);
> @@ -858,7 +860,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
> }
> fprintf(out, "%sUser: %5d Group: %5d",
> prefix, inode_uid(*inode), inode_gid(*inode));
> - if (is_large_inode && large_inode->i_extra_isize >= 32)
> + if (ext2fs_inode_includes(inode_size, i_projid))
> fprintf(out, " Project: %5d", large_inode->i_projid);
> fputs(" Size: ", out);
> if (LINUX_S_ISREG(inode->i_mode) || LINUX_S_ISDIR(inode->i_mode))
> @@ -895,39 +897,48 @@ void internal_dump_inode(FILE *out, const char *prefix,
> }
> fprintf(out, "%sFragment: Address: %u Number: %u Size: %u\n",
> prefix, inode->i_faddr, frag, fsize);
> - if (is_large_inode && large_inode->i_extra_isize >= 24) {
> + if (ext2fs_inode_includes(inode_size, i_ctime_extra))
> fprintf(out, "%s ctime: 0x%08x:%08x -- %s", prefix,
> inode->i_ctime, large_inode->i_ctime_extra,
> - inode_time_to_string(inode->i_ctime,
> - large_inode->i_ctime_extra));
> + time_to_string(ext2fs_inode_xtime_get(inode, i_ctime)));
> + else
> + fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime,
> + time_to_string((__s32) inode->i_ctime));
> + if (ext2fs_inode_includes(inode_size, i_atime_extra))
> fprintf(out, "%s atime: 0x%08x:%08x -- %s", prefix,
> inode->i_atime, large_inode->i_atime_extra,
> - inode_time_to_string(inode->i_atime,
> - large_inode->i_atime_extra));
> + time_to_string(ext2fs_inode_xtime_get(inode, i_atime)));
> + else
> + fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime,
> + time_to_string((__s32) inode->i_atime));
> + if (ext2fs_inode_includes(inode_size, i_mtime_extra))
> fprintf(out, "%s mtime: 0x%08x:%08x -- %s", prefix,
> inode->i_mtime, large_inode->i_mtime_extra,
> - inode_time_to_string(inode->i_mtime,
> - large_inode->i_mtime_extra));
> + time_to_string(ext2fs_inode_xtime_get(inode, i_mtime)));
> + else
> + fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime,
> + time_to_string((__s32) inode->i_mtime));
> + if (ext2fs_inode_includes(inode_size, i_crtime_extra))
> fprintf(out, "%scrtime: 0x%08x:%08x -- %s", prefix,
> large_inode->i_crtime, large_inode->i_crtime_extra,
> - inode_time_to_string(large_inode->i_crtime,
> - large_inode->i_crtime_extra));
> - if (inode->i_dtime)
> + time_to_string(ext2fs_inode_xtime_get(large_inode,
> + i_crtime)));
> + if (inode->i_dtime) {
> + if (ext2fs_inode_includes(inode_size, i_ctime_extra)) {
> + time_t tm;
> +
> + /* dtime doesn't have its own i_dtime_extra field, so
> + * approximate this with i_ctime_extra instead. */
> + tm = __decode_extra_sec(inode->i_dtime,
> + large_inode->i_ctime_extra);
> fprintf(out, "%s dtime: 0x%08x:(%08x) -- %s", prefix,
> - large_inode->i_dtime, large_inode->i_ctime_extra,
> - inode_time_to_string(inode->i_dtime,
> - large_inode->i_ctime_extra));
> - } else {
> - fprintf(out, "%sctime: 0x%08x -- %s", prefix, inode->i_ctime,
> - time_to_string((__s32) inode->i_ctime));
> - fprintf(out, "%satime: 0x%08x -- %s", prefix, inode->i_atime,
> - time_to_string((__s32) inode->i_atime));
> - fprintf(out, "%smtime: 0x%08x -- %s", prefix, inode->i_mtime,
> - time_to_string((__s32) inode->i_mtime));
> - if (inode->i_dtime)
> + inode->i_dtime, large_inode->i_ctime_extra,
> + time_to_string(tm));
> + } else {
> fprintf(out, "%sdtime: 0x%08x -- %s", prefix,
> inode->i_dtime,
> time_to_string((__s32) inode->i_dtime));
> + }
> }
> if (EXT2_INODE_SIZE(current_fs->super) > EXT2_GOOD_OLD_INODE_SIZE)
> internal_dump_inode_extra(out, prefix, inode_num,
> @@ -935,11 +946,7 @@ void internal_dump_inode(FILE *out, const char *prefix,
> dump_inode_attributes(out, inode_num);
> if (ext2fs_has_feature_metadata_csum(current_fs->super)) {
> __u32 crc = inode->i_checksum_lo;
> - if (is_large_inode &&
> - large_inode->i_extra_isize >=
> - (offsetof(struct ext2_inode_large,
> - i_checksum_hi) -
> - EXT2_GOOD_OLD_INODE_SIZE))
> + if (ext2fs_inode_includes(inode_size, i_checksum_hi))
> crc |= ((__u32)large_inode->i_checksum_hi) << 16;
> fprintf(out, "Inode checksum: 0x%08x\n", crc);
> }
> diff --git a/debugfs/debugfs.h b/debugfs/debugfs.h
> index 39bc0247..85c82b95 100644
> --- a/debugfs/debugfs.h
> +++ b/debugfs/debugfs.h
> @@ -36,7 +36,6 @@ extern int check_fs_not_open(char *name);
> extern int check_fs_read_write(char *name);
> extern int check_fs_bitmaps(char *name);
> extern ext2_ino_t string_to_inode(char *str);
> -extern char *inode_time_to_string(__u32 xtime, __u32 xtime_extra);
> extern char *time_to_string(__s64);
> extern __s64 string_to_time(const char *);
> extern unsigned long parse_ulong(const char *str, const char *cmd,
> diff --git a/debugfs/journal.c b/debugfs/journal.c
> index 5bac0d3b..454fbcfc 100644
> --- a/debugfs/journal.c
> +++ b/debugfs/journal.c
> @@ -245,6 +245,8 @@ void wait_on_buffer(struct buffer_head *bh)
>
> static void ext2fs_clear_recover(ext2_filsys fs, int error)
> {
> + time_t s_mtime;
> +
> ext2fs_clear_feature_journal_needs_recovery(fs->super);
>
> /* if we had an error doing journal recovery, we need a full fsck */
> @@ -254,8 +256,9 @@ static void ext2fs_clear_recover(ext2_filsys fs, int error)
> * If we replayed the journal by definition the file system
> * was mounted since the last time it was checked
> */
> - if (fs->super->s_lastcheck >= fs->super->s_mtime)
> - fs->super->s_lastcheck = fs->super->s_mtime - 1;
> + s_mtime = ext2fs_get_tstamp(fs->super, s_mtime);
> + if (ext2fs_get_tstamp(fs->super, s_lastcheck) >= s_mtime)
> + ext2fs_set_tstamp(fs->super, s_lastcheck, s_mtime - 1);
> ext2fs_mark_super_dirty(fs);
> }
>
> diff --git a/debugfs/set_fields.c b/debugfs/set_fields.c
> index f916deab..ef137b0f 100644
> --- a/debugfs/set_fields.c
> +++ b/debugfs/set_fields.c
> @@ -99,15 +99,16 @@ static struct field_set_info super_fields[] = {
> { "blocks_per_group", &set_sb.s_blocks_per_group, NULL, 4, parse_uint },
> { "clusters_per_group", &set_sb.s_clusters_per_group, NULL, 4, parse_uint },
> { "inodes_per_group", &set_sb.s_inodes_per_group, NULL, 4, parse_uint },
> - { "mtime", &set_sb.s_mtime, NULL, 4, parse_time },
> - { "wtime", &set_sb.s_wtime, NULL, 4, parse_time },
> + { "mtime", &set_sb.s_mtime, &set_sb.s_mtime_hi, 5, parse_time },
> + { "wtime", &set_sb.s_wtime, &set_sb.s_wtime_hi, 5, parse_time },
> { "mnt_count", &set_sb.s_mnt_count, NULL, 2, parse_uint },
> { "max_mnt_count", &set_sb.s_max_mnt_count, NULL, 2, parse_int },
> /* s_magic */
> { "state", &set_sb.s_state, NULL, 2, parse_uint },
> { "errors", &set_sb.s_errors, NULL, 2, parse_uint },
> { "minor_rev_level", &set_sb.s_minor_rev_level, NULL, 2, parse_uint },
> - { "lastcheck", &set_sb.s_lastcheck, NULL, 4, parse_time },
> + { "lastcheck", &set_sb.s_lastcheck, &set_sb.s_lastcheck_hi, 5,
> + parse_time },
> { "checkinterval", &set_sb.s_checkinterval, NULL, 4, parse_uint },
> { "creator_os", &set_sb.s_creator_os, NULL, 4, parse_uint },
> { "rev_level", &set_sb.s_rev_level, NULL, 4, parse_uint },
> @@ -139,7 +140,8 @@ static struct field_set_info super_fields[] = {
> { "desc_size", &set_sb.s_desc_size, NULL, 2, parse_uint },
> { "default_mount_opts", &set_sb.s_default_mount_opts, NULL, 4, parse_uint },
> { "first_meta_bg", &set_sb.s_first_meta_bg, NULL, 4, parse_uint },
> - { "mkfs_time", &set_sb.s_mkfs_time, NULL, 4, parse_time },
> + { "mkfs_time", &set_sb.s_mkfs_time, &set_sb.s_mkfs_time_hi, 5,
> + parse_time },
> { "jnl_blocks", &set_sb.s_jnl_blocks[0], NULL, 4, parse_uint, FLAG_ARRAY,
> 17 },
> { "min_extra_isize", &set_sb.s_min_extra_isize, NULL, 2, parse_uint },
> @@ -167,12 +169,14 @@ static struct field_set_info super_fields[] = {
> { "checksum_type", &set_sb.s_checksum_type, NULL, 1, parse_uint },
> { "encryption_level", &set_sb.s_encryption_level, NULL, 1, parse_uint },
> { "error_count", &set_sb.s_error_count, NULL, 4, parse_uint },
> - { "first_error_time", &set_sb.s_first_error_time, NULL, 4, parse_time },
> + { "first_error_time", &set_sb.s_first_error_time,
> + &set_sb.s_first_error_time_hi, 5, parse_time },
> { "first_error_ino", &set_sb.s_first_error_ino, NULL, 4, parse_uint },
> { "first_error_block", &set_sb.s_first_error_block, NULL, 8, parse_uint },
> { "first_error_func", &set_sb.s_first_error_func, NULL, 32, parse_string },
> { "first_error_line", &set_sb.s_first_error_line, NULL, 4, parse_uint },
> - { "last_error_time", &set_sb.s_last_error_time, NULL, 4, parse_time },
> + { "last_error_time", &set_sb.s_last_error_time,
> + &set_sb.s_last_error_time_hi, 5, parse_time },
> { "last_error_ino", &set_sb.s_last_error_ino, NULL, 4, parse_uint },
> { "last_error_block", &set_sb.s_last_error_block, NULL, 8, parse_uint },
> { "last_error_func", &set_sb.s_last_error_func, NULL, 32, parse_string },
> @@ -441,6 +445,9 @@ static struct field_set_info *find_field(struct field_set_info *fields,
> * Note: info->size == 6 is special; this means a base size 4 bytes,
> * and secondary (high) size of 2 bytes. This is needed for the
> * special case of i_blocks_high and i_file_acl_high.
> + *
> + * Similarly, info->size == 5 is for superblock timestamps, which have
> + * a 4-byte primary field and a 1-byte _hi field.
> */
> static errcode_t parse_uint(struct field_set_info *info, char *field,
> char *arg)
> @@ -449,7 +456,7 @@ static errcode_t parse_uint(struct field_set_info *info, char *field,
> int suffix = check_suffix(field);
> char *tmp;
> void *field1 = info->ptr, *field2 = info->ptr2;
> - int size = (info->size == 6) ? 4 : info->size;
> + int size = (info->size == 6 || info->size == 5) ? 4 : info->size;
> union {
> __u64 *ptr64;
> __u32 *ptr32;
> @@ -477,7 +484,7 @@ static errcode_t parse_uint(struct field_set_info *info, char *field,
> }
> mask = ~0ULL >> ((8 - size) * 8);
> limit = ~0ULL >> ((8 - info->size) * 8);
> - if (field2 && info->size != 6)
> + if (field2 && (info->size != 6 || info->size != 5))
> limit = ~0ULL >> ((8 - info->size*2) * 8);
>
> if (num > limit) {
> @@ -504,13 +511,14 @@ static errcode_t parse_uint(struct field_set_info *info, char *field,
> return 0;
> n = (size == 8) ? 0 : (num >> (size*8));
> u.ptr8 = (__u8 *) field2;
> - if (info->size == 6)
> - size = 2;
> + if (info->size > size)
> + size = info->size - size;
> switch (size) {
> case 8:
> /* Should never get here */
> - fprintf(stderr, "64-bit field %s has a second 64-bit field\n"
> - "defined; BUG?!?\n", info->name);
> + fprintf(stderr,
> + "64-bit field %s has a second 64-bit field defined; BUG?!?\n",
> + info->name);
> *u.ptr64 = 0;
> break;
> case 4:
> diff --git a/debugfs/util.c b/debugfs/util.c
> index 9e880548..d3ef63c6 100644
> --- a/debugfs/util.c
> +++ b/debugfs/util.c
> @@ -191,14 +191,6 @@ int check_fs_bitmaps(char *name)
> return 0;
> }
>
> -char *inode_time_to_string(__u32 xtime, __u32 xtime_extra)
> -{
> - __s64 t = (__s32) xtime;
> -
> - t += (__s64) (xtime_extra & EXT4_EPOCH_MASK) << 32;
> - return time_to_string(t);
> -}
> -
> /*
> * This function takes a __s64 time value and converts it to a string,
> * using ctime
> diff --git a/e2fsck/message.c b/e2fsck/message.c
> index ba38038c..9c42b13f 100644
> --- a/e2fsck/message.c
> +++ b/e2fsck/message.c
> @@ -301,7 +301,7 @@ static _INLINE_ void expand_inode_expression(FILE *f, ext2_filsys fs, char ch,
> fprintf(f, "0%o", inode->i_mode);
> break;
> case 'M':
> - print_time(f, inode->i_mtime);
> + print_time(f, ext2fs_inode_xtime_get(inode, i_mtime));
> break;
> case 'F':
> fprintf(f, "%u", inode->i_faddr);
> diff --git a/e2fsck/pass1.c b/e2fsck/pass1.c
> index a341c72a..078bcb9b 100644
> --- a/e2fsck/pass1.c
> +++ b/e2fsck/pass1.c
> @@ -1181,6 +1181,7 @@ void e2fsck_pass1(e2fsck_t ctx)
> ext2_ino_t ino_threshold = 0;
> dgrp_t ra_group = 0;
> struct ea_quota ea_ibody_quota;
> + time_t tm;
>
> init_resource_track(&rtrack, ctx->fs->io);
> clear_problem_context(&pctx);
> @@ -1357,12 +1358,13 @@ void e2fsck_pass1(e2fsck_t ctx)
> if (ctx->progress && ((ctx->progress)(ctx, 1, 0,
> ctx->fs->group_desc_count)))
> goto endit;
> - if ((fs->super->s_wtime &&
> - fs->super->s_wtime < fs->super->s_inodes_count) ||
> - (fs->super->s_mtime &&
> - fs->super->s_mtime < fs->super->s_inodes_count) ||
> - (fs->super->s_mkfs_time &&
> - fs->super->s_mkfs_time < fs->super->s_inodes_count))
> +
> + if (((tm = ext2fs_get_tstamp(fs->super, s_wtime)) &&
> + tm < fs->super->s_inodes_count) ||
> + ((tm = ext2fs_get_tstamp(fs->super, s_mtime)) &&
> + tm < fs->super->s_inodes_count) ||
> + ((tm = ext2fs_get_tstamp(fs->super, s_mkfs_time)) &&
> + tm < fs->super->s_inodes_count))
> low_dtime_check = 0;
>
> if (ext2fs_has_feature_mmp(fs->super) &&
> @@ -2076,7 +2078,7 @@ void e2fsck_pass1(e2fsck_t ctx)
> if (!pctx.errcode) {
> e2fsck_read_inode(ctx, EXT2_RESIZE_INO, inode,
> "recreate inode");
> - inode->i_mtime = ctx->now;
> + ext2fs_inode_xtime_set(inode, i_mtime, ctx->now);
> e2fsck_write_inode(ctx, EXT2_RESIZE_INO, inode,
> "recreate inode");
> }
> diff --git a/e2fsck/pass3.c b/e2fsck/pass3.c
> index 16d243f6..ba794165 100644
> --- a/e2fsck/pass3.c
> +++ b/e2fsck/pass3.c
> @@ -212,7 +212,9 @@ skip_new_block:
> memset(&inode, 0, sizeof(inode));
> inode.i_mode = 040755;
> inode.i_size = fs->blocksize;
> - inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
> + ext2fs_inode_xtime_set(&inode, i_atime, ctx->now);
> + ext2fs_inode_xtime_set(&inode, i_ctime, ctx->now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, ctx->now);
> inode.i_links_count = 2;
> ext2fs_iblk_set(fs, iptr, 1);
> inode.i_block[0] = blk;
> @@ -528,7 +530,9 @@ skip_new_block:
> memset(&inode, 0, sizeof(inode));
> inode.i_mode = 040700;
> inode.i_size = fs->blocksize;
> - inode.i_atime = inode.i_ctime = inode.i_mtime = ctx->now;
> + ext2fs_inode_xtime_set(&inode, i_atime, ctx->now);
> + ext2fs_inode_xtime_set(&inode, i_ctime, ctx->now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, ctx->now);
> inode.i_links_count = 2;
> ext2fs_iblk_set(fs, EXT2_INODE(&inode), 1);
> inode.i_block[0] = blk;
> diff --git a/e2fsck/super.c b/e2fsck/super.c
> index be40dd8f..757a475d 100644
> --- a/e2fsck/super.c
> +++ b/e2fsck/super.c
> @@ -1320,25 +1320,25 @@ void check_super_block(e2fsck_t ctx)
> */
> if (((ctx->options & E2F_OPT_FORCE) || fs->super->s_checkinterval) &&
> !broken_system_clock && !(ctx->flags & E2F_FLAG_TIME_INSANE) &&
> - (fs->super->s_mtime > (__u32) ctx->now)) {
> - pctx.num = fs->super->s_mtime;
> + (ext2fs_get_tstamp(fs->super, s_mtime) > ctx->now)) {
> + pctx.num = ext2fs_get_tstamp(fs->super, s_mtime);
> problem = PR_0_FUTURE_SB_LAST_MOUNT;
> - if (fs->super->s_mtime <= (__u32) ctx->now + ctx->time_fudge)
> + if (pctx.num <= ctx->now + ctx->time_fudge)
> problem = PR_0_FUTURE_SB_LAST_MOUNT_FUDGED;
> if (fix_problem(ctx, problem, &pctx)) {
> - fs->super->s_mtime = ctx->now;
> + ext2fs_set_tstamp(fs->super, s_mtime, ctx->now);
> fs->flags |= EXT2_FLAG_DIRTY;
> }
> }
> if (((ctx->options & E2F_OPT_FORCE) || fs->super->s_checkinterval) &&
> !broken_system_clock && !(ctx->flags & E2F_FLAG_TIME_INSANE) &&
> - (fs->super->s_wtime > (__u32) ctx->now)) {
> - pctx.num = fs->super->s_wtime;
> + (ext2fs_get_tstamp(fs->super, s_wtime) > ctx->now)) {
> + pctx.num = ext2fs_get_tstamp(fs->super, s_wtime);
> problem = PR_0_FUTURE_SB_LAST_WRITE;
> - if (fs->super->s_wtime <= (__u32) ctx->now + ctx->time_fudge)
> + if (pctx.num <= ctx->now + ctx->time_fudge)
> problem = PR_0_FUTURE_SB_LAST_WRITE_FUDGED;
> if (fix_problem(ctx, problem, &pctx)) {
> - fs->super->s_wtime = ctx->now;
> + ext2fs_set_tstamp(fs->super, s_wtime, ctx->now);
> fs->flags |= EXT2_FLAG_DIRTY;
> }
> }
> diff --git a/e2fsck/unix.c b/e2fsck/unix.c
> index e5b672a2..bc6b518d 100644
> --- a/e2fsck/unix.c
> +++ b/e2fsck/unix.c
> @@ -2080,7 +2080,7 @@ cleanup:
> } else
> sb->s_state &= ~EXT2_VALID_FS;
> if (!(ctx->flags & E2F_FLAG_TIME_INSANE))
> - sb->s_lastcheck = ctx->now;
> + ext2fs_set_tstamp(sb, s_lastcheck, ctx->now);
> sb->s_mnt_count = 0;
> memset(((char *) sb) + EXT4_S_ERR_START, 0, EXT4_S_ERR_LEN);
> pctx.errcode = ext2fs_set_gdt_csum(ctx->fs);
> diff --git a/lib/e2p/ls.c b/lib/e2p/ls.c
> index 0b74aea2..081ef975 100644
> --- a/lib/e2p/ls.c
> +++ b/lib/e2p/ls.c
> @@ -313,27 +313,23 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
> if (sb->s_log_groups_per_flex)
> fprintf(f, "Flex block group size: %u\n",
> 1U << sb->s_log_groups_per_flex);
> - if (sb->s_mkfs_time) {
> - tm = sb->s_mkfs_time;
> + tm = ext2fs_get_tstamp(sb, s_mkfs_time);
> + if (tm)
> fprintf(f, "Filesystem created: %s", ctime(&tm));
> - }
> - tm = sb->s_mtime;
> - fprintf(f, "Last mount time: %s",
> - sb->s_mtime ? ctime(&tm) : "n/a\n");
> - tm = sb->s_wtime;
> + tm = ext2fs_get_tstamp(sb, s_mtime);
> + fprintf(f, "Last mount time: %s", tm ? ctime(&tm) : "n/a\n");
> + tm = ext2fs_get_tstamp(sb, s_wtime);
> fprintf(f, "Last write time: %s", ctime(&tm));
> fprintf(f, "Mount count: %u\n", sb->s_mnt_count);
> fprintf(f, "Maximum mount count: %d\n", sb->s_max_mnt_count);
> - tm = sb->s_lastcheck;
> + tm = ext2fs_get_tstamp(sb, s_lastcheck);
> fprintf(f, "Last checked: %s", ctime(&tm));
> fprintf(f, "Check interval: %u (%s)\n", sb->s_checkinterval,
> interval_string(sb->s_checkinterval));
> if (sb->s_checkinterval)
> {
> - time_t next;
> -
> - next = sb->s_lastcheck + sb->s_checkinterval;
> - fprintf(f, "Next check after: %s", ctime(&next));
> + tm += sb->s_checkinterval;
> + fprintf(f, "Next check after: %s", ctime(&tm));
> }
> #define POW2(x) ((__u64) 1 << (x))
> if (sb->s_kbytes_written) {
> @@ -419,8 +415,8 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
> if (sb->s_error_count)
> fprintf(f, "FS Error count: %u\n",
> sb->s_error_count);
> - if (sb->s_first_error_time) {
> - tm = sb->s_first_error_time;
> + tm = ext2fs_get_tstamp(sb, s_first_error_time);
> + if (tm) {
> fprintf(f, "First error time: %s", ctime(&tm));
> fprintf(f, "First error function: %.*s\n",
> EXT2_LEN_STR(sb->s_first_error_func));
> @@ -436,8 +432,8 @@ void list_super2(struct ext2_super_block * sb, FILE *f)
> fprintf(f, "First error err: %s\n",
> e2p_errcode2str(sb->s_first_error_errcode));
> }
> - if (sb->s_last_error_time) {
> - tm = sb->s_last_error_time;
> + tm = ext2fs_get_tstamp(sb, s_last_error_time);
> + if (tm) {
> fprintf(f, "Last error time: %s", ctime(&tm));
> fprintf(f, "Last error function: %.*s\n",
> EXT2_LEN_STR(sb->s_last_error_func));
> diff --git a/lib/ext2fs/bb_inode.c b/lib/ext2fs/bb_inode.c
> index 11f10ebc..927a4d41 100644
> --- a/lib/ext2fs/bb_inode.c
> +++ b/lib/ext2fs/bb_inode.c
> @@ -58,8 +58,9 @@ static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
> errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
> {
> errcode_t retval;
> - struct set_badblock_record rec;
> + struct set_badblock_record rec;
> struct ext2_inode inode;
> + time_t now;
>
> EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
>
> @@ -124,9 +125,11 @@ errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
> if (retval)
> goto cleanup;
>
> - inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0);
> - if (!inode.i_ctime)
> - inode.i_ctime = fs->now ? fs->now : time(0);
> + now = fs->now ? fs->now : time(0);
> + ext2fs_inode_xtime_set(&inode, i_atime, now);
> + if (!ext2fs_inode_xtime_get(&inode, i_ctime))
> + ext2fs_inode_xtime_set(&inode, i_ctime, now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, now);
> ext2fs_iblk_set(fs, &inode, rec.bad_block_count);
> retval = ext2fs_inode_size_set(fs, &inode,
> rec.bad_block_count * fs->blocksize);
> diff --git a/lib/ext2fs/closefs.c b/lib/ext2fs/closefs.c
> index 69cbdd8c..42bda1fa 100644
> --- a/lib/ext2fs/closefs.c
> +++ b/lib/ext2fs/closefs.c
> @@ -301,7 +301,7 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
> fs_state = fs->super->s_state;
> feature_incompat = fs->super->s_feature_incompat;
>
> - fs->super->s_wtime = fs->now ? fs->now : time(NULL);
> + ext2fs_set_tstamp(fs->super, s_wtime, fs->now ? fs->now : time(NULL));
> fs->super->s_block_group_nr = 0;
>
> /*
> diff --git a/lib/ext2fs/ext2_fs.h b/lib/ext2fs/ext2_fs.h
> index 0fc9c09a..586141f8 100644
> --- a/lib/ext2fs/ext2_fs.h
> +++ b/lib/ext2fs/ext2_fs.h
> @@ -512,9 +512,9 @@ struct ext2_inode_large {
>
> #define i_checksum_lo osd2.linux2.l_i_checksum_lo
>
> -#define inode_includes(size, field) \
> - (size >= (sizeof(((struct ext2_inode_large *)0)->field) + \
> - offsetof(struct ext2_inode_large, field)))
> +#define ext2fs_inode_includes(size, field) \
> + ((size) >= (sizeof(((struct ext2_inode_large *)0)->field) + \
> + offsetof(struct ext2_inode_large, field)))
>
> #if defined(__KERNEL__) || defined(__linux__)
> #define i_reserved1 osd1.linux1.l_i_reserved1
> diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h
> index 72c60d2b..8953817c 100644
> --- a/lib/ext2fs/ext2fs.h
> +++ b/lib/ext2fs/ext2fs.h
> @@ -579,6 +579,58 @@ typedef struct ext2_struct_inode_scan *ext2_inode_scan;
> */
> #define EXT2_I_SIZE(i) ((i)->i_size | ((__u64) (i)->i_size_high << 32))
>
> +static inline __u32 __encode_extra_time(time_t seconds, __u32 nsec)
> +{
> + __u32 extra = ((seconds - (__s32)seconds) >> 32) & EXT4_EPOCH_MASK;
> + return extra | (nsec << EXT4_EPOCH_BITS);
> +}
> +static inline time_t __decode_extra_sec(time_t seconds, __u32 extra)
> +{
> + if (extra & EXT4_EPOCH_MASK)
> + seconds += ((time_t)(extra & EXT4_EPOCH_MASK) << 32);
> + return seconds;
> +}
> +static inline __u32 __decode_extra_nsec(__u32 extra)
> +{
> + return (extra & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS;
> +}
> +#define ext2fs_inode_actual_size(inode) \
> + (EXT2_GOOD_OLD_INODE_SIZE + \
> + (sizeof(*inode) > EXT2_GOOD_OLD_INODE_SIZE ? \
> + ((struct ext2_inode_large *)(inode))->i_extra_isize : 0))
> +#define clamp(val, min, max) ((val) < (min) ? (min) : ((val) > (max) ? \
> + (max) : (val)))
> +#define ext2fs_inode_xtime_set(inode, field, sec) \
> +do { \
> + if (ext2fs_inode_includes(ext2fs_inode_actual_size(inode), \
> + field ## _extra)) { \
> + (inode)->field = (__s32)sec; \
> + ((struct ext2_inode_large *)(inode))->field ## _extra = \
> + __encode_extra_time(sec, 0); \
> + } else { \
> + (inode)->field = clamp(sec, INT32_MIN, INT32_MAX); \
> + } \
> +} while (0)
> +#define ext2fs_inode_xtime_get(inode, field) \
> +(ext2fs_inode_includes(ext2fs_inode_actual_size(inode), field ## _extra) ? \
> + __decode_extra_sec((inode)->field, \
> + ((struct ext2_inode_large *)(inode))->field ## _extra) : \
> + (time_t)(inode)->field)
> +
> +static inline void __sb_set_tstamp(__u32 *lo, __u8 *hi, time_t seconds)
> +{
> + *lo = seconds & 0xffffffff;
> + *hi = seconds >> 32;
> +}
> +static inline time_t __sb_get_tstamp(__u32 *lo, __u8 *hi)
> +{
> + return ((time_t)(*hi) << 32) | *lo;
> +}
> +#define ext2fs_set_tstamp(sb, field, seconds) \
> + __sb_set_tstamp(&(sb)->field, &(sb)->field ## _hi, seconds)
> +#define ext2fs_get_tstamp(sb, field) \
> + __sb_get_tstamp(&(sb)->field, &(sb)->field ## _hi)
> +
> /*
> * ext2_icount_t abstraction
> */
> diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c
> index edd692bb..32467a29 100644
> --- a/lib/ext2fs/initialize.c
> +++ b/lib/ext2fs/initialize.c
> @@ -218,7 +218,8 @@ errcode_t ext2fs_initialize(const char *name, int flags,
> }
>
> set_field(s_checkinterval, 0);
> - super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL);
> + ext2fs_set_tstamp(super, s_mkfs_time, fs->now ? fs->now : time(NULL));
> + ext2fs_set_tstamp(super, s_lastcheck, fs->now ? fs->now : time(NULL));
>
> super->s_creator_os = CREATOR_OS;
>
> diff --git a/lib/ext2fs/inode.c b/lib/ext2fs/inode.c
> index 957d5aa9..8686f99c 100644
> --- a/lib/ext2fs/inode.c
> +++ b/lib/ext2fs/inode.c
> @@ -1039,17 +1039,17 @@ errcode_t ext2fs_write_new_inode(ext2_filsys fs, ext2_ino_t ino,
> struct ext2_inode *inode)
> {
> struct ext2_inode *buf;
> - int size = EXT2_INODE_SIZE(fs->super);
> + int size = EXT2_INODE_SIZE(fs->super);
> struct ext2_inode_large *large_inode;
> errcode_t retval;
> - __u32 t = fs->now ? fs->now : time(NULL);
> + time_t t = fs->now ? fs->now : time(NULL);
>
> - if (!inode->i_ctime)
> - inode->i_ctime = t;
> - if (!inode->i_mtime)
> - inode->i_mtime = t;
> - if (!inode->i_atime)
> - inode->i_atime = t;
> + if (!ext2fs_inode_xtime_get(inode, i_atime))
> + ext2fs_inode_xtime_set(inode, i_atime, t);
> + if (!ext2fs_inode_xtime_get(inode, i_ctime))
> + ext2fs_inode_xtime_set(inode, i_ctime, t);
> + if (!ext2fs_inode_xtime_get(inode, i_mtime))
> + ext2fs_inode_xtime_set(inode, i_mtime, t);
>
> if (size == sizeof(struct ext2_inode))
> return ext2fs_write_inode_full(fs, ino, inode,
> diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c
> index 54772dd5..4a947b61 100644
> --- a/lib/ext2fs/mkjournal.c
> +++ b/lib/ext2fs/mkjournal.c
> @@ -285,6 +285,7 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
> unsigned long long inode_size;
> int falloc_flags = EXT2_FALLOCATE_FORCE_INIT;
> blk64_t zblk;
> + time_t now;
>
> if ((retval = ext2fs_create_journal_superblock2(fs, jparams, flags,
> &buf)))
> @@ -312,7 +313,9 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
>
> inode_size = (unsigned long long)fs->blocksize *
> (jparams->num_journal_blocks + jparams->num_fc_blocks);
> - inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
> + now = fs->now ? fs->now : time(0);
> + ext2fs_inode_xtime_set(&inode, i_mtime, now);
> + ext2fs_inode_xtime_set(&inode, i_ctime, now);
> inode.i_links_count = 1;
> inode.i_mode = LINUX_S_IFREG | 0600;
> retval = ext2fs_inode_size_set(fs, &inode, inode_size);
> diff --git a/lib/ext2fs/orphan.c b/lib/ext2fs/orphan.c
> index e25f20ca..60f4ea18 100644
> --- a/lib/ext2fs/orphan.c
> +++ b/lib/ext2fs/orphan.c
> @@ -126,6 +126,7 @@ errcode_t ext2fs_create_orphan_file(ext2_filsys fs, blk_t num_blocks)
> char *buf = NULL, *zerobuf = NULL;
> struct mkorphan_info oi;
> struct ext4_orphan_block_tail *ob_tail;
> + time_t now;
>
> if (!ino) {
> err = ext2fs_new_inode(fs, EXT2_ROOT_INO, LINUX_S_IFREG | 0600,
> @@ -185,8 +186,10 @@ errcode_t ext2fs_create_orphan_file(ext2_filsys fs, blk_t num_blocks)
> if (err)
> goto out;
> ext2fs_iblk_set(fs, &inode, 0);
> - inode.i_atime = inode.i_mtime =
> - inode.i_ctime = fs->now ? fs->now : time(0);
> + now = fs->now ? fs->now : time(0);
> + ext2fs_inode_xtime_set(&inode, i_atime, now);
> + ext2fs_inode_xtime_set(&inode, i_ctime, now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, now);
> inode.i_links_count = 1;
> inode.i_mode = LINUX_S_IFREG | 0600;
> ext2fs_iblk_add_blocks(fs, &inode, oi.alloc_blocks);
> diff --git a/lib/ext2fs/res_gdt.c b/lib/ext2fs/res_gdt.c
> index fa8d8d6b..9024165d 100644
> --- a/lib/ext2fs/res_gdt.c
> +++ b/lib/ext2fs/res_gdt.c
> @@ -227,7 +227,10 @@ out_inode:
> EXT2_I_SIZE(&inode));
> #endif
> if (inode_dirty) {
> - inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0);
> + time_t now = fs->now ? fs->now : time(0);
> +
> + ext2fs_inode_xtime_set(&inode, i_atime, now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, now);
> retval2 = ext2fs_write_new_inode(fs, EXT2_RESIZE_INO, &inode);
> if (!retval)
> retval = retval2;
> diff --git a/lib/ext2fs/swapfs.c b/lib/ext2fs/swapfs.c
> index fe764b9e..d8d21407 100644
> --- a/lib/ext2fs/swapfs.c
> +++ b/lib/ext2fs/swapfs.c
> @@ -345,21 +345,21 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t,
> return; /* Illegal inode extra_isize */
>
> inode_size = EXT2_GOOD_OLD_INODE_SIZE + extra_isize;
> - if (inode_includes(inode_size, i_checksum_hi))
> + if (ext2fs_inode_includes(inode_size, i_checksum_hi))
> t->i_checksum_hi = ext2fs_swab16(f->i_checksum_hi);
> - if (inode_includes(inode_size, i_ctime_extra))
> + if (ext2fs_inode_includes(inode_size, i_ctime_extra))
> t->i_ctime_extra = ext2fs_swab32(f->i_ctime_extra);
> - if (inode_includes(inode_size, i_mtime_extra))
> + if (ext2fs_inode_includes(inode_size, i_mtime_extra))
> t->i_mtime_extra = ext2fs_swab32(f->i_mtime_extra);
> - if (inode_includes(inode_size, i_atime_extra))
> + if (ext2fs_inode_includes(inode_size, i_atime_extra))
> t->i_atime_extra = ext2fs_swab32(f->i_atime_extra);
> - if (inode_includes(inode_size, i_crtime))
> + if (ext2fs_inode_includes(inode_size, i_crtime))
> t->i_crtime = ext2fs_swab32(f->i_crtime);
> - if (inode_includes(inode_size, i_crtime_extra))
> + if (ext2fs_inode_includes(inode_size, i_crtime_extra))
> t->i_crtime_extra = ext2fs_swab32(f->i_crtime_extra);
> - if (inode_includes(inode_size, i_version_hi))
> + if (ext2fs_inode_includes(inode_size, i_version_hi))
> t->i_version_hi = ext2fs_swab32(f->i_version_hi);
> - if (inode_includes(inode_size, i_projid))
> + if (ext2fs_inode_includes(inode_size, i_projid))
> t->i_projid = ext2fs_swab32(f->i_projid);
> /* catch new static fields added after i_projid */
> EXT2FS_BUILD_BUG_ON(sizeof(struct ext2_inode_large) != 160);
> diff --git a/lib/support/mkquota.c b/lib/support/mkquota.c
> index 9339c994..81cfbf1f 100644
> --- a/lib/support/mkquota.c
> +++ b/lib/support/mkquota.c
> @@ -269,7 +269,7 @@ static inline qid_t get_qid(struct ext2_inode_large *inode, enum quota_type qtyp
> case PRJQUOTA:
> inode_size = EXT2_GOOD_OLD_INODE_SIZE +
> inode->i_extra_isize;
> - if (inode_includes(inode_size, i_projid))
> + if (ext2fs_inode_includes(inode_size, i_projid))
> return inode_projid(*inode);
> return 0;
> default:
> diff --git a/lib/support/plausible.c b/lib/support/plausible.c
> index 65a6b2e1..eccba22a 100644
> --- a/lib/support/plausible.c
> +++ b/lib/support/plausible.c
> @@ -108,18 +108,15 @@ static void print_ext2_info(const char *device)
> return;
> sb = fs->super;
>
> - if (sb->s_mtime) {
> - tm = sb->s_mtime;
> + if ((tm = ext2fs_get_tstamp(sb, s_mtime))) {
> if (sb->s_last_mounted[0])
> printf(_("\tlast mounted on %.*s on %s"),
> EXT2_LEN_STR(sb->s_last_mounted), ctime(&tm));
> else
> printf(_("\tlast mounted on %s"), ctime(&tm));
> - } else if (sb->s_mkfs_time) {
> - tm = sb->s_mkfs_time;
> + } else if ((tm = ext2fs_get_tstamp(sb, s_mkfs_time))) {
> printf(_("\tcreated on %s"), ctime(&tm));
> - } else if (sb->s_wtime) {
> - tm = sb->s_wtime;
> + } else if ((tm = ext2fs_get_tstamp(sb, s_wtime))) {
> printf(_("\tlast modified on %s"), ctime(&tm));
> }
> ext2fs_close_free(&fs);
> diff --git a/lib/support/quotaio.c b/lib/support/quotaio.c
> index b41bb749..916e28cf 100644
> --- a/lib/support/quotaio.c
> +++ b/lib/support/quotaio.c
> @@ -272,6 +272,7 @@ static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino)
> {
> struct ext2_inode inode;
> errcode_t err = 0;
> + time_t now;
>
> err = ext2fs_read_inode(fs, ino, &inode);
> if (err) {
> @@ -287,8 +288,10 @@ static errcode_t quota_inode_init_new(ext2_filsys fs, ext2_ino_t ino)
>
> memset(&inode, 0, sizeof(struct ext2_inode));
> ext2fs_iblk_set(fs, &inode, 0);
> - inode.i_atime = inode.i_mtime =
> - inode.i_ctime = fs->now ? fs->now : time(0);
> + now = fs->now ? fs->now : time(0);
> + ext2fs_inode_xtime_set(&inode, i_atime, now);
> + ext2fs_inode_xtime_set(&inode, i_ctime, now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, now);
> inode.i_links_count = 1;
> inode.i_mode = LINUX_S_IFREG | 0600;
> inode.i_flags |= EXT2_IMMUTABLE_FL;
> diff --git a/misc/create_inode.c b/misc/create_inode.c
> index a3a34cd9..28f478c0 100644
> --- a/misc/create_inode.c
> +++ b/misc/create_inode.c
> @@ -125,9 +125,9 @@ static errcode_t set_inode_extra(ext2_filsys fs, ext2_ino_t ino,
> inode.i_gid = st->st_gid;
> ext2fs_set_i_gid_high(inode, st->st_gid >> 16);
> inode.i_mode = (LINUX_S_IFMT & inode.i_mode) | (~S_IFMT & st->st_mode);
> - inode.i_atime = st->st_atime;
> - inode.i_mtime = st->st_mtime;
> - inode.i_ctime = st->st_ctime;
> + ext2fs_inode_xtime_set(&inode, i_atime, st->st_atime);
> + ext2fs_inode_xtime_set(&inode, i_ctime, st->st_ctime);
> + ext2fs_inode_xtime_set(&inode, i_mtime, st->st_mtime);
>
> retval = ext2fs_write_inode(fs, ino, &inode);
> if (retval)
> @@ -256,6 +256,7 @@ errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
> struct ext2_inode inode;
> unsigned long devmajor, devminor, mode;
> int filetype;
> + time_t now;
>
> switch(st_mode & S_IFMT) {
> case S_IFCHR:
> @@ -309,8 +310,10 @@ errcode_t do_mknod_internal(ext2_filsys fs, ext2_ino_t cwd, const char *name,
> ext2fs_inode_alloc_stats2(fs, ino, +1, 0);
> memset(&inode, 0, sizeof(inode));
> inode.i_mode = mode;
> - inode.i_atime = inode.i_ctime = inode.i_mtime =
> - fs->now ? fs->now : time(0);
> + now = fs->now ? fs->now : time(0);
> + ext2fs_inode_xtime_set(&inode, i_atime, now);
> + ext2fs_inode_xtime_set(&inode, i_ctime, now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, now);
>
> if (filetype != S_IFIFO) {
> devmajor = major(st_rdev);
> @@ -631,6 +634,7 @@ errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
> errcode_t retval;
> struct ext2_inode inode;
> char *cp;
> + time_t now;
>
> fd = ext2fs_open_file(src, O_RDONLY, 0);
> if (fd < 0) {
> @@ -684,8 +688,10 @@ errcode_t do_write_internal(ext2_filsys fs, ext2_ino_t cwd, const char *src,
> ext2fs_inode_alloc_stats2(fs, newfile, +1, 0);
> memset(&inode, 0, sizeof(inode));
> inode.i_mode = (statbuf.st_mode & ~S_IFMT) | LINUX_S_IFREG;
> - inode.i_atime = inode.i_ctime = inode.i_mtime =
> - fs->now ? fs->now : time(0);
> + now = fs->now ? fs->now : time(0);
> + ext2fs_inode_xtime_set(&inode, i_atime, now);
> + ext2fs_inode_xtime_set(&inode, i_ctime, now);
> + ext2fs_inode_xtime_set(&inode, i_mtime, now);
> inode.i_links_count = 1;
> retval = ext2fs_inode_size_set(fs, &inode, statbuf.st_size);
> if (retval)
> diff --git a/misc/e2undo.c b/misc/e2undo.c
> index bc78fb2e..4cbf8884 100644
> --- a/misc/e2undo.c
> +++ b/misc/e2undo.c
> @@ -154,9 +154,11 @@ static void print_undo_mismatch(struct ext2_super_block *fs_super,
> if (memcmp(fs_super->s_uuid, undo_super->s_uuid,
> sizeof(fs_super->s_uuid)))
> printf("%s", _("UUID does not match.\n"));
> - if (fs_super->s_mtime != undo_super->s_mtime)
> + if (ext2fs_get_tstamp(fs_super, s_mtime) !=
> + ext2fs_get_tstamp(undo_super, s_mtime))
> printf("%s", _("Last mount time does not match.\n"));
> - if (fs_super->s_wtime != undo_super->s_wtime)
> + if (ext2fs_get_tstamp(fs_super, s_wtime) !=
> + ext2fs_get_tstamp(undo_super, s_wtime))
> printf("%s", _("Last write time does not match.\n"));
> if (fs_super->s_kbytes_written != undo_super->s_kbytes_written)
> printf("%s", _("Lifetime write counter does not match.\n"));
> diff --git a/misc/findsuper.c b/misc/findsuper.c
> index 7e78c1fc..1f5c3e72 100644
> --- a/misc/findsuper.c
> +++ b/misc/findsuper.c
> @@ -230,10 +230,9 @@ int main(int argc, char *argv[])
> WHY("free_inodes_count > inodes_count (%u > %u)\n",
> ext2.s_free_inodes_count, ext2.s_inodes_count);
>
> - if (ext2.s_mkfs_time != 0)
> - tm = ext2.s_mkfs_time;
> - else
> - tm = ext2.s_mtime;
> + tm = ext2fs_get_tstamp(ext2, s_mkfs_time);
> + if (tm == 0)
> + tm = ext2fs_get_tstamp(ext2, s_mtime);
> s = ctime(&tm);
> s[24] = 0;
> bsize = 1 << (ext2.s_log_block_size + 10);
> diff --git a/misc/fuse2fs.c b/misc/fuse2fs.c
> index 0dc77ead..4133e060 100644
> --- a/misc/fuse2fs.c
> +++ b/misc/fuse2fs.c
> @@ -746,7 +746,7 @@ static void *op_init(struct fuse_conn_info *conn)
> #endif
> if (fs->flags & EXT2_FLAG_RW) {
> fs->super->s_mnt_count++;
> - fs->super->s_mtime = time(NULL);
> + ext2fs_set_tstamp(fs->super, s_mtime, time(NULL));
> fs->super->s_state &= ~EXT2_VALID_FS;
> ext2fs_mark_super_dirty(fs);
> err = ext2fs_flush2(fs, 0);
> @@ -3984,14 +3984,14 @@ no_translation:
>
> /* Make a note in the error log */
> get_now(&now);
> - fs->super->s_last_error_time = now.tv_sec;
> + ext2fs_set_tstamp(fs->super, s_last_error_time, now.tv_sec);
> fs->super->s_last_error_ino = ino;
> fs->super->s_last_error_line = line;
> fs->super->s_last_error_block = err; /* Yeah... */
> strncpy((char *)fs->super->s_last_error_func, file,
> sizeof(fs->super->s_last_error_func));
> - if (fs->super->s_first_error_time == 0) {
> - fs->super->s_first_error_time = now.tv_sec;
> + if (ext2fs_get_tstamp(fs->super, s_first_error_time) == 0) {
> + ext2fs_set_tstamp(fs->super, s_first_error_time, now.tv_sec);
> fs->super->s_first_error_ino = ino;
> fs->super->s_first_error_line = line;
> fs->super->s_first_error_block = err;
> diff --git a/misc/tune2fs.c b/misc/tune2fs.c
> index 458f7cf6..52b0aa53 100644
> --- a/misc/tune2fs.c
> +++ b/misc/tune2fs.c
> @@ -466,7 +466,8 @@ static int check_fsck_needed(ext2_filsys fs, const char *prompt)
> /* Refuse to modify anything but a freshly checked valid filesystem. */
> if (!(fs->super->s_state & EXT2_VALID_FS) ||
> (fs->super->s_state & EXT2_ERROR_FS) ||
> - (fs->super->s_lastcheck < fs->super->s_mtime)) {
> + (ext2fs_get_tstamp(fs->super, s_lastcheck) <
> + ext2fs_get_tstamp(fs->super, s_mtime))) {
> puts(_(fsck_explain));
> puts(_(please_fsck));
> if (mount_flags & EXT2_MF_READONLY)
> @@ -520,7 +521,8 @@ static void convert_64bit(ext2_filsys fs, int direction)
> if (!fsck_requested &&
> ((fs->super->s_state & EXT2_ERROR_FS) ||
> !(fs->super->s_state & EXT2_VALID_FS) ||
> - fs->super->s_lastcheck < fs->super->s_mtime))
> + ext2fs_get_tstamp(fs->super, s_lastcheck) <
> + ext2fs_get_tstamp(fs->super, s_mtime)))
> request_fsck_afterwards(fs);
> if (fsck_requested)
> fprintf(stderr, _("After running e2fsck, please run `resize2fs %s %s"),
> --
> 2.25.1
>
Cheers, Andreas
Download attachment "signature.asc" of type "application/pgp-signature" (874 bytes)
Powered by blists - more mailing lists