1 | // SPDX-License-Identifier: LGPL-2.0+ |
2 | /* Copyright (C) 1993, 1994, 1995, 1996, 1997 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | Contributed by Paul Eggert (eggert@twinsun.com). */ |
5 | |
6 | /* |
7 | * dgb 10/02/98: ripped this from glibc source to help convert timestamps |
8 | * to unix time |
9 | * 10/04/98: added new table-based lookup after seeing how ugly |
10 | * the gnu code is |
11 | * blf 09/27/99: ripped out all the old code and inserted new table from |
12 | * John Brockmeyer (without leap second corrections) |
13 | * rewrote udf_stamp_to_time and fixed timezone accounting in |
14 | * udf_time_to_stamp. |
15 | */ |
16 | |
17 | /* |
18 | * We don't take into account leap seconds. This may be correct or incorrect. |
19 | * For more NIST information (especially dealing with leap seconds), see: |
20 | * http://www.boulder.nist.gov/timefreq/pubs/bulletin/leapsecond.htm |
21 | */ |
22 | |
23 | #include "udfdecl.h" |
24 | |
25 | #include <linux/types.h> |
26 | #include <linux/kernel.h> |
27 | #include <linux/time.h> |
28 | |
29 | void |
30 | udf_disk_stamp_to_time(struct timespec64 *dest, struct timestamp src) |
31 | { |
32 | u16 typeAndTimezone = le16_to_cpu(src.typeAndTimezone); |
33 | u16 year = le16_to_cpu(src.year); |
34 | uint8_t type = typeAndTimezone >> 12; |
35 | int16_t offset; |
36 | |
37 | if (type == 1) { |
38 | offset = typeAndTimezone << 4; |
39 | /* sign extent offset */ |
40 | offset = (offset >> 4); |
41 | if (offset == -2047) /* unspecified offset */ |
42 | offset = 0; |
43 | } else |
44 | offset = 0; |
45 | |
46 | dest->tv_sec = mktime64(year, mon: src.month, day: src.day, hour: src.hour, min: src.minute, |
47 | sec: src.second); |
48 | dest->tv_sec -= offset * 60; |
49 | dest->tv_nsec = 1000 * (src.centiseconds * 10000 + |
50 | src.hundredsOfMicroseconds * 100 + src.microseconds); |
51 | /* |
52 | * Sanitize nanosecond field since reportedly some filesystems are |
53 | * recorded with bogus sub-second values. |
54 | */ |
55 | dest->tv_nsec %= NSEC_PER_SEC; |
56 | } |
57 | |
58 | void |
59 | udf_time_to_disk_stamp(struct timestamp *dest, struct timespec64 ts) |
60 | { |
61 | time64_t seconds; |
62 | int16_t offset; |
63 | struct tm tm; |
64 | |
65 | offset = -sys_tz.tz_minuteswest; |
66 | |
67 | dest->typeAndTimezone = cpu_to_le16(0x1000 | (offset & 0x0FFF)); |
68 | |
69 | seconds = ts.tv_sec + offset * 60; |
70 | time64_to_tm(totalsecs: seconds, offset: 0, result: &tm); |
71 | dest->year = cpu_to_le16(tm.tm_year + 1900); |
72 | dest->month = tm.tm_mon + 1; |
73 | dest->day = tm.tm_mday; |
74 | dest->hour = tm.tm_hour; |
75 | dest->minute = tm.tm_min; |
76 | dest->second = tm.tm_sec; |
77 | dest->centiseconds = ts.tv_nsec / 10000000; |
78 | dest->hundredsOfMicroseconds = (ts.tv_nsec / 1000 - |
79 | dest->centiseconds * 10000) / 100; |
80 | dest->microseconds = (ts.tv_nsec / 1000 - dest->centiseconds * 10000 - |
81 | dest->hundredsOfMicroseconds * 100); |
82 | } |
83 | |
84 | /* EOF */ |
85 | |