On Mon, 6 Aug 2018, Bruce Evans wrote:

...
I forgot about FAT times, and only remembered that utc_offset() was used
for RTC drivers.  I thought that utc_offset() is 0 unless something sets
the timezone to nonzero or the RTC is on local time (wall_cmos_clock case).
However, since the kernel needs the timezone for FAT times, it must be
known even if the RTC is on UTC time.  Now I don't see how FAT times can
even work unless the wall_cmos_clock.  They are just the UTC minus
utc_offset(), where utc_offset() is

        (tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0))

Here wall_cmos_clock is only for managing the RTC offset.  It must be 0
unless the RTC is on local time.  But then either FAT times or RTC times
must be broken except in the Greenwich meridian.  Otherwise, tz_minuteswest
must be nonzero to ajust FAT times right, but this makes utc_offset()
unusable for the RTC offset.

I verified the brokenness:
- adjkerntz() normally leaves tz_minuteswest as 0.  I verified that it does
  this when there is a nonzero dst adjustment.  dst adjustments are folded
  into machdep.adjkerntz.
- when wall_cmos_clock == 0, adjkerntz(8) does little or nothing, so all
  adjustments are 0, so utc_offset() is 0, so FAT times are broken except
  in the Greenwich meridian.

The broken FAT times are not completely obvious, since getting and setting
them use the same wrong offset of 0, so the times appear to be correct when
displayed on FreeBSD.  The are only obviously wrong when displayed on another
system with non-broken FAT times, perhaps by rebooting to the other system
or by moving removable media to such a system.

FAT times are used by other file systems.  I checked this in FreeBSD-9
so as to find axed file systems.  The were used by smbfs, nwfs and msdosfs.
Now they are only used by msdosfs.  I never liked de-deduplicating their
implementation into an over-engineered version with especially excessive
handling for leap years.  Leap year handling is unimportant compared with
offset handling.

tz_minuteswest is used by compatibility code.  It cannot usefully be
removed from the native version, since non-native syscalls use it and
non-native applications might use it.  Of course, it must have a correct
value to work in compatibility.  Its normal value of 0 breaks compatibility
code much like the bugs in utc_offset() breaks FAT time.  It is used in the
following compatibility code:
- amd64 linux32 linux_gettimeofday().  Like native gettimeofday().  It also
  reconstructs the dstflag part of the timezone struct.  If linux drops this,
  then strict compatiility requires the support to depend on the linux version.
- amd64 linux32 linux_settimeofday().  Like native settimeofday().  Has
  invisible reference to tz_minuteswest hidden in assignment of timezones.
  I only grepped for tz_minuteswest and only checked this indirect reference.
- freebsd32 freebsd32_gettimeofday().  Similarly, except we control it, so
  can avoid needing version checks by not dropping support.
- dev/tws/tws_services.h.  This uses utc_offset() for FreeBSD-7 and later,
  and its reference to tz_minuteswest is only explicit for older versions
  where it open-codes utc_offset() with bug for bug compatibility except for
  adding style bugs.
- smbfs.  This uses FAT times, and in nearby code it uses tzoff for the offset
  and has commented-out code with an open-coded fully-buggy utc_offset().
- ibcs2 xenix_ftime().  This is similar to gettimeofday().

Bruce
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to