2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #if defined(HAVE_NETWORK) || defined(OS_OS2) || defined(OS_WIN32)
20 #include "os_pos_s.inc"
24 static inline bool os_drives_bitmap(uint32_t mask, char **drives, size_t *drives_l, ajla_error_t *err)
27 if (unlikely(!array_init_mayfail(char, drives, drives_l, err)))
31 unsigned bit = low_bit(mask);
32 mask = mask >> bit >> 1;
33 str[2] = os_path_separator();
34 str[0] = bit + shift + 'A';
36 if (unlikely(str[0] > 'Z'))
38 if (unlikely(!array_add_multiple_mayfail(char, drives, drives_l, str, 4, NULL, err)))
45 #if defined(HAVE_NETWORK) || defined(OS_OS2) || defined(OS_WIN32)
47 static int translate_flags(int (*x)(int idx, ajla_error_t *err), int flags, ajla_error_t *err)
51 unsigned lb = 1U << low_bit(flags);
61 static struct sockaddr *os_get_sock_addr(unsigned char *addr, size_t *addr_len, ajla_error_t *err)
66 if (unlikely(*addr_len < 2)) {
67 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_INVALID_OPERATION), err, "too short address");
70 if (unlikely(*addr_len >= SOCKADDR_MAX_LEN)) {
71 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_SIZE_OVERFLOW), err, "too long address");
74 domain = os_socket_af(addr[0] | (addr[1] << 8), err);
75 if (unlikely(domain == -1))
77 padded_len = maximum(*addr_len, sizeof(struct sockaddr));
78 sa = mem_align_mayfail(struct sockaddr *, padded_len, SOCKADDR_ALIGN, err);
81 memset(sa, 0, padded_len);
82 sa->sa_family = domain;
83 memcpy(sa->sa_data, addr + 2, *addr_len - 2);
84 *addr_len = padded_len;
88 static unsigned char *os_get_ajla_addr(struct sockaddr *sa, socklen_t *addr_len, ajla_error_t *err)
92 if (unlikely(*addr_len < 2)) {
93 fatal_mayfail(error_ajla(EC_SYNC, AJLA_ERROR_SYSTEM_RETURNED_INVALID_DATA), err, "too short address");
96 if (sa->sa_family == AF_INET)
97 *addr_len = minimum(*addr_len, 8);
98 domain = os_af_socket(sa->sa_family, err);
99 if (unlikely(domain == -1))
101 addr = mem_alloc_mayfail(unsigned char *, *addr_len, err);
105 addr[1] = domain >> 8;
106 memcpy(addr + 2, sa->sa_data, *addr_len - 2);
114 static const uint8_t month_days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
116 static bool is_leap_year(int year)
118 return !(year % 4) - !(year % 100) + !(year % 400);
122 #define add(x) do { t2 = (uintmax_t)t + (x); if (unlikely(t2 < t)) goto ovf; t = t2; } while (0)
123 #define sub(x) do { t2 = (uintmax_t)t - (x); if (unlikely(t2 > t)) goto ovf; t = t2; } while (0)
124 static time_t my_timegm(struct tm *tm)
128 time_t t = 946684800;
129 int year = (unsigned)tm->tm_year - 100;
130 if (unlikely(year > tm->tm_year))
133 time_t y400 = year / 400;
135 if (unlikely(y400 > signed_maximum(time_t) / 126227808 / 100))
137 add(y400 * 126227808 * 100);
138 for (i = 0; i < year; i++)
139 add((365 + is_leap_year(i)) * 24 * 3600);
141 for (i = 0; i < tm->tm_mon; i++) {
142 add((month_days[i] + (i == 1 && is_leap_year(year))) * 24 * 3600);
144 add((tm->tm_mday - 1) * 24 * 3600);
145 add(tm->tm_hour * 3600);
146 add(tm->tm_min * 60);
149 time_t y400 = (-(unsigned)year / 400);
150 year = -(-(unsigned)year % 400);
151 if (unlikely(y400 > signed_maximum(time_t) / 126227808 / 100))
153 sub(y400 * 126227808 * 100);
154 for (i = -1; i >= year; i--)
155 sub((365 + is_leap_year(400 - i)) * 24 * 3600);
170 #define my_timegm timegm
173 #if (!defined(HAVE_GMTIME_R) && !defined(HAVE_LOCALTIME_R)) || defined(THREAD_NONE)
174 #define HAVE_CALENDAR_LOCK
175 static mutex_t calendar_lock;
178 bool os_time_to_calendar(ajla_time_t t, bool local, int *year, int *month, int *day, int *hour, int *min, int *sec, int *usec, int *yday, int *wday, int *is_dst, ajla_error_t *err)
181 struct tm attr_unused xtm;
188 at = -(-(ajla_utime_t)t / 1000000);
193 if (unlikely(tim != at))
195 #ifdef HAVE_CALENDAR_LOCK
196 mutex_lock(&calendar_lock);
197 tm = local ? localtime(&tim) : gmtime(&tim);
199 tm = local ? localtime_r(&tim, &xtm) : gmtime_r(&tim, &xtm);
203 if (errno == EOVERFLOW)
206 e = error_from_errno(EC_SYSCALL, errno);
207 fatal_mayfail(e, err, "can't convert time: %s", error_decode(e));
208 #ifdef HAVE_CALENDAR_LOCK
209 mutex_unlock(&calendar_lock);
213 *year = tm->tm_year + 1900;
215 *day = tm->tm_mday - 1;
219 *usec = (ajla_utime_t)t - (at * 1000000);
222 *is_dst = tm->tm_isdst;
223 #ifdef HAVE_CALENDAR_LOCK
224 mutex_unlock(&calendar_lock);
229 e = error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE);
230 fatal_mayfail(e, err, "can't convert time: %s", error_decode(e));
234 bool os_calendar_to_time(bool local, int year, int month, int day, int hour, int min, int sec, int usec, int is_dst, ajla_time_t *t, ajla_error_t *err)
241 if (unlikely((int)((unsigned)year - 1900) > year) ||
242 unlikely((unsigned)month >= 12))
244 days = month_days[month];
245 if (month == 1 && is_leap_year(year))
247 if (unlikely((unsigned)day >= days) ||
248 unlikely((unsigned)hour >= 24) ||
249 unlikely((unsigned)min >= 60) ||
250 unlikely((unsigned)sec >= 60) ||
251 unlikely((unsigned)usec >= 1000000))
253 memset(&tm, 0, sizeof(struct tm));
254 tm.tm_year = year - 1900;
256 tm.tm_mday = day + 1;
260 tm.tm_isdst = is_dst;
262 s = local ? mktime(&tm) : my_timegm(&tm);
263 if (unlikely(errno)) {
265 if (errno == EOVERFLOW)
268 e = error_from_errno(EC_SYSCALL, errno);
269 fatal_mayfail(e, err, "can't convert time: %s", error_decode(e));
272 at = (ajla_utime_t)s * 1000000U;
273 if (unlikely((ajla_time_t)at / 1000000 != (ajla_time_t)s) ||
274 unlikely(at + usec < at)) {
282 e = error_ajla(EC_SYNC, AJLA_ERROR_INT_TOO_LARGE);
283 fatal_mayfail(e, err, "can't convert time: %s", error_decode(e));
287 static void os_init_calendar_lock(void)
289 #ifdef HAVE_CALENDAR_LOCK
290 mutex_init(&calendar_lock);
294 static void os_done_calendar_lock(void)
296 #ifdef HAVE_CALENDAR_LOCK
297 mutex_done(&calendar_lock);