aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2012-12-17 19:02:58 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2012-12-17 20:15:22 -0500
commit58156c8fbf43e71dd091848d4dbfd780d04016e6 (patch)
treeffe31e639221d1f2434f873f93d3ee654cbfb9da /fs/fat
parentf562146a3daf6aa0bbf2a1bc4b6b7da031ed5dcd (diff)
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>
Diffstat (limited to 'fs/fat')
-rw-r--r--fs/fat/fat.h3
-rw-r--r--fs/fat/inode.c25
-rw-r--r--fs/fat/misc.c9
3 files changed, 28 insertions, 9 deletions
diff --git a/fs/fat/fat.h b/fs/fat/fat.h
index 623f36f0423b..12701a567752 100644
--- a/fs/fat/fat.h
+++ b/fs/fat/fat.h
@@ -29,6 +29,7 @@ struct fat_mount_options {
29 unsigned short fs_fmask; 29 unsigned short fs_fmask;
30 unsigned short fs_dmask; 30 unsigned short fs_dmask;
31 unsigned short codepage; /* Codepage for shortname conversions */ 31 unsigned short codepage; /* Codepage for shortname conversions */
32 int time_offset; /* Offset of timestamps from UTC (in minutes) */
32 char *iocharset; /* Charset used for filename input/display */ 33 char *iocharset; /* Charset used for filename input/display */
33 unsigned short shortname; /* flags for shortname display/create rule */ 34 unsigned short shortname; /* flags for shortname display/create rule */
34 unsigned char name_check; /* r = relaxed, n = normal, s = strict */ 35 unsigned char name_check; /* r = relaxed, n = normal, s = strict */
@@ -45,7 +46,7 @@ struct fat_mount_options {
45 flush:1, /* write things quickly */ 46 flush:1, /* write things quickly */
46 nocase:1, /* Does this need case conversion? 0=need case conversion*/ 47 nocase:1, /* Does this need case conversion? 0=need case conversion*/
47 usefree:1, /* Use free_clusters for FAT32 */ 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 rodir:1, /* allow ATTR_RO for directory */ 50 rodir:1, /* allow ATTR_RO for directory */
50 discard:1, /* Issue discard requests on deletions */ 51 discard:1, /* Issue discard requests on deletions */
51 nfs:1; /* Do extra work needed for NFS export */ 52 nfs:1; /* Do extra work needed for NFS export */
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 7b186a5d51b1..59ac83be2d5b 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -778,8 +778,12 @@ static int fat_show_options(struct seq_file *m, struct dentry *root)
778 } 778 }
779 if (opts->flush) 779 if (opts->flush)
780 seq_puts(m, ",flush"); 780 seq_puts(m, ",flush");
781 if (opts->tz_utc) 781 if (opts->tz_set) {
782 seq_puts(m, ",tz=UTC"); 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 if (opts->errors == FAT_ERRORS_CONT) 787 if (opts->errors == FAT_ERRORS_CONT)
784 seq_puts(m, ",errors=continue"); 788 seq_puts(m, ",errors=continue");
785 else if (opts->errors == FAT_ERRORS_PANIC) 789 else if (opts->errors == FAT_ERRORS_PANIC)
@@ -801,7 +805,8 @@ enum {
801 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, 805 Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
802 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, 806 Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
803 Opt_obsolete, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err_cont, 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
807static const match_table_t fat_tokens = { 812static const match_table_t fat_tokens = {
@@ -826,6 +831,7 @@ static const match_table_t fat_tokens = {
826 {Opt_immutable, "sys_immutable"}, 831 {Opt_immutable, "sys_immutable"},
827 {Opt_flush, "flush"}, 832 {Opt_flush, "flush"},
828 {Opt_tz_utc, "tz=UTC"}, 833 {Opt_tz_utc, "tz=UTC"},
834 {Opt_time_offset, "time_offset=%d"},
829 {Opt_err_cont, "errors=continue"}, 835 {Opt_err_cont, "errors=continue"},
830 {Opt_err_panic, "errors=panic"}, 836 {Opt_err_panic, "errors=panic"},
831 {Opt_err_ro, "errors=remount-ro"}, 837 {Opt_err_ro, "errors=remount-ro"},
@@ -910,7 +916,7 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
910 opts->utf8 = opts->unicode_xlate = 0; 916 opts->utf8 = opts->unicode_xlate = 0;
911 opts->numtail = 1; 917 opts->numtail = 1;
912 opts->usefree = opts->nocase = 0; 918 opts->usefree = opts->nocase = 0;
913 opts->tz_utc = 0; 919 opts->tz_set = 0;
914 opts->nfs = 0; 920 opts->nfs = 0;
915 opts->errors = FAT_ERRORS_RO; 921 opts->errors = FAT_ERRORS_RO;
916 *debug = 0; 922 *debug = 0;
@@ -1006,8 +1012,17 @@ static int parse_options(struct super_block *sb, char *options, int is_vfat,
1006 case Opt_flush: 1012 case Opt_flush:
1007 opts->flush = 1; 1013 opts->flush = 1;
1008 break; 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 case Opt_tz_utc: 1023 case Opt_tz_utc:
1010 opts->tz_utc = 1; 1024 opts->tz_set = 1;
1025 opts->time_offset = 0;
1011 break; 1026 break;
1012 case Opt_err_cont: 1027 case Opt_err_cont:
1013 opts->errors = FAT_ERRORS_CONT; 1028 opts->errors = FAT_ERRORS_CONT;
diff --git a/fs/fat/misc.c b/fs/fat/misc.c
index 6d93360ca0cc..5eb600dc43a9 100644
--- a/fs/fat/misc.c
+++ b/fs/fat/misc.c
@@ -212,8 +212,10 @@ void fat_time_fat2unix(struct msdos_sb_info *sbi, struct timespec *ts,
212 + days_in_year[month] + day 212 + days_in_year[month] + day
213 + DAYS_DELTA) * SECS_PER_DAY; 213 + DAYS_DELTA) * SECS_PER_DAY;
214 214
215 if (!sbi->options.tz_utc) 215 if (!sbi->options.tz_set)
216 second += sys_tz.tz_minuteswest * SECS_PER_MIN; 216 second += sys_tz.tz_minuteswest * SECS_PER_MIN;
217 else
218 second -= sbi->options.time_offset * SECS_PER_MIN;
217 219
218 if (time_cs) { 220 if (time_cs) {
219 ts->tv_sec = second + (time_cs / 100); 221 ts->tv_sec = second + (time_cs / 100);
@@ -229,8 +231,9 @@ void fat_time_unix2fat(struct msdos_sb_info *sbi, struct timespec *ts,
229 __le16 *time, __le16 *date, u8 *time_cs) 231 __le16 *time, __le16 *date, u8 *time_cs)
230{ 232{
231 struct tm tm; 233 struct tm tm;
232 time_to_tm(ts->tv_sec, sbi->options.tz_utc ? 0 : 234 time_to_tm(ts->tv_sec,
233 -sys_tz.tz_minuteswest * 60, &tm); 235 (sbi->options.tz_set ? sbi->options.time_offset :
236 -sys_tz.tz_minuteswest) * SECS_PER_MIN, &tm);
234 237
235 /* FAT can only support year between 1980 to 2107 */ 238 /* FAT can only support year between 1980 to 2107 */
236 if (tm.tm_year < 1980 - 1900) { 239 if (tm.tm_year < 1980 - 1900) {