#include <io.h>
#include <sys/locking.h>
#include <errno.h>
#include <pmemcompat.h>
#include "util.h"
#include "os.h"
#include "out.h"
#define UTF8_BOM "\xEF\xBB\xBF"
int
os_open(const char *pathname, int flags, ...)
{
wchar_t *path = util_toUTF16(pathname);
if (path == NULL)
return -1;
int ret;
if (flags & O_CREAT) {
va_list arg;
va_start(arg, flags);
mode_t mode = va_arg(arg, mode_t);
va_end(arg);
ret = _wopen(path, flags, mode);
} else {
ret = _wopen(path, flags);
}
util_free_UTF16(path);
int orig_errno = errno;
if (ret != -1) {
char bom[3];
if (_read(ret, bom, sizeof(bom)) != 3 ||
memcmp(bom, UTF8_BOM, 3) != 0) {
lseek(ret, 0, SEEK_SET);
}
}
errno = orig_errno;
return ret;
}
int
os_stat(const char *pathname, os_stat_t *buf)
{
wchar_t *path = util_toUTF16(pathname);
if (path == NULL)
return -1;
int ret = _wstat64(path, buf);
util_free_UTF16(path);
return ret;
}
int
os_unlink(const char *pathname)
{
wchar_t *path = util_toUTF16(pathname);
if (path == NULL)
return -1;
int ret = _wunlink(path);
util_free_UTF16(path);
return ret;
}
int
os_access(const char *pathname, int mode)
{
wchar_t *path = util_toUTF16(pathname);
if (path == NULL)
return -1;
int ret = _waccess(path, mode);
util_free_UTF16(path);
return ret;
}
static void
os_skipBOM(FILE *file)
{
if (file == NULL)
return;
int orig_errno = errno;
uint8_t bom[3];
size_t read_num = fread(bom, sizeof(bom[0]), sizeof(bom), file);
if (read_num != ARRAY_SIZE(bom))
goto out;
if (memcmp(bom, UTF8_BOM, ARRAY_SIZE(bom)) != 0) {
fseek(file, 0, SEEK_SET);
}
out:
errno = orig_errno;
}
FILE *
os_fopen(const char *pathname, const char *mode)
{
wchar_t *path = util_toUTF16(pathname);
if (path == NULL)
return NULL;
wchar_t *wmode = util_toUTF16(mode);
if (path == NULL) {
util_free_UTF16(path);
return NULL;
}
FILE *ret = _wfopen(path, wmode);
util_free_UTF16(path);
util_free_UTF16(wmode);
os_skipBOM(ret);
return ret;
}
FILE *
os_fdopen(int fd, const char *mode)
{
FILE *ret = fdopen(fd, mode);
os_skipBOM(ret);
return ret;
}
int
os_chmod(const char *pathname, mode_t mode)
{
wchar_t *path = util_toUTF16(pathname);
if (path == NULL)
return -1;
int ret = _wchmod(path, mode);
util_free_UTF16(path);
return ret;
}
int
os_mkstemp(char *temp)
{
unsigned rnd;
wchar_t *utemp = util_toUTF16(temp);
if (utemp == NULL)
return -1;
wchar_t *path = _wmktemp(utemp);
if (path == NULL) {
util_free_UTF16(utemp);
return -1;
}
wchar_t *npath = Malloc(sizeof(*npath) * wcslen(path) + _MAX_FNAME);
if (npath == NULL) {
util_free_UTF16(utemp);
return -1;
}
wcscpy(npath, path);
util_free_UTF16(utemp);
rand_s(&rnd);
int ret = _snwprintf(npath + wcslen(npath), _MAX_FNAME, L"%u", rnd);
if (ret < 0)
goto out;
ret = _wopen(npath, O_RDWR | O_CREAT | O_EXCL | O_TEMPORARY,
S_IWRITE | S_IREAD);
out:
Free(npath);
return ret;
}
int
os_posix_fallocate(int fd, os_off_t offset, os_off_t len)
{
if (offset < 0 || len <= 0)
return EINVAL;
if (offset + len < offset)
return EFBIG;
int orig_errno = errno;
__int64 current_size = _filelengthi64(fd);
int file_length_errno = errno;
errno = orig_errno;
if (current_size < 0)
return file_length_errno;
__int64 requested_size = offset + len;
if (requested_size <= current_size)
return 0;
return _chsize_s(fd, requested_size);
}
int
os_ftruncate(int fd, os_off_t length)
{
return _chsize_s(fd, length);
}
int
os_flock(int fd, int operation)
{
int flags = 0;
SYSTEM_INFO systemInfo;
GetSystemInfo(&systemInfo);
switch (operation & (OS_LOCK_EX | OS_LOCK_SH | OS_LOCK_UN)) {
case OS_LOCK_EX:
case OS_LOCK_SH:
if (operation & OS_LOCK_NB)
flags = _LK_NBLCK;
else
flags = _LK_LOCK;
break;
case OS_LOCK_UN:
flags = _LK_UNLCK;
break;
default:
errno = EINVAL;
return -1;
}
os_off_t filelen = _filelengthi64(fd);
if (filelen < 0)
return -1;
long len = (filelen > systemInfo.dwPageSize) ?
systemInfo.dwPageSize : (long)filelen;
int res = _locking(fd, flags, len);
if (res != 0 && errno == EACCES)
errno = EWOULDBLOCK;
return res;
}
ssize_t
os_writev(int fd, const struct iovec *iov, int iovcnt)
{
size_t size = 0;
for (int i = 0; i < iovcnt; i++)
size += iov[i].iov_len;
void *buf = malloc(size);
if (buf == NULL)
return ENOMEM;
char *it_buf = buf;
for (int i = 0; i < iovcnt; i++) {
memcpy(it_buf, iov[i].iov_base, iov[i].iov_len);
it_buf += iov[i].iov_len;
}
ssize_t written = 0;
while (size > 0) {
int ret = _write(fd, buf, size >= MAXUINT ?
MAXUINT : (unsigned)size);
if (ret == -1) {
written = -1;
break;
}
written += ret;
size -= ret;
}
free(buf);
return written;
}
#define NSEC_IN_SEC 1000000000ull
#define DELTA_WIN2UNIX (11644473600000000ull)
int
os_clock_gettime(int id, struct timespec *ts)
{
switch (id) {
case CLOCK_MONOTONIC:
{
LARGE_INTEGER time;
LARGE_INTEGER frequency;
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&time);
ts->tv_sec = time.QuadPart / frequency.QuadPart;
ts->tv_nsec = (long)(
(time.QuadPart % frequency.QuadPart) *
NSEC_IN_SEC / frequency.QuadPart);
}
break;
case CLOCK_REALTIME:
{
FILETIME ctime_ft;
GetSystemTimeAsFileTime(&ctime_ft);
ULARGE_INTEGER ctime = {
.HighPart = ctime_ft.dwHighDateTime,
.LowPart = ctime_ft.dwLowDateTime,
};
ts->tv_sec = (ctime.QuadPart - DELTA_WIN2UNIX * 10)
/ 10000000;
ts->tv_nsec = ((ctime.QuadPart - DELTA_WIN2UNIX * 10)
% 10000000) * 100;
}
break;
default:
SetLastError(EINVAL);
return -1;
}
return 0;
}
int
os_setenv(const char *name, const char *value, int overwrite)
{
errno_t err;
if (!overwrite && getenv(name))
return 0;
if ((err = _putenv_s(name, value)) != 0) {
errno = err;
return -1;
}
return 0;
}
int
os_unsetenv(const char *name)
{
errno_t err;
if ((err = _putenv_s(name, "")) != 0) {
errno = err;
return -1;
}
return 0;
}
char *
os_getenv(const char *name)
{
return getenv(name);
}
int
os_rand_r(unsigned *seedp)
{
UNREFERENCED_PARAMETER(seedp);
unsigned part1, part2;
rand_s(&part1);
rand_s(&part2);
return part1 << 16 | part2;
}
const char * const sys_siglist[] = {
"Unknown signal 0",
"Hangup",
"Interrupt",
"Quit",
"Illegal instruction",
"Trace/breakpoint trap",
"Aborted",
"Bus error",
"Floating point exception",
"Killed",
"User defined signal 1",
"Segmentation fault",
"User defined signal 2",
"Broken pipe",
"Alarm clock",
"Terminated",
"Stack fault",
"Child exited",
"Continued",
"Stopped (signal)",
"Stopped",
"Stopped (tty input)",
"Stopped (tty output)",
"Urgent I/O condition",
"CPU time limit exceeded",
"File size limit exceeded",
"Virtual timer expired",
"Profiling timer expired",
"Window changed",
"I/O possible",
"Power failure",
"Bad system call",
"Unknown signal 32"
};
int sys_siglist_size = ARRAYSIZE(sys_siglist);
#define STR_REALTIME_SIGNAL "Real-time signal"
#define STR_UNKNOWN_SIGNAL "Unknown signal"
const char *
os_strsignal(int sig)
{
if (sig >= 0 && sig < ARRAYSIZE(sys_siglist))
return sys_siglist[sig];
else if (sig >= 34 && sig <= 64)
return STR_REALTIME_SIGNAL;
else
return STR_UNKNOWN_SIGNAL;
}