xref: /OK3568_Linux_fs/kernel/fs/udf/udftime.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
2*4882a593Smuzhiyun    This file is part of the GNU C Library.
3*4882a593Smuzhiyun    Contributed by Paul Eggert (eggert@twinsun.com).
4*4882a593Smuzhiyun 
5*4882a593Smuzhiyun    The GNU C Library is free software; you can redistribute it and/or
6*4882a593Smuzhiyun    modify it under the terms of the GNU Library General Public License as
7*4882a593Smuzhiyun    published by the Free Software Foundation; either version 2 of the
8*4882a593Smuzhiyun    License, or (at your option) any later version.
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun    The GNU C Library is distributed in the hope that it will be useful,
11*4882a593Smuzhiyun    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*4882a593Smuzhiyun    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13*4882a593Smuzhiyun    Library General Public License for more details.
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun    You should have received a copy of the GNU Library General Public
16*4882a593Smuzhiyun    License along with the GNU C Library; see the file COPYING.LIB.  If not,
17*4882a593Smuzhiyun    write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18*4882a593Smuzhiyun    Boston, MA 02111-1307, USA.  */
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun /*
21*4882a593Smuzhiyun  * dgb 10/02/98: ripped this from glibc source to help convert timestamps
22*4882a593Smuzhiyun  *               to unix time
23*4882a593Smuzhiyun  *     10/04/98: added new table-based lookup after seeing how ugly
24*4882a593Smuzhiyun  *               the gnu code is
25*4882a593Smuzhiyun  * blf 09/27/99: ripped out all the old code and inserted new table from
26*4882a593Smuzhiyun  *		 John Brockmeyer (without leap second corrections)
27*4882a593Smuzhiyun  *		 rewrote udf_stamp_to_time and fixed timezone accounting in
28*4882a593Smuzhiyun  *		 udf_time_to_stamp.
29*4882a593Smuzhiyun  */
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun /*
32*4882a593Smuzhiyun  * We don't take into account leap seconds. This may be correct or incorrect.
33*4882a593Smuzhiyun  * For more NIST information (especially dealing with leap seconds), see:
34*4882a593Smuzhiyun  * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm
35*4882a593Smuzhiyun  */
36*4882a593Smuzhiyun 
37*4882a593Smuzhiyun #include "udfdecl.h"
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun #include <linux/types.h>
40*4882a593Smuzhiyun #include <linux/kernel.h>
41*4882a593Smuzhiyun #include <linux/time.h>
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun void
udf_disk_stamp_to_time(struct timespec64 * dest,struct timestamp src)44*4882a593Smuzhiyun udf_disk_stamp_to_time(struct timespec64 *dest, struct timestamp src)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone);
47*4882a593Smuzhiyun 	u16 year = le16_to_cpu(src.year);
48*4882a593Smuzhiyun 	uint8_t type = typeAndTimezone >> 12;
49*4882a593Smuzhiyun 	int16_t offset;
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun 	if (type == 1) {
52*4882a593Smuzhiyun 		offset = typeAndTimezone << 4;
53*4882a593Smuzhiyun 		/* sign extent offset */
54*4882a593Smuzhiyun 		offset = (offset >> 4);
55*4882a593Smuzhiyun 		if (offset == -2047) /* unspecified offset */
56*4882a593Smuzhiyun 			offset = 0;
57*4882a593Smuzhiyun 	} else
58*4882a593Smuzhiyun 		offset = 0;
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun 	dest->tv_sec = mktime64(year, src.month, src.day, src.hour, src.minute,
61*4882a593Smuzhiyun 			src.second);
62*4882a593Smuzhiyun 	dest->tv_sec -= offset * 60;
63*4882a593Smuzhiyun 	dest->tv_nsec = 1000 * (src.centiseconds * 10000 +
64*4882a593Smuzhiyun 			src.hundredsOfMicroseconds * 100 + src.microseconds);
65*4882a593Smuzhiyun 	/*
66*4882a593Smuzhiyun 	 * Sanitize nanosecond field since reportedly some filesystems are
67*4882a593Smuzhiyun 	 * recorded with bogus sub-second values.
68*4882a593Smuzhiyun 	 */
69*4882a593Smuzhiyun 	dest->tv_nsec %= NSEC_PER_SEC;
70*4882a593Smuzhiyun }
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun void
udf_time_to_disk_stamp(struct timestamp * dest,struct timespec64 ts)73*4882a593Smuzhiyun udf_time_to_disk_stamp(struct timestamp *dest, struct timespec64 ts)
74*4882a593Smuzhiyun {
75*4882a593Smuzhiyun 	time64_t seconds;
76*4882a593Smuzhiyun 	int16_t offset;
77*4882a593Smuzhiyun 	struct tm tm;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	offset = -sys_tz.tz_minuteswest;
80*4882a593Smuzhiyun 
81*4882a593Smuzhiyun 	dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF));
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun 	seconds = ts.tv_sec + offset * 60;
84*4882a593Smuzhiyun 	time64_to_tm(seconds, 0, &tm);
85*4882a593Smuzhiyun 	dest->year = cpu_to_le16(tm.tm_year + 1900);
86*4882a593Smuzhiyun 	dest->month = tm.tm_mon + 1;
87*4882a593Smuzhiyun 	dest->day = tm.tm_mday;
88*4882a593Smuzhiyun 	dest->hour = tm.tm_hour;
89*4882a593Smuzhiyun 	dest->minute = tm.tm_min;
90*4882a593Smuzhiyun 	dest->second = tm.tm_sec;
91*4882a593Smuzhiyun 	dest->centiseconds = ts.tv_nsec / 10000000;
92*4882a593Smuzhiyun 	dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 -
93*4882a593Smuzhiyun 					dest->centiseconds * 10000) / 100;
94*4882a593Smuzhiyun 	dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 -
95*4882a593Smuzhiyun 			      dest->hundredsOfMicroseconds * 100);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun /* EOF */
99