blob: 8739a4c29ee44a0b48858775ff2d7f32d211fa52 [file] [log] [blame] [raw]
/*
Copyright: Boaz segev, 2016-2017
License: MIT except for any non-public-domain algorithms (none that I'm aware
of), which might be subject to their own licenses.
Feel free to copy, use and enjoy in accordance with to the license(s).
*/
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include "misc.h"
/* ***************************************************************************
Other helper functions
*/
#ifdef HAS_UNIX_FEATURES
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
/**
Allocates memory and dumps the whole file into the memory allocated.
Remember to call `free` when done.
Returns the number of bytes allocated. On error, returns 0 and sets the
container pointer to NULL.
This function has some Unix specific properties that resolve links and user
folder referencing.
*/
fdump_s *bscrypt_fdump(const char *file_path, size_t size_limit) {
struct stat f_data;
int file = -1;
fdump_s *container = NULL;
size_t file_path_len;
if (file_path == NULL || (file_path_len = strlen(file_path)) == 0 ||
file_path_len > PATH_MAX)
return NULL;
char real_public_path[PATH_MAX + 1];
real_public_path[PATH_MAX] = 0;
if (file_path[0] == '~' && getenv("HOME") && file_path_len <= PATH_MAX) {
strcpy(real_public_path, getenv("HOME"));
memcpy(real_public_path + strlen(real_public_path), file_path + 1,
file_path_len);
file_path = real_public_path;
}
if (stat(file_path, &f_data))
goto error;
if (size_limit == 0 || (size_t)f_data.st_size < size_limit)
size_limit = f_data.st_size;
container = malloc(size_limit + sizeof(fdump_s) + 1);
if (!container)
goto error;
file = open(file_path, O_RDONLY);
if (file < 0)
goto error;
if (read(file, container->data, size_limit) != (ssize_t)size_limit)
goto error;
close(file);
container->length = size_limit;
container->data[size_limit] = 0;
return container;
error:
if (container)
free(container), (container = NULL);
if (file >= 0)
close(file);
return 0;
}
#endif /* HAS_UNIX_FEATURES */
/**
A faster (yet less localized) alternative to `gmtime_r`.
See the libc `gmtime_r` documentation for details.
Falls back to `gmtime_r` for dates before epoch.
*/
struct tm *bscrypt_gmtime(const time_t *timer, struct tm *tmbuf) {
// static char* DAYS[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"};
// static char * Months = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
// "Jul",
// "Aug", "Sep", "Oct", "Nov", "Dec"};
static uint8_t month_len[] = {
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31, // nonleap year
31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 // leap year
};
if (*timer < 0)
return gmtime_r(timer, tmbuf);
ssize_t tmp;
tmbuf->tm_gmtoff = 0;
tmbuf->tm_zone = "UTC";
tmbuf->tm_isdst = 0;
tmbuf->tm_year = 70; // tm_year == The number of years since 1900
tmbuf->tm_mon = 0;
// for seconds up to weekdays, we build up, as small values clean up larger
// values.
tmp = ((ssize_t)*timer);
tmbuf->tm_sec = tmp % 60;
tmp = tmp / 60;
tmbuf->tm_min = tmp % 60;
tmp = tmp / 60;
tmbuf->tm_hour = tmp % 24;
tmp = tmp / 24;
// day of epoch was a thursday. Add + 3 so sunday == 0...
tmbuf->tm_wday = (tmp + 3) % 7;
// tmp == number of days since epoch
#define DAYS_PER_400_YEARS ((400 * 365) + 97)
while (tmp >= DAYS_PER_400_YEARS) {
tmbuf->tm_year += 400;
tmp -= DAYS_PER_400_YEARS;
}
#undef DAYS_PER_400_YEARS
#define DAYS_PER_100_YEARS ((100 * 365) + 24)
while (tmp >= DAYS_PER_100_YEARS) {
tmbuf->tm_year += 100;
tmp -= DAYS_PER_100_YEARS;
if (((tmbuf->tm_year / 100) & 3) ==
0) // leap century divisable by 400 => add leap
--tmp;
}
#undef DAYS_PER_100_YEARS
#define DAYS_PER_32_YEARS ((32 * 365) + 8)
while (tmp >= DAYS_PER_32_YEARS) {
tmbuf->tm_year += 32;
tmp -= DAYS_PER_32_YEARS;
}
#undef DAYS_PER_32_YEARS
#define DAYS_PER_8_YEARS ((8 * 365) + 2)
while (tmp >= DAYS_PER_8_YEARS) {
tmbuf->tm_year += 8;
tmp -= DAYS_PER_8_YEARS;
}
#undef DAYS_PER_8_YEARS
#define DAYS_PER_4_YEARS ((4 * 365) + 1)
while (tmp >= DAYS_PER_4_YEARS) {
tmbuf->tm_year += 4;
tmp -= DAYS_PER_4_YEARS;
}
#undef DAYS_PER_4_YEARS
while (tmp >= 365) {
tmbuf->tm_year += 1;
tmp -= 365;
if ((tmbuf->tm_year & 3) == 0) { // leap year
if (tmp > 0) {
--tmp;
continue;
} else {
tmp += 365;
--tmbuf->tm_year;
break;
}
}
}
tmbuf->tm_yday = tmp;
if ((tmbuf->tm_year & 3) == 1) {
// regular year
for (size_t i = 0; i < 12; i++) {
if (tmp < month_len[i])
break;
tmp -= month_len[i];
++tmbuf->tm_mon;
}
} else {
// leap year
for (size_t i = 12; i < 24; i++) {
if (tmp < month_len[i])
break;
tmp -= month_len[i];
++tmbuf->tm_mon;
}
}
tmbuf->tm_mday = tmp;
return tmbuf;
}