svn commit: r190074 - in stable/7/sys: . contrib/pf dev/ath/ath_hal dev/cxgb fs/udf

Andriy Gapon avg at FreeBSD.org
Thu Mar 19 08:49:31 PDT 2009


Author: avg
Date: Thu Mar 19 15:49:30 2009
New Revision: 190074
URL: http://svn.freebsd.org/changeset/base/190074

Log:
  MFC 179060: udf: fix and speedup timestamp calculations
  
  markus and emax are notified
  
  Approved by:	jhb (mentor)

Modified:
  stable/7/sys/   (props changed)
  stable/7/sys/contrib/pf/   (props changed)
  stable/7/sys/dev/ath/ath_hal/   (props changed)
  stable/7/sys/dev/cxgb/   (props changed)
  stable/7/sys/fs/udf/udf_vnops.c

Modified: stable/7/sys/fs/udf/udf_vnops.c
==============================================================================
--- stable/7/sys/fs/udf/udf_vnops.c	Thu Mar 19 15:46:33 2009	(r190073)
+++ stable/7/sys/fs/udf/udf_vnops.c	Thu Mar 19 15:49:30 2009	(r190074)
@@ -188,9 +188,9 @@ udf_open(struct vop_open_args *ap) {
 	return 0;
 }
 
-static int mon_lens[2][12] = {
-	{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
-	{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
+static const int mon_lens[2][12] = {
+	{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
+	{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
 };
 
 static int
@@ -206,25 +206,25 @@ udf_isaleapyear(int year)
 }
 
 /*
- * XXX This is just a rough hack.  Daylight savings isn't calculated and tv_nsec
- * is ignored.
  * Timezone calculation compliments of Julian Elischer <julian at elischer.org>.
  */
 static void
 udf_timetotimespec(struct timestamp *time, struct timespec *t)
 {
-	int i, lpyear, daysinyear, year;
+	int i, lpyear, daysinyear, year, startyear;
 	union {
 		uint16_t	u_tz_offset;
 		int16_t		s_tz_offset;
 	} tz;
 
-	t->tv_nsec = 0;
-
-	/* DirectCD seems to like using bogus year values */
+	/*
+	 * DirectCD seems to like using bogus year values.
+	 * Don't trust time->month as it will be used for an array index.
+	 */
 	year = le16toh(time->year);
-	if (year < 1970) {
+	if (year < 1970 || time->month < 1 || time->month > 12) {
 		t->tv_sec = 0;
+		t->tv_nsec = 0;
 		return;
 	}
 
@@ -232,25 +232,37 @@ udf_timetotimespec(struct timestamp *tim
 	t->tv_sec = time->second;
 	t->tv_sec += time->minute * 60;
 	t->tv_sec += time->hour * 3600;
-	t->tv_sec += time->day * 3600 * 24;
+	t->tv_sec += (time->day - 1) * 3600 * 24;
 
 	/* Calculate the month */
 	lpyear = udf_isaleapyear(year);
-	for (i = 1; i < time->month; i++)
-		t->tv_sec += mon_lens[lpyear][i] * 3600 * 24;
+	t->tv_sec += mon_lens[lpyear][time->month - 1] * 3600 * 24;
 
 	/* Speed up the calculation */
-	if (year > 1979)
+	startyear = 1970;
+	if (year > 2009) {
+		t->tv_sec += 1262304000;
+		startyear += 40;
+	} else if (year > 1999) {
+		t->tv_sec += 946684800;
+		startyear += 30;
+	} else if (year > 1989) {
+		t->tv_sec += 631152000;
+		startyear += 20;
+	} else if (year > 1979) {
 		t->tv_sec += 315532800;
-	if (year > 1989)
-		t->tv_sec += 315619200;
-	if (year > 1999)
-		t->tv_sec += 315532800;
-	for (i = 2000; i < year; i++) {
-		daysinyear = udf_isaleapyear(i) + 365 ;
-		t->tv_sec += daysinyear * 3600 * 24;
+		startyear += 10;
 	}
 
+	daysinyear = (year - startyear) * 365;
+	for (i = startyear; i < year; i++)
+		daysinyear += udf_isaleapyear(i);
+	t->tv_sec += daysinyear * 3600 * 24;
+
+	/* Calculate microseconds */
+	t->tv_nsec = time->centisec * 10000 + time->hund_usec * 100 +
+	    time->usec;
+
 	/*
 	 * Calculate the time zone.  The timezone is 12 bit signed 2's
 	 * complement, so we gotta do some extra magic to handle it right.
@@ -259,7 +271,7 @@ udf_timetotimespec(struct timestamp *tim
 	tz.u_tz_offset &= 0x0fff;
 	if (tz.u_tz_offset & 0x0800)
 		tz.u_tz_offset |= 0xf000;	/* extend the sign to 16 bits */
-	if ((time->type_tz & 0x1000) && (tz.s_tz_offset != -2047))
+	if ((le16toh(time->type_tz) & 0x1000) && (tz.s_tz_offset != -2047))
 		t->tv_sec -= tz.s_tz_offset * 60;
 
 	return;


More information about the svn-src-all mailing list