Commit 58156c8fbf43e71dd091848d4dbfd780d04016e6

Authored by Jan Kara
Committed by Linus Torvalds
1 parent f562146a3d

fat: provide option for setting timezone offset

So far FAT either offsets time stamps by sys_tz.minuteswest or leaves them
as they are (when tz=UTC mount option is used).  However in some cases it
is useful if one can specify time stamp offset on his own (e.g.  when time
zone of the camera connected is different from time zone of the computer,
or when HW clock is in UTC and thus sys_tz.minuteswest == 0).

So provide a mount option time_offset= which allows user to specify offset
in minutes that should be applied to time stamps on the filesystem.

akpm: this code would work incorrectly when used via `mount -o remount',
because cached inodes would not be updated.  But fatfs's fat_remount() is
basically a no-op anyway.

Signed-off-by: Jan Kara <jack@suse.cz>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 4 changed files with 37 additions and 9 deletions Side-by-side Diff

Documentation/filesystems/vfat.txt
... ... @@ -111,6 +111,15 @@
111 111 useful when mounting devices (like digital cameras)
112 112 that are set to UTC in order to avoid the pitfalls of
113 113 local time.
  114 +time_offset=minutes
  115 + -- Set offset for conversion of timestamps from local time
  116 + used by FAT to UTC. I.e. <minutes> minutes will be subtracted
  117 + from each timestamp to convert it to UTC used internally by
  118 + Linux. This is useful when time zone set in sys_tz is
  119 + not the time zone used by the filesystem. Note that this
  120 + option still does not provide correct time stamps in all
  121 + cases in presence of DST - time stamps in a different DST
  122 + setting will be off by one hour.
114 123  
115 124 showexec -- If set, the execute permission bits of the file will be
116 125 allowed only if the extension part of the name is .EXE,
... ... @@ -29,6 +29,7 @@
29 29 unsigned short fs_fmask;
30 30 unsigned short fs_dmask;
31 31 unsigned short codepage; /* Codepage for shortname conversions */
  32 + int time_offset; /* Offset of timestamps from UTC (in minutes) */
32 33 char *iocharset; /* Charset used for filename input/display */
33 34 unsigned short shortname; /* flags for shortname display/create rule */
34 35 unsigned char name_check; /* r = relaxed, n = normal, s = strict */
... ... @@ -45,7 +46,7 @@
45 46 flush:1, /* write things quickly */
46 47 nocase:1, /* Does this need case conversion? 0=need case conversion*/
47 48 usefree:1, /* Use free_clusters for FAT32 */
48   - tz_utc:1, /* Filesystem timestamps are in UTC */
  49 + tz_set:1, /* Filesystem timestamps' offset set */
49 50 rodir:1, /* allow ATTR_RO for directory */
50 51 discard:1, /* Issue discard requests on deletions */
51 52 nfs:1; /* Do extra work needed for NFS export */
... ... @@ -778,8 +778,12 @@
778 778 }
779 779 if (opts->flush)
780 780 seq_puts(m, ",flush");
781   - if (opts->tz_utc)
782   - seq_puts(m, ",tz=UTC");
  781 + if (opts->tz_set) {
  782 + if (opts->time_offset)
  783 + seq_printf(m, ",time_offset=%d", opts->time_offset);
  784 + else
  785 + seq_puts(m, ",tz=UTC");
  786 + }
783 787 if (opts->errors == FAT_ERRORS_CONT)
784 788 seq_puts(m, ",errors=continue");
785 789 else if (opts->errors == FAT_ERRORS_PANIC)
... ... @@ -801,7 +805,8 @@
801 805 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
802 806 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
803 807 Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont,
804   - Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_err,
  808 + Opt_err_panic, Opt_err_ro, Opt_discard, Opt_nfs, Opt_time_offset,
  809 + Opt_err,
805 810 };
806 811  
807 812 static const match_table_t fat_tokens = {
... ... @@ -826,6 +831,7 @@
826 831 {Opt_immutable, "sys_immutable"},
827 832 {Opt_flush, "flush"},
828 833 {Opt_tz_utc, "tz=UTC"},
  834 + {Opt_time_offset, "time_offset=%d"},
829 835 {Opt_err_cont, "errors=continue"},
830 836 {Opt_err_panic, "errors=panic"},
831 837 {Opt_err_ro, "errors=remount-ro"},
... ... @@ -910,7 +916,7 @@
910 916 opts->utf8 = opts->unicode_xlate = 0;
911 917 opts->numtail = 1;
912 918 opts->usefree = opts->nocase = 0;
913   - opts->tz_utc = 0;
  919 + opts->tz_set = 0;
914 920 opts->nfs = 0;
915 921 opts->errors = FAT_ERRORS_RO;
916 922 *debug = 0;
917 923  
... ... @@ -1006,8 +1012,17 @@
1006 1012 case Opt_flush:
1007 1013 opts->flush = 1;
1008 1014 break;
  1015 + case Opt_time_offset:
  1016 + if (match_int(&args[0], &option))
  1017 + return 0;
  1018 + if (option < -12 * 60 || option > 12 * 60)
  1019 + return 0;
  1020 + opts->tz_set = 1;
  1021 + opts->time_offset = option;
  1022 + break;
1009 1023 case Opt_tz_utc:
1010   - opts->tz_utc = 1;
  1024 + opts->tz_set = 1;
  1025 + opts->time_offset = 0;
1011 1026 break;
1012 1027 case Opt_err_cont:
1013 1028 opts->errors = FAT_ERRORS_CONT;
... ... @@ -212,8 +212,10 @@
212 212 + days_in_year[month] + day
213 213 + DAYS_DELTA) * SECS_PER_DAY;
214 214  
215   - if (!sbi->options.tz_utc)
  215 + if (!sbi->options.tz_set)
216 216 second += sys_tz.tz_minuteswest * SECS_PER_MIN;
  217 + else
  218 + second -= sbi->options.time_offset * SECS_PER_MIN;
217 219  
218 220 if (time_cs) {
219 221 ts->tv_sec = second + (time_cs / 100);
... ... @@ -229,8 +231,9 @@
229 231 __le16 *time, __le16 *date, u8 *time_cs)
230 232 {
231 233 struct tm tm;
232   - time_to_tm(ts->tv_sec, sbi->options.tz_utc ? 0 :
233   - -sys_tz.tz_minuteswest * 60, &tm);
  234 + time_to_tm(ts->tv_sec,
  235 + (sbi->options.tz_set ? sbi->options.time_offset :
  236 + -sys_tz.tz_minuteswest) * SECS_PER_MIN, &tm);
234 237  
235 238 /* FAT can only support year between 1980 to 2107 */
236 239 if (tm.tm_year < 1980 - 1900) {