+ hfs-hfsplus-follow-macos-time-behavior.patch added to -mm tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



The patch titled
     Subject: hfs/hfsplus: follow MacOS time behavior
has been added to the -mm tree.  Its filename is
     hfs-hfsplus-follow-macos-time-behavior.patch

This patch should soon appear at
    http://ozlabs.org/~akpm/mmots/broken-out/hfs-hfsplus-follow-macos-time-behavior.patch
and later at
    http://ozlabs.org/~akpm/mmotm/broken-out/hfs-hfsplus-follow-macos-time-behavior.patch

Before you just go and hit "reply", please:
   a) Consider who else should be cc'ed
   b) Prefer to cc a suitable mailing list as well
   c) Ideally: find the original patch on the mailing list and do a
      reply-to-all to that, adding suitable additional cc's

*** Remember to use Documentation/process/submit-checklist.rst when testing your code ***

The -mm tree is included into linux-next and is updated
there every 3-4 working days

------------------------------------------------------
From: Arnd Bergmann <arnd@xxxxxxxx>
Subject: hfs/hfsplus: follow MacOS time behavior

According to the official documentation for HFS+ [1], inode timestamps are
supposed to cover the time range from 1904 to 2040 as originally used in
classic MacOS.

The traditional Linux usage is to convert the timestamps into an unsigned
32-bit number based on the Unix epoch and from there to a time_t.  On
32-bit systems, that wraps the time from 2038 to 1902, so the last two
years of the valid time range become garbled.  On 64-bit systems, all
times before 1970 get turned into timestamps between 2038 and 2106, which
is more convenient but also different from the documented behavior.

Looking at the Darwin sources [2], it seems that MacOS is inconsistent in
yet another way: all timestamps are wrapped around to a 32-bit unsigned
number when written to the disk, but when read back, all numeric values
lower than 2082844800U are assumed to be invalid, so we cannot represent
the times before 1970 or the times after 2040.

While all implementations seem to agree on the interpretation of values
between 1970 and 2038, they often differ on the exact range they support
when reading back values outside of the common range:

MacOS (traditional):		1904-2040
Apple Documentation:		1904-2040
MacOS X source comments:	1970-2040
MacOS X source code:		1970-2038
32-bit Linux:			1902-2038
64-bit Linux:			1970-2106
hfsfuse:			1970-2040
hfsutils (32 bit, old libc)	1902-2038
hfsutils (32 bit, new libc)	1970-2106
hfsutils (64 bit)		1904-2040
hfsplus-utils			1904-2040
hfsexplorer			1904-2040
7-zip				1904-2040

This changes Linux over to mostly the same behavior as described in the
code comment in MacOS X, disallowing all times before 1970 and after 2040,
while still allowing times between 2038 and 2040 like most other
implementations do.  Most importantly, it means we can have the same
behavior on 32-bit and 64-bit.

Link: http://lkml.kernel.org/r/20180710214131.4106527-1-arnd@xxxxxxxx
Cc: stable@xxxxxxxxxxxxxxx
Link: [1] https://developer.apple.com/library/archive/technotes/tn/tn1150.html
Link: [2] https://opensource.apple.com/source/hfs/hfs-407.30.1/core/MacOSStubs.c.auto.html
Signed-off-by: Arnd Bergmann <arnd@xxxxxxxx>
Suggested-by: Viacheslav Dubeyko <slava@xxxxxxxxxxx>
Cc: Al Viro <viro@xxxxxxxxxxxxxxxxxx>
Cc: Arnd Bergmann <arnd@xxxxxxxx>
Cc: Deepa Dinamani <deepa.kernel@xxxxxxxxx>
Cc: Jeff Layton <jlayton@xxxxxxxxxx>
Cc: Jan Kara <jack@xxxxxxx>
Cc: "Ernesto A. Fernandez" <ernesto.mnd.fernandez@xxxxxxxxx>
Cc: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx>
---

 fs/hfs/hfs_fs.h         |   29 +++++++++++++++++++++++++----
 fs/hfsplus/hfsplus_fs.h |   26 +++++++++++++++++++++++---
 2 files changed, 48 insertions(+), 7 deletions(-)

diff -puN fs/hfs/hfs_fs.h~hfs-hfsplus-follow-macos-time-behavior fs/hfs/hfs_fs.h
--- a/fs/hfs/hfs_fs.h~hfs-hfsplus-follow-macos-time-behavior
+++ a/fs/hfs/hfs_fs.h
@@ -246,14 +246,35 @@ extern void hfs_mark_mdb_dirty(struct su
  *	mac:	unsigned big-endian since 00:00 GMT, Jan. 1, 1904
  *
  */
-#define __hfs_u_to_mtime(sec)	cpu_to_be32(sec + 2082844800U - sys_tz.tz_minuteswest * 60)
-#define __hfs_m_to_utime(sec)	(be32_to_cpu(sec) - 2082844800U  + sys_tz.tz_minuteswest * 60)
+static inline time64_t __hfs_m_to_utime(__be32 mt)
+{
+	time64_t ut = (u32)(be32_to_cpu(mt) - 2082844800U);
 
+	/*
+	 * Times past 2040-02-06 06:28 are assumed to be invalid,
+	 * matching the MacOS behavior.
+	 */
+	if (ut > 2082844800U + UINT_MAX)
+		ut = 0;
+
+	return ut + sys_tz.tz_minuteswest * 60;
+}
+
+static inline __be32 __hfs_u_to_mtime(time64_t ut)
+{
+	ut -= - sys_tz.tz_minuteswest * 60;
+
+	/*
+	 * MacOS wraps "invalid" times after 2040 when writing back, so
+	 * let's do the same here.
+	 */
+	return cpu_to_be32(lower_32_bits(ut + 2082844800U));
+}
 #define HFS_I(inode)	(container_of(inode, struct hfs_inode_info, vfs_inode))
 #define HFS_SB(sb)	((struct hfs_sb_info *)(sb)->s_fs_info)
 
-#define hfs_m_to_utime(time)	(struct timespec){ .tv_sec = __hfs_m_to_utime(time) }
-#define hfs_u_to_mtime(time)	__hfs_u_to_mtime((time).tv_sec)
+#define hfs_m_to_utime(time)   (struct timespec){ .tv_sec = __hfs_m_to_utime(time) }
+#define hfs_u_to_mtime(time)   __hfs_u_to_mtime((time).tv_sec)
 #define hfs_mtime()		__hfs_u_to_mtime(get_seconds())
 
 static inline const char *hfs_mdb_name(struct super_block *sb)
diff -puN fs/hfsplus/hfsplus_fs.h~hfs-hfsplus-follow-macos-time-behavior fs/hfsplus/hfsplus_fs.h
--- a/fs/hfsplus/hfsplus_fs.h~hfs-hfsplus-follow-macos-time-behavior
+++ a/fs/hfsplus/hfsplus_fs.h
@@ -530,9 +530,29 @@ int hfsplus_submit_bio(struct super_bloc
 		       void **data, int op, int op_flags);
 int hfsplus_read_wrapper(struct super_block *sb);
 
-/* time macros */
-#define __hfsp_mt2ut(t)		(be32_to_cpu(t) - 2082844800U)
-#define __hfsp_ut2mt(t)		(cpu_to_be32(t + 2082844800U))
+/* time helpers */
+static inline time64_t __hfsp_mt2ut(__be32 mt)
+{
+	time64_t ut = (u32)(be32_to_cpu(mt) - 2082844800U);
+
+	/*
+	 * Times past 2040-02-06 06:28 are assumed to be invalid,
+	 * matching the MacOS behavior.
+	 */
+	if (ut > 2082844800U + UINT_MAX)
+		ut = 0;
+
+	return ut;
+}
+
+static inline __be32 __hfsp_ut2mt(time64_t ut)
+{
+	/*
+	 * MacOS wraps "invalid" times after 2040 when writing back, so
+	 * let's do the same here.
+	 */
+	return cpu_to_be32(lower_32_bits(ut + 2082844800U));
+}
 
 /* compatibility */
 #define hfsp_mt2ut(t)		(struct timespec){ .tv_sec = __hfsp_mt2ut(t) }
_

Patches currently in -mm which might be from arnd@xxxxxxxx are

kasan-only-select-slub_debug-with-sysfs=y.patch
firewire-use-64-bit-time_t-based-interfaces.patch
ocfs2-dlmglue-clean-up-timestamp-handling.patch
shmem-use-monotonic-time-for-i_generation.patch
mm-zsmalloc-make-several-functions-and-a-struct-static-fix.patch
procfs-uptime-use-ktime_get_boottime_ts64.patch
crash-print-timestamp-using-time64_t.patch
nilfs2-use-64-bit-superblock-timstamps.patch
hfs-hfsplus-follow-macos-time-behavior.patch
hfs-hfsplus-stop-using-timespec-based-interfaces.patch
reiserfs-use-monotonic-time-for-j_trans_start_time.patch
reiserfs-remove-obsolete-print_time-function.patch
reiserfs-change-j_timestamp-type-to-time64_t.patch
fat-propagate-64-bit-inode-timestamps.patch
adfs-use-timespec64-for-time-conversion.patch
vmcore-hide-vmcoredd_mmap_dumps-for-nommu-builds.patch

--
To unsubscribe from this list: send the line "unsubscribe mm-commits" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Kernel Archive]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux