diff options
author | Joe Peterson <joe@skyrush.com> | 2008-07-25 04:46:47 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:34 -0400 |
commit | b271e067c896ad4082b15e96077675d08db40625 (patch) | |
tree | 1837d1c988226116e277c4f71b7f57aed5a7df05 /fs/fat/inode.c | |
parent | e8938a62a85d1f487e02c3b01955b47c9598f6d2 (diff) |
fatfs: add UTC timestamp option
Provide a new mount option ("tz=UTC") for DOS (vfat/msdos) filesystems,
allowing timestamps to be in coordinated universal time (UTC) rather than
local time in applications where doing this is advantageous.
In particular, portable devices that use fat/vfat (such as digital
cameras) can benefit from using UTC in their internal clocks, thus
avoiding daylight saving time errors and general time ambiguity issues.
The user of the device does not have to worry about changing the time when
moving from place or when daylight saving changes.
The new mount option, when set, disables the counter-adjustment that Linux
currently makes to FAT timestamp info in anticipation of the normal
userspace time zone correction. When used in this new mode, all daylight
saving time and time zone handling is done in userspace as is normal for
many other filesystems (like ext3). The default mode, which remains
unchanged, is still appropriate when mounting volumes written in Windows
(because of its use of local time).
I originally based this patch on one submitted last year by Paul Collins,
but I updated it to work with current source and changed variable/option
naming. Ogawa Hirofumi (who maintains these filesystems) and I discussed
this patch at length on lkml, and he suggested using the option name in
the attached version of the patch. Barry Bouwsma pointed out a good
addition to the patch as well.
Signed-off-by: Joe Peterson <joe@skyrush.com>
Signed-off-by: Paul Collins <paul@ondioline.org>
Acked-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Cc: Barry Bouwsma <free_beer_for_all@yahoo.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/fat/inode.c')
-rw-r--r-- | fs/fat/inode.c | 27 |
1 files changed, 20 insertions, 7 deletions
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 60deb5fd1188..23676f9d79ce 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -382,17 +382,20 @@ static int fat_fill_inode(struct inode *inode, struct msdos_dir_entry *de) | |||
382 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) | 382 | inode->i_blocks = ((inode->i_size + (sbi->cluster_size - 1)) |
383 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; | 383 | & ~((loff_t)sbi->cluster_size - 1)) >> 9; |
384 | inode->i_mtime.tv_sec = | 384 | inode->i_mtime.tv_sec = |
385 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date)); | 385 | date_dos2unix(le16_to_cpu(de->time), le16_to_cpu(de->date), |
386 | sbi->options.tz_utc); | ||
386 | inode->i_mtime.tv_nsec = 0; | 387 | inode->i_mtime.tv_nsec = 0; |
387 | if (sbi->options.isvfat) { | 388 | if (sbi->options.isvfat) { |
388 | int secs = de->ctime_cs / 100; | 389 | int secs = de->ctime_cs / 100; |
389 | int csecs = de->ctime_cs % 100; | 390 | int csecs = de->ctime_cs % 100; |
390 | inode->i_ctime.tv_sec = | 391 | inode->i_ctime.tv_sec = |
391 | date_dos2unix(le16_to_cpu(de->ctime), | 392 | date_dos2unix(le16_to_cpu(de->ctime), |
392 | le16_to_cpu(de->cdate)) + secs; | 393 | le16_to_cpu(de->cdate), |
394 | sbi->options.tz_utc) + secs; | ||
393 | inode->i_ctime.tv_nsec = csecs * 10000000; | 395 | inode->i_ctime.tv_nsec = csecs * 10000000; |
394 | inode->i_atime.tv_sec = | 396 | inode->i_atime.tv_sec = |
395 | date_dos2unix(0, le16_to_cpu(de->adate)); | 397 | date_dos2unix(0, le16_to_cpu(de->adate), |
398 | sbi->options.tz_utc); | ||
396 | inode->i_atime.tv_nsec = 0; | 399 | inode->i_atime.tv_nsec = 0; |
397 | } else | 400 | } else |
398 | inode->i_ctime = inode->i_atime = inode->i_mtime; | 401 | inode->i_ctime = inode->i_atime = inode->i_mtime; |
@@ -591,11 +594,14 @@ retry: | |||
591 | raw_entry->attr = fat_attr(inode); | 594 | raw_entry->attr = fat_attr(inode); |
592 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); | 595 | raw_entry->start = cpu_to_le16(MSDOS_I(inode)->i_logstart); |
593 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); | 596 | raw_entry->starthi = cpu_to_le16(MSDOS_I(inode)->i_logstart >> 16); |
594 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, &raw_entry->date); | 597 | fat_date_unix2dos(inode->i_mtime.tv_sec, &raw_entry->time, |
598 | &raw_entry->date, sbi->options.tz_utc); | ||
595 | if (sbi->options.isvfat) { | 599 | if (sbi->options.isvfat) { |
596 | __le16 atime; | 600 | __le16 atime; |
597 | fat_date_unix2dos(inode->i_ctime.tv_sec,&raw_entry->ctime,&raw_entry->cdate); | 601 | fat_date_unix2dos(inode->i_ctime.tv_sec, &raw_entry->ctime, |
598 | fat_date_unix2dos(inode->i_atime.tv_sec,&atime,&raw_entry->adate); | 602 | &raw_entry->cdate, sbi->options.tz_utc); |
603 | fat_date_unix2dos(inode->i_atime.tv_sec, &atime, | ||
604 | &raw_entry->adate, sbi->options.tz_utc); | ||
599 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + | 605 | raw_entry->ctime_cs = (inode->i_ctime.tv_sec & 1) * 100 + |
600 | inode->i_ctime.tv_nsec / 10000000; | 606 | inode->i_ctime.tv_nsec / 10000000; |
601 | } | 607 | } |
@@ -836,6 +842,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
836 | } | 842 | } |
837 | if (sbi->options.flush) | 843 | if (sbi->options.flush) |
838 | seq_puts(m, ",flush"); | 844 | seq_puts(m, ",flush"); |
845 | if (opts->tz_utc) | ||
846 | seq_puts(m, ",tz=UTC"); | ||
839 | 847 | ||
840 | return 0; | 848 | return 0; |
841 | } | 849 | } |
@@ -848,7 +856,7 @@ enum { | |||
848 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 856 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
849 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 857 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
850 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 858 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
851 | Opt_obsolate, Opt_flush, Opt_err, | 859 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err, |
852 | }; | 860 | }; |
853 | 861 | ||
854 | static match_table_t fat_tokens = { | 862 | static match_table_t fat_tokens = { |
@@ -883,6 +891,7 @@ static match_table_t fat_tokens = { | |||
883 | {Opt_obsolate, "cvf_options=%100s"}, | 891 | {Opt_obsolate, "cvf_options=%100s"}, |
884 | {Opt_obsolate, "posix"}, | 892 | {Opt_obsolate, "posix"}, |
885 | {Opt_flush, "flush"}, | 893 | {Opt_flush, "flush"}, |
894 | {Opt_tz_utc, "tz=UTC"}, | ||
886 | {Opt_err, NULL}, | 895 | {Opt_err, NULL}, |
887 | }; | 896 | }; |
888 | static match_table_t msdos_tokens = { | 897 | static match_table_t msdos_tokens = { |
@@ -947,6 +956,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
947 | opts->utf8 = opts->unicode_xlate = 0; | 956 | opts->utf8 = opts->unicode_xlate = 0; |
948 | opts->numtail = 1; | 957 | opts->numtail = 1; |
949 | opts->usefree = opts->nocase = 0; | 958 | opts->usefree = opts->nocase = 0; |
959 | opts->tz_utc = 0; | ||
950 | *debug = 0; | 960 | *debug = 0; |
951 | 961 | ||
952 | if (!options) | 962 | if (!options) |
@@ -1036,6 +1046,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1036 | case Opt_flush: | 1046 | case Opt_flush: |
1037 | opts->flush = 1; | 1047 | opts->flush = 1; |
1038 | break; | 1048 | break; |
1049 | case Opt_tz_utc: | ||
1050 | opts->tz_utc = 1; | ||
1051 | break; | ||
1039 | 1052 | ||
1040 | /* msdos specific */ | 1053 | /* msdos specific */ |
1041 | case Opt_dots: | 1054 | case Opt_dots: |