/src/CMake/Utilities/cmlibarchive/libarchive/archive_time.c
Line | Count | Source |
1 | | /*- |
2 | | * Copyright © 2025 ARJANEN Loïc Jean David |
3 | | * All rights reserved. |
4 | | * |
5 | | * Redistribution and use in source and binary forms, with or without |
6 | | * modification, are permitted provided that the following conditions |
7 | | * are met: |
8 | | * 1. Redistributions of source code must retain the above copyright |
9 | | * notice, this list of conditions and the following disclaimer. |
10 | | * 2. Redistributions in binary form must reproduce the above copyright |
11 | | * notice, this list of conditions and the following disclaimer in the |
12 | | * documentation and/or other materials provided with the distribution. |
13 | | * |
14 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR |
15 | | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
16 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
17 | | * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, |
18 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
19 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
20 | | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
21 | | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
22 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
23 | | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
24 | | */ |
25 | | |
26 | | #include "archive_platform.h" |
27 | | |
28 | | #ifdef HAVE_LIMITS_H |
29 | | #include <limits.h> |
30 | | #endif |
31 | | #ifdef HAVE_STDLIB_H |
32 | | #include <stdlib.h> |
33 | | #endif |
34 | | #ifdef HAVE_STRING_H |
35 | | #include <string.h> |
36 | | #endif |
37 | | |
38 | | #include "archive_integer.h" |
39 | | #include "archive_private.h" |
40 | | #include "archive_time_private.h" |
41 | | |
42 | 2.92k | #define NTFS_EPOC_TIME ARCHIVE_LITERAL_ULL(11644473600) |
43 | 6.58k | #define NTFS_TICKS ARCHIVE_LITERAL_ULL(10000000) |
44 | 2.92k | #define NTFS_EPOC_TICKS (NTFS_EPOC_TIME * NTFS_TICKS) |
45 | 0 | #define DOS_MIN_TIME 0x00210000U |
46 | 0 | #define DOS_MAX_TIME 0xff9fbf7dU |
47 | | |
48 | | #if defined(_WIN32) && !defined(__CYGWIN__) |
49 | | #include <winnt.h> |
50 | | /* Windows FILETIME to NTFS time. */ |
51 | | uint64_t |
52 | | FILETIME_to_ntfs(const FILETIME* filetime) |
53 | | { |
54 | | ULARGE_INTEGER utc; |
55 | | utc.HighPart = filetime->dwHighDateTime; |
56 | | utc.LowPart = filetime->dwLowDateTime; |
57 | | return utc.QuadPart; |
58 | | } |
59 | | #endif |
60 | | |
61 | | /* Convert an MSDOS-style date/time into Unix-style time. */ |
62 | | int64_t |
63 | | dos_to_unix(uint32_t dos_time) |
64 | 50.1k | { |
65 | 50.1k | uint16_t msTime, msDate; |
66 | 50.1k | struct tm ts; |
67 | 50.1k | time_t t; |
68 | | |
69 | 50.1k | msTime = (0xFFFF & dos_time); |
70 | 50.1k | msDate = (dos_time >> 16); |
71 | | |
72 | 50.1k | memset(&ts, 0, sizeof(ts)); |
73 | 50.1k | ts.tm_year = ((msDate >> 9) & 0x7f) + 80; /* Years since 1900. */ |
74 | 50.1k | ts.tm_mon = ((msDate >> 5) & 0x0f) - 1; /* Month number. */ |
75 | 50.1k | ts.tm_mday = msDate & 0x1f; /* Day of month. */ |
76 | 50.1k | ts.tm_hour = (msTime >> 11) & 0x1f; |
77 | 50.1k | ts.tm_min = (msTime >> 5) & 0x3f; |
78 | 50.1k | ts.tm_sec = (msTime << 1) & 0x3e; |
79 | 50.1k | ts.tm_isdst = -1; |
80 | 50.1k | t = mktime(&ts); |
81 | 50.1k | return (int64_t)(t == (time_t)-1 ? INT32_MAX : t); |
82 | 50.1k | } |
83 | | |
84 | | /* Convert into MSDOS-style date/time. */ |
85 | | uint32_t |
86 | | unix_to_dos(int64_t unix_time) |
87 | 0 | { |
88 | 0 | struct tm *t; |
89 | 0 | uint32_t dt; |
90 | 0 | time_t ut = unix_time; |
91 | 0 | #if defined(HAVE_LOCALTIME_R) || defined(HAVE_LOCALTIME_S) |
92 | 0 | struct tm tmbuf; |
93 | 0 | #endif |
94 | |
|
95 | 0 | if (sizeof(time_t) < sizeof(int64_t) && (int64_t)ut != unix_time) { |
96 | 0 | ut = (time_t)(unix_time > 0 ? INT32_MAX : INT32_MIN); |
97 | 0 | } |
98 | |
|
99 | | #if defined(HAVE_LOCALTIME_S) |
100 | | t = localtime_s(&tmbuf, &ut) ? NULL : &tmbuf; |
101 | | #elif defined(HAVE_LOCALTIME_R) |
102 | | t = localtime_r(&ut, &tmbuf); |
103 | | #else |
104 | | t = localtime(&ut); |
105 | | #endif |
106 | 0 | dt = 0; |
107 | 0 | if (t != NULL && t->tm_year >= INT_MIN + 80) { |
108 | 0 | const int year = t->tm_year - 80; |
109 | |
|
110 | 0 | if (year & ~0x7f) { |
111 | 0 | dt = year > 0 ? DOS_MAX_TIME : DOS_MIN_TIME; |
112 | 0 | } |
113 | 0 | else { |
114 | 0 | dt += (year & 0x7f) << 9; |
115 | 0 | dt += ((t->tm_mon + 1) & 0x0f) << 5; |
116 | 0 | dt += (t->tm_mday & 0x1f); |
117 | 0 | dt <<= 16; |
118 | 0 | dt += (t->tm_hour & 0x1f) << 11; |
119 | 0 | dt += (t->tm_min & 0x3f) << 5; |
120 | | /* Only counting every 2 seconds. */ |
121 | 0 | dt += (t->tm_sec & 0x3e) >> 1; |
122 | 0 | } |
123 | 0 | } |
124 | 0 | if (dt > DOS_MAX_TIME) { |
125 | 0 | dt = DOS_MAX_TIME; |
126 | 0 | } |
127 | 0 | else if (dt < DOS_MIN_TIME) { |
128 | 0 | dt = DOS_MIN_TIME; |
129 | 0 | } |
130 | 0 | return dt; |
131 | 0 | } |
132 | | |
133 | | /* Convert NTFS time to Unix sec/nsec */ |
134 | | void |
135 | | ntfs_to_unix(uint64_t ntfs, int64_t* secs, uint32_t* nsecs) |
136 | 2.92k | { |
137 | 2.92k | if (ntfs > INT64_MAX) { |
138 | 726 | ntfs -= NTFS_EPOC_TICKS; |
139 | 726 | *secs = ntfs / NTFS_TICKS; |
140 | 726 | *nsecs = 100 * (ntfs % NTFS_TICKS); |
141 | 726 | } |
142 | 2.20k | else { |
143 | 2.20k | lldiv_t tdiv; |
144 | 2.20k | int64_t value = (int64_t)ntfs - (int64_t)NTFS_EPOC_TICKS; |
145 | | |
146 | 2.20k | tdiv = lldiv(value, NTFS_TICKS); |
147 | 2.20k | *secs = tdiv.quot; |
148 | 2.20k | *nsecs = (uint32_t)(tdiv.rem * 100); |
149 | 2.20k | } |
150 | 2.92k | } |
151 | | |
152 | | /* Convert Unix sec/nsec to NTFS time */ |
153 | | uint64_t |
154 | | unix_to_ntfs(int64_t secs, uint32_t nsecs) |
155 | 0 | { |
156 | 0 | uint64_t ntfs; |
157 | |
|
158 | 0 | if (secs < -(int64_t)NTFS_EPOC_TIME) |
159 | 0 | return 0; |
160 | | |
161 | | /* (secs + NTFS_EPOC_TIME) * NTFS_TICKS + nsecs / 100 */ |
162 | 0 | if (archive_ckd_add_u64(&ntfs, secs, NTFS_EPOC_TIME) || |
163 | 0 | archive_ckd_mul_u64(&ntfs, ntfs, NTFS_TICKS) || |
164 | 0 | archive_ckd_add_u64(&ntfs, ntfs, nsecs / 100)) |
165 | 0 | return UINT64_MAX; |
166 | | |
167 | 0 | return ntfs; |
168 | 0 | } |