Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8dbffe20 authored by Chung-Chiang Cheng's avatar Chung-Chiang Cheng Committed by Namjae Jeon
Browse files

exfat: introduce mount option 'sys_tz'

EXFAT_TZ_VALID bit in {create,modify,access}_tz is corresponding to
OffsetValid field in exfat specification [1]. When this bit isn't
set, timestamps should be treated as having the same UTC offset as
the current local time.

Currently, there is an option 'time_offset' for users to specify the
UTC offset for this issue. This patch introduces a new mount option
'sys_tz' to use system timezone as time offset.

Link: [1] https://docs.microsoft.com/en-us/windows/win32/fileio/exfat-specification#74102-offsetvalid-field



Signed-off-by: default avatarChung-Chiang Cheng <cccheng@synology.com>
Acked-by: default avatarSungjong Seo <sj1557.seo@samsung.com>
Signed-off-by: default avatarNamjae Jeon <linkinjeon@kernel.org>
parent 2ae96136
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -213,6 +213,7 @@ struct exfat_mount_options {
	/* on error: continue, panic, remount-ro */
	enum exfat_error_mode errors;
	unsigned utf8:1, /* Use of UTF-8 character set */
		 sys_tz:1, /* Use local timezone */
		 discard:1, /* Issue discard requests on deletions */
		 keep_last_dots:1; /* Keep trailing periods in paths */
	int time_offset; /* Offset of timestamps from UTC (in minutes) */
+8 −2
Original line number Diff line number Diff line
@@ -84,6 +84,13 @@ static void exfat_adjust_tz(struct timespec *ts, u8 tz_off)
		ts->tv_sec += TIMEZONE_SEC(0x80 - tz_off);
}

static inline int exfat_tz_offset(struct exfat_sb_info *sbi)
{
	if (sbi->options.sys_tz)
		return -sys_tz.tz_minuteswest;
	return sbi->options.time_offset;
}

/* Convert a EXFAT time/date pair to a UNIX date (seconds since 1 1 70). */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 19, 0)
void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec64 *ts,
@@ -111,8 +118,7 @@ void exfat_get_entry_time(struct exfat_sb_info *sbi, struct timespec *ts,
		/* Adjust timezone to UTC0. */
		exfat_adjust_tz(ts, tz & ~EXFAT_TZ_VALID);
	else
		/* Convert from local time to UTC using time_offset. */
		ts->tv_sec -= sbi->options.time_offset * SECS_PER_MIN;
		ts->tv_sec -= exfat_tz_offset(sbi) * SECS_PER_MIN;
}

/* Convert linear UNIX date to a EXFAT time/date pair. */
+8 −1
Original line number Diff line number Diff line
@@ -191,7 +191,9 @@ static int exfat_show_options(struct seq_file *m, struct dentry *root)
		seq_puts(m, ",discard");
	if (opts->keep_last_dots)
		seq_puts(m, ",keep_last_dots");
	if (opts->time_offset)
	if (opts->sys_tz)
		seq_puts(m, ",sys_tz");
	else if (opts->time_offset)
		seq_printf(m, ",time_offset=%d", opts->time_offset);
	return 0;
}
@@ -270,6 +272,7 @@ enum {
	Opt_errors,
	Opt_discard,
	Opt_keep_last_dots,
	Opt_sys_tz,
	Opt_time_offset,

	/* Deprecated options */
@@ -314,6 +317,7 @@ static const struct fs_parameter_spec exfat_param_specs[] = {
#endif
	fsparam_flag("discard",			Opt_discard),
	fsparam_flag("keep_last_dots",		Opt_keep_last_dots),
	fsparam_flag("sys_tz",			Opt_sys_tz),
	fsparam_s32("time_offset",		Opt_time_offset),
	__fsparam(NULL, "utf8",			Opt_utf8, fs_param_deprecated,
		  NULL),
@@ -383,6 +387,9 @@ static int exfat_parse_param(struct fs_context *fc, struct fs_parameter *param)
	case Opt_keep_last_dots:
		opts->keep_last_dots = 1;
		break;
	case Opt_sys_tz:
		opts->sys_tz = 1;
		break;
	case Opt_time_offset:
		/*
		 * Make the limit 24 just in case someone invents something