1/* This file contains functions which implement those POSIX and Linux functions
2 * that MinGW and Microsoft don't provide. The implementations contain just enough
3 * functionality to support fio.
4 */
5
6#include <arpa/inet.h>
7#include <netinet/in.h>
8#include <windows.h>
9#include <stddef.h>
10#include <string.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <dirent.h>
14#include <pthread.h>
15#include <time.h>
16#include <semaphore.h>
17#include <sys/shm.h>
18#include <sys/mman.h>
19#include <sys/uio.h>
20#include <sys/resource.h>
21#include <sys/poll.h>
22#include <sys/wait.h>
23#include <setjmp.h>
24
25#include "../os-windows.h"
26#include "../../lib/hweight.h"
27
28extern unsigned long mtime_since_now(struct timeval *);
29extern void fio_gettime(struct timeval *, void *);
30
31/* These aren't defined in the MinGW headers */
32HRESULT WINAPI StringCchCopyA(
33  char *pszDest,
34  size_t cchDest,
35  const char *pszSrc);
36
37HRESULT WINAPI StringCchPrintfA(
38  char *pszDest,
39  size_t cchDest,
40  const char *pszFormat,
41  ...);
42
43int vsprintf_s(
44  char *buffer,
45  size_t numberOfElements,
46  const char *format,
47  va_list argptr);
48
49int win_to_posix_error(DWORD winerr)
50{
51	switch (winerr)
52	{
53	case ERROR_FILE_NOT_FOUND:		return ENOENT;
54	case ERROR_PATH_NOT_FOUND:		return ENOENT;
55	case ERROR_ACCESS_DENIED:		return EACCES;
56	case ERROR_INVALID_HANDLE:		return EBADF;
57	case ERROR_NOT_ENOUGH_MEMORY:	return ENOMEM;
58	case ERROR_INVALID_DATA:		return EINVAL;
59	case ERROR_OUTOFMEMORY:			return ENOMEM;
60	case ERROR_INVALID_DRIVE:		return ENODEV;
61	case ERROR_NOT_SAME_DEVICE:		return EXDEV;
62	case ERROR_WRITE_PROTECT:		return EROFS;
63	case ERROR_BAD_UNIT:			return ENODEV;
64	case ERROR_SHARING_VIOLATION:	return EACCES;
65	case ERROR_LOCK_VIOLATION:		return EACCES;
66	case ERROR_SHARING_BUFFER_EXCEEDED:	return ENOLCK;
67	case ERROR_HANDLE_DISK_FULL:	return ENOSPC;
68	case ERROR_NOT_SUPPORTED:		return ENOSYS;
69	case ERROR_FILE_EXISTS:			return EEXIST;
70	case ERROR_CANNOT_MAKE:			return EPERM;
71	case ERROR_INVALID_PARAMETER:	return EINVAL;
72	case ERROR_NO_PROC_SLOTS:		return EAGAIN;
73	case ERROR_BROKEN_PIPE:			return EPIPE;
74	case ERROR_OPEN_FAILED:			return EIO;
75	case ERROR_NO_MORE_SEARCH_HANDLES:	return ENFILE;
76	case ERROR_CALL_NOT_IMPLEMENTED:	return ENOSYS;
77	case ERROR_INVALID_NAME:		return ENOENT;
78	case ERROR_WAIT_NO_CHILDREN:	return ECHILD;
79	case ERROR_CHILD_NOT_COMPLETE:	return EBUSY;
80	case ERROR_DIR_NOT_EMPTY:		return ENOTEMPTY;
81	case ERROR_SIGNAL_REFUSED:		return EIO;
82	case ERROR_BAD_PATHNAME:		return ENOENT;
83	case ERROR_SIGNAL_PENDING:		return EBUSY;
84	case ERROR_MAX_THRDS_REACHED:	return EAGAIN;
85	case ERROR_BUSY:				return EBUSY;
86	case ERROR_ALREADY_EXISTS:		return EEXIST;
87	case ERROR_NO_SIGNAL_SENT:		return EIO;
88	case ERROR_FILENAME_EXCED_RANGE:	return EINVAL;
89	case ERROR_META_EXPANSION_TOO_LONG:	return EINVAL;
90	case ERROR_INVALID_SIGNAL_NUMBER:	return EINVAL;
91	case ERROR_THREAD_1_INACTIVE:	return EINVAL;
92	case ERROR_BAD_PIPE:			return EINVAL;
93	case ERROR_PIPE_BUSY:			return EBUSY;
94	case ERROR_NO_DATA:				return EPIPE;
95	case ERROR_MORE_DATA:			return EAGAIN;
96	case ERROR_DIRECTORY:			return ENOTDIR;
97	case ERROR_PIPE_CONNECTED:		return EBUSY;
98	case ERROR_NO_TOKEN:			return EINVAL;
99	case ERROR_PROCESS_ABORTED:		return EFAULT;
100	case ERROR_BAD_DEVICE:			return ENODEV;
101	case ERROR_BAD_USERNAME:		return EINVAL;
102	case ERROR_OPEN_FILES:			return EAGAIN;
103	case ERROR_ACTIVE_CONNECTIONS:	return EAGAIN;
104	case ERROR_DEVICE_IN_USE:		return EAGAIN;
105	case ERROR_INVALID_AT_INTERRUPT_TIME:	return EINTR;
106	case ERROR_IO_DEVICE:			return EIO;
107	case ERROR_NOT_OWNER:			return EPERM;
108	case ERROR_END_OF_MEDIA:		return ENOSPC;
109	case ERROR_EOM_OVERFLOW:		return ENOSPC;
110	case ERROR_BEGINNING_OF_MEDIA:	return ESPIPE;
111	case ERROR_SETMARK_DETECTED:	return ESPIPE;
112	case ERROR_NO_DATA_DETECTED:	return ENOSPC;
113	case ERROR_POSSIBLE_DEADLOCK:	return EDEADLOCK;
114	case ERROR_CRC:					return EIO;
115	case ERROR_NEGATIVE_SEEK:		return EINVAL;
116	case ERROR_DISK_FULL:			return ENOSPC;
117	case ERROR_NOACCESS:			return EFAULT;
118	case ERROR_FILE_INVALID:		return ENXIO;
119	}
120
121	return winerr;
122}
123
124int GetNumLogicalProcessors(void)
125{
126	SYSTEM_LOGICAL_PROCESSOR_INFORMATION *processor_info = NULL;
127	DWORD len = 0;
128	DWORD num_processors = 0;
129	DWORD error = 0;
130	DWORD i;
131
132	while (!GetLogicalProcessorInformation(processor_info, &len)) {
133		error = GetLastError();
134		if (error == ERROR_INSUFFICIENT_BUFFER)
135			processor_info = malloc(len);
136		else {
137			log_err("Error: GetLogicalProcessorInformation failed: %d\n", error);
138			return -1;
139		}
140
141		if (processor_info == NULL) {
142			log_err("Error: failed to allocate memory for GetLogicalProcessorInformation");
143			return -1;
144		}
145	}
146
147	for (i = 0; i < len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); i++)
148	{
149		if (processor_info[i].Relationship == RelationProcessorCore)
150			num_processors += hweight64(processor_info[i].ProcessorMask);
151	}
152
153	free(processor_info);
154	return num_processors;
155}
156
157long sysconf(int name)
158{
159	long val = -1;
160	long val2 = -1;
161	SYSTEM_INFO sysInfo;
162	MEMORYSTATUSEX status;
163
164	switch (name)
165	{
166	case _SC_NPROCESSORS_ONLN:
167		val = GetNumLogicalProcessors();
168		if (val == -1)
169			log_err("sysconf(_SC_NPROCESSORS_ONLN) failed\n");
170
171		break;
172
173	case _SC_PAGESIZE:
174		GetSystemInfo(&sysInfo);
175		val = sysInfo.dwPageSize;
176		break;
177
178	case _SC_PHYS_PAGES:
179		status.dwLength = sizeof(status);
180		val2 = sysconf(_SC_PAGESIZE);
181		if (GlobalMemoryStatusEx(&status) && val2 != -1)
182			val = status.ullTotalPhys / val2;
183		else
184			log_err("sysconf(_SC_PHYS_PAGES) failed\n");
185		break;
186	default:
187		log_err("sysconf(%d) is not implemented\n", name);
188		break;
189	}
190
191	return val;
192}
193
194char *dl_error = NULL;
195
196int dlclose(void *handle)
197{
198	return !FreeLibrary((HMODULE)handle);
199}
200
201void *dlopen(const char *file, int mode)
202{
203	HMODULE hMod;
204
205	hMod = LoadLibrary(file);
206	if (hMod == INVALID_HANDLE_VALUE)
207		dl_error = (char*)"LoadLibrary failed";
208	else
209		dl_error = NULL;
210
211	return hMod;
212}
213
214void *dlsym(void *handle, const char *name)
215{
216	FARPROC fnPtr;
217
218	fnPtr = GetProcAddress((HMODULE)handle, name);
219	if (fnPtr == NULL)
220		dl_error = (char*)"GetProcAddress failed";
221	else
222		dl_error = NULL;
223
224	return fnPtr;
225}
226
227char *dlerror(void)
228{
229	return dl_error;
230}
231
232int gettimeofday(struct timeval *restrict tp, void *restrict tzp)
233{
234	FILETIME fileTime;
235	uint64_t unix_time, windows_time;
236	const uint64_t MILLISECONDS_BETWEEN_1601_AND_1970 = 11644473600000;
237
238	/* Ignore the timezone parameter */
239	(void)tzp;
240
241	/*
242	 * Windows time is stored as the number 100 ns intervals since January 1 1601.
243	 * Conversion details from http://www.informit.com/articles/article.aspx?p=102236&seqNum=3
244	 * Its precision is 100 ns but accuracy is only one clock tick, or normally around 15 ms.
245	 */
246	GetSystemTimeAsFileTime(&fileTime);
247	windows_time = ((uint64_t)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
248	/* Divide by 10,000 to convert to ms and subtract the time between 1601 and 1970 */
249	unix_time = (((windows_time)/10000) - MILLISECONDS_BETWEEN_1601_AND_1970);
250	/* unix_time is now the number of milliseconds since 1970 (the Unix epoch) */
251	tp->tv_sec = unix_time / 1000;
252	tp->tv_usec = (unix_time % 1000) * 1000;
253	return 0;
254}
255
256int sigaction(int sig, const struct sigaction *act,
257		struct sigaction *oact)
258{
259	int rc = 0;
260	void (*prev_handler)(int);
261
262	prev_handler = signal(sig, act->sa_handler);
263	if (oact != NULL)
264		oact->sa_handler = prev_handler;
265
266	if (prev_handler == SIG_ERR)
267		rc = -1;
268
269	return rc;
270}
271
272int lstat(const char * path, struct stat * buf)
273{
274	return stat(path, buf);
275}
276
277void *mmap(void *addr, size_t len, int prot, int flags,
278		int fildes, off_t off)
279{
280	DWORD vaProt = 0;
281	void* allocAddr = NULL;
282
283	if (prot & PROT_NONE)
284		vaProt |= PAGE_NOACCESS;
285
286	if ((prot & PROT_READ) && !(prot & PROT_WRITE))
287		vaProt |= PAGE_READONLY;
288
289	if (prot & PROT_WRITE)
290		vaProt |= PAGE_READWRITE;
291
292	if ((flags & MAP_ANON) | (flags & MAP_ANONYMOUS))
293	{
294		allocAddr = VirtualAlloc(addr, len, MEM_COMMIT, vaProt);
295		if (allocAddr == NULL)
296			errno = win_to_posix_error(GetLastError());
297	}
298
299	return allocAddr;
300}
301
302int munmap(void *addr, size_t len)
303{
304	if (!VirtualFree(addr, 0, MEM_RELEASE)) {
305		errno = win_to_posix_error(GetLastError());
306		return -1;
307	}
308
309	return 0;
310}
311
312int fork(void)
313{
314	log_err("%s is not implemented\n", __func__);
315	errno = ENOSYS;
316	return -1;
317}
318
319pid_t setsid(void)
320{
321	log_err("%s is not implemented\n", __func__);
322	errno = ENOSYS;
323	return -1;
324}
325
326static HANDLE log_file = INVALID_HANDLE_VALUE;
327
328void openlog(const char *ident, int logopt, int facility)
329{
330	if (log_file == INVALID_HANDLE_VALUE)
331		log_file = CreateFileA("syslog.txt", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
332}
333
334void closelog(void)
335{
336	CloseHandle(log_file);
337	log_file = INVALID_HANDLE_VALUE;
338}
339
340void syslog(int priority, const char *message, ... /* argument */)
341{
342	va_list v;
343	int len;
344	char *output;
345	DWORD bytes_written;
346
347	if (log_file == INVALID_HANDLE_VALUE) {
348		log_file = CreateFileA("syslog.txt", GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 0, NULL);
349	}
350
351	if (log_file == INVALID_HANDLE_VALUE) {
352		log_err("syslog: failed to open log file\n");
353		return;
354	}
355
356	va_start(v, message);
357	len = _vscprintf(message, v);
358	output = malloc(len + sizeof(char));
359	vsprintf(output, message, v);
360	WriteFile(log_file, output, len, &bytes_written, NULL);
361	va_end(v);
362	free(output);
363}
364
365int kill(pid_t pid, int sig)
366{
367	errno = ESRCH;
368	return -1;
369}
370
371/*
372 * This is assumed to be used only by the network code,
373 * and so doesn't try and handle any of the other cases
374 */
375int fcntl(int fildes, int cmd, ...)
376{
377	/*
378	 * non-blocking mode doesn't work the same as in BSD sockets,
379	 * so ignore it.
380	 */
381#if 0
382	va_list ap;
383	int val, opt, status;
384
385	if (cmd == F_GETFL)
386		return 0;
387	else if (cmd != F_SETFL) {
388		errno = EINVAL;
389		return -1;
390	}
391
392	va_start(ap, 1);
393
394	opt = va_arg(ap, int);
395	if (opt & O_NONBLOCK)
396		val = 1;
397	else
398		val = 0;
399
400	status = ioctlsocket((SOCKET)fildes, opt, &val);
401
402	if (status == SOCKET_ERROR) {
403		errno = EINVAL;
404		val = -1;
405	}
406
407	va_end(ap);
408
409	return val;
410#endif
411return 0;
412}
413
414/*
415 * Get the value of a local clock source.
416 * This implementation supports 2 clocks: CLOCK_MONOTONIC provides high-accuracy
417 * relative time, while CLOCK_REALTIME provides a low-accuracy wall time.
418 */
419int clock_gettime(clockid_t clock_id, struct timespec *tp)
420{
421	int rc = 0;
422
423	if (clock_id == CLOCK_MONOTONIC)
424	{
425		static LARGE_INTEGER freq = {{0,0}};
426		LARGE_INTEGER counts;
427		uint64_t t;
428
429		QueryPerformanceCounter(&counts);
430		if (freq.QuadPart == 0)
431			QueryPerformanceFrequency(&freq);
432
433		tp->tv_sec = counts.QuadPart / freq.QuadPart;
434		/* Get the difference between the number of ns stored
435		 * in 'tv_sec' and that stored in 'counts' */
436		t = tp->tv_sec * freq.QuadPart;
437		t = counts.QuadPart - t;
438		/* 't' now contains the number of cycles since the last second.
439		 * We want the number of nanoseconds, so multiply out by 1,000,000,000
440		 * and then divide by the frequency. */
441		t *= 1000000000;
442		tp->tv_nsec = t / freq.QuadPart;
443	}
444	else if (clock_id == CLOCK_REALTIME)
445	{
446		/* clock_gettime(CLOCK_REALTIME,...) is just an alias for gettimeofday with a
447		 * higher-precision field. */
448		struct timeval tv;
449		gettimeofday(&tv, NULL);
450		tp->tv_sec = tv.tv_sec;
451		tp->tv_nsec = tv.tv_usec * 1000;
452	} else {
453		errno = EINVAL;
454		rc = -1;
455	}
456
457	return rc;
458}
459
460int mlock(const void * addr, size_t len)
461{
462	SIZE_T min, max;
463	BOOL success;
464	HANDLE process = GetCurrentProcess();
465
466	success = GetProcessWorkingSetSize(process, &min, &max);
467	if (!success) {
468		errno = win_to_posix_error(GetLastError());
469		return -1;
470	}
471
472	min += len;
473	max += len;
474	success = SetProcessWorkingSetSize(process, min, max);
475	if (!success) {
476		errno = win_to_posix_error(GetLastError());
477		return -1;
478	}
479
480	success = VirtualLock((LPVOID)addr, len);
481	if (!success) {
482		errno = win_to_posix_error(GetLastError());
483		return -1;
484	}
485
486	return 0;
487}
488
489int munlock(const void * addr, size_t len)
490{
491	BOOL success = VirtualUnlock((LPVOID)addr, len);
492	if (!success) {
493		errno = win_to_posix_error(GetLastError());
494		return -1;
495	}
496
497	return 0;
498}
499
500pid_t waitpid(pid_t pid, int *stat_loc, int options)
501{
502	log_err("%s is not implemented\n", __func__);
503	errno = ENOSYS;
504	return -1;
505}
506
507int usleep(useconds_t useconds)
508{
509	Sleep(useconds / 1000);
510	return 0;
511}
512
513char *basename(char *path)
514{
515	static char name[MAX_PATH];
516	int i;
517
518	if (path == NULL || strlen(path) == 0)
519		return (char*)".";
520
521	i = strlen(path) - 1;
522
523	while (path[i] != '\\' && path[i] != '/' && i >= 0)
524		i--;
525
526	strncpy(name, path + i + 1, MAX_PATH);
527
528	return name;
529}
530
531int fsync(int fildes)
532{
533	HANDLE hFile = (HANDLE)_get_osfhandle(fildes);
534	if (!FlushFileBuffers(hFile)) {
535		errno = win_to_posix_error(GetLastError());
536		return -1;
537	}
538
539	return 0;
540}
541
542int nFileMappings = 0;
543HANDLE fileMappings[1024];
544
545int shmget(key_t key, size_t size, int shmflg)
546{
547	int mapid = -1;
548	uint32_t size_low = size & 0xFFFFFFFF;
549	uint32_t size_high = ((uint64_t)size) >> 32;
550	HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, (PAGE_EXECUTE_READWRITE | SEC_RESERVE), size_high, size_low, NULL);
551	if (hMapping != NULL) {
552		fileMappings[nFileMappings] = hMapping;
553		mapid = nFileMappings;
554		nFileMappings++;
555	} else {
556		errno = ENOSYS;
557	}
558
559	return mapid;
560}
561
562void *shmat(int shmid, const void *shmaddr, int shmflg)
563{
564	void* mapAddr;
565	MEMORY_BASIC_INFORMATION memInfo;
566	mapAddr = MapViewOfFile(fileMappings[shmid], FILE_MAP_ALL_ACCESS, 0, 0, 0);
567	if (mapAddr == NULL) {
568		errno = win_to_posix_error(GetLastError());
569		return (void*)-1;
570	}
571
572	if (VirtualQuery(mapAddr, &memInfo, sizeof(memInfo)) == 0) {
573		errno = win_to_posix_error(GetLastError());
574		return (void*)-1;
575	}
576
577	mapAddr = VirtualAlloc(mapAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE);
578	if (mapAddr == NULL) {
579		errno = win_to_posix_error(GetLastError());
580		return (void*)-1;
581	}
582
583	return mapAddr;
584}
585
586int shmdt(const void *shmaddr)
587{
588	if (!UnmapViewOfFile(shmaddr)) {
589		errno = win_to_posix_error(GetLastError());
590		return -1;
591	}
592
593	return 0;
594}
595
596int shmctl(int shmid, int cmd, struct shmid_ds *buf)
597{
598	if (cmd == IPC_RMID) {
599		fileMappings[shmid] = INVALID_HANDLE_VALUE;
600		return 0;
601	} else {
602		log_err("%s is not implemented\n", __func__);
603	}
604	errno = ENOSYS;
605	return -1;
606}
607
608int setuid(uid_t uid)
609{
610	log_err("%s is not implemented\n", __func__);
611	errno = ENOSYS;
612	return -1;
613}
614
615int setgid(gid_t gid)
616{
617	log_err("%s is not implemented\n", __func__);
618	errno = ENOSYS;
619	return -1;
620}
621
622int nice(int incr)
623{
624	if (incr != 0) {
625		errno = EINVAL;
626		return -1;
627	}
628
629	return 0;
630}
631
632int getrusage(int who, struct rusage *r_usage)
633{
634	const uint64_t SECONDS_BETWEEN_1601_AND_1970 = 11644473600;
635	FILETIME cTime, eTime, kTime, uTime;
636	time_t time;
637	HANDLE h;
638
639	memset(r_usage, 0, sizeof(*r_usage));
640
641	if (who == RUSAGE_SELF) {
642		h = GetCurrentProcess();
643		GetProcessTimes(h, &cTime, &eTime, &kTime, &uTime);
644	} else if (who == RUSAGE_THREAD) {
645		h = GetCurrentThread();
646		GetThreadTimes(h, &cTime, &eTime, &kTime, &uTime);
647	} else {
648		log_err("fio: getrusage %d is not implemented\n", who);
649		return -1;
650	}
651
652	time = ((uint64_t)uTime.dwHighDateTime << 32) + uTime.dwLowDateTime;
653	/* Divide by 10,000,000 to get the number of seconds and move the epoch from
654	 * 1601 to 1970 */
655	time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970);
656	r_usage->ru_utime.tv_sec = time;
657	/* getrusage() doesn't care about anything other than seconds, so set tv_usec to 0 */
658	r_usage->ru_utime.tv_usec = 0;
659	time = ((uint64_t)kTime.dwHighDateTime << 32) + kTime.dwLowDateTime;
660	/* Divide by 10,000,000 to get the number of seconds and move the epoch from
661	 * 1601 to 1970 */
662	time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970);
663	r_usage->ru_stime.tv_sec = time;
664	r_usage->ru_stime.tv_usec = 0;
665	return 0;
666}
667
668int posix_madvise(void *addr, size_t len, int advice)
669{
670	log_err("%s is not implemented\n", __func__);
671	return ENOSYS;
672}
673
674/* Windows doesn't support advice for memory pages. Just ignore it. */
675int msync(void *addr, size_t len, int flags)
676{
677	errno = ENOSYS;
678	return -1;
679}
680
681int fdatasync(int fildes)
682{
683	return fsync(fildes);
684}
685
686ssize_t pwrite(int fildes, const void *buf, size_t nbyte,
687		off_t offset)
688{
689	int64_t pos = _telli64(fildes);
690	ssize_t len = _write(fildes, buf, nbyte);
691	_lseeki64(fildes, pos, SEEK_SET);
692	return len;
693}
694
695ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset)
696{
697	int64_t pos = _telli64(fildes);
698	ssize_t len = read(fildes, buf, nbyte);
699	_lseeki64(fildes, pos, SEEK_SET);
700	return len;
701}
702
703ssize_t readv(int fildes, const struct iovec *iov, int iovcnt)
704{
705	log_err("%s is not implemented\n", __func__);
706	errno = ENOSYS;
707	return -1;
708}
709
710ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
711{
712	int i;
713	DWORD bytes_written = 0;
714	for (i = 0; i < iovcnt; i++)
715	{
716		int len = send((SOCKET)fildes, iov[i].iov_base, iov[i].iov_len, 0);
717		if (len == SOCKET_ERROR)
718		{
719			DWORD err = GetLastError();
720			errno = win_to_posix_error(err);
721			bytes_written = -1;
722			break;
723		}
724		bytes_written += len;
725	}
726
727	return bytes_written;
728}
729
730long long strtoll(const char *restrict str, char **restrict endptr,
731		int base)
732{
733	return _strtoi64(str, endptr, base);
734}
735
736int poll(struct pollfd fds[], nfds_t nfds, int timeout)
737{
738	struct timeval tv;
739	struct timeval *to = NULL;
740	fd_set readfds, writefds, exceptfds;
741	int i;
742	int rc;
743
744	if (timeout != -1) {
745		to = &tv;
746		to->tv_sec = timeout / 1000;
747		to->tv_usec = (timeout % 1000) * 1000;
748	}
749
750	FD_ZERO(&readfds);
751	FD_ZERO(&writefds);
752	FD_ZERO(&exceptfds);
753
754	for (i = 0; i < nfds; i++)
755	{
756		if (fds[i].fd < 0) {
757			fds[i].revents = 0;
758			continue;
759		}
760
761		if (fds[i].events & POLLIN)
762			FD_SET(fds[i].fd, &readfds);
763
764		if (fds[i].events & POLLOUT)
765			FD_SET(fds[i].fd, &writefds);
766
767		FD_SET(fds[i].fd, &exceptfds);
768	}
769	rc = select(nfds, &readfds, &writefds, &exceptfds, to);
770
771	if (rc != SOCKET_ERROR) {
772		for (i = 0; i < nfds; i++)
773		{
774			if (fds[i].fd < 0) {
775				continue;
776			}
777
778			if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds))
779				fds[i].revents |= POLLIN;
780
781			if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds))
782				fds[i].revents |= POLLOUT;
783
784			if (FD_ISSET(fds[i].fd, &exceptfds))
785				fds[i].revents |= POLLHUP;
786		}
787	}
788	return rc;
789}
790
791int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
792{
793	struct timeval tv;
794	DWORD ms_remaining;
795	DWORD ms_total = (rqtp->tv_sec * 1000) + (rqtp->tv_nsec / 1000000.0);
796
797	if (ms_total == 0)
798		ms_total = 1;
799
800	ms_remaining = ms_total;
801
802	/* Since Sleep() can sleep for less than the requested time, add a loop to
803	   ensure we only return after the requested length of time has elapsed */
804	do {
805		fio_gettime(&tv, NULL);
806		Sleep(ms_remaining);
807		ms_remaining = ms_total - mtime_since_now(&tv);
808	} while (ms_remaining > 0 && ms_remaining < ms_total);
809
810	/* this implementation will never sleep for less than the requested time */
811	if (rmtp != NULL) {
812		rmtp->tv_sec = 0;
813		rmtp->tv_nsec = 0;
814	}
815
816	return 0;
817}
818
819DIR *opendir(const char *dirname)
820{
821	struct dirent_ctx *dc = NULL;
822
823	/* See if we can open it. If not, we'll return an error here */
824	HANDLE file = CreateFileA(dirname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
825	if (file != INVALID_HANDLE_VALUE) {
826		CloseHandle(file);
827		dc = (struct dirent_ctx*)malloc(sizeof(struct dirent_ctx));
828		StringCchCopyA(dc->dirname, MAX_PATH, dirname);
829		dc->find_handle = INVALID_HANDLE_VALUE;
830	} else {
831		DWORD error = GetLastError();
832		if (error == ERROR_FILE_NOT_FOUND)
833			errno = ENOENT;
834
835		else if (error == ERROR_PATH_NOT_FOUND)
836			errno = ENOTDIR;
837		else if (error == ERROR_TOO_MANY_OPEN_FILES)
838			errno = ENFILE;
839		else if (error == ERROR_ACCESS_DENIED)
840			errno = EACCES;
841		else
842			errno = error;
843	}
844
845	return dc;
846}
847
848int closedir(DIR *dirp)
849{
850	if (dirp != NULL && dirp->find_handle != INVALID_HANDLE_VALUE)
851		FindClose(dirp->find_handle);
852
853	free(dirp);
854	return 0;
855}
856
857struct dirent *readdir(DIR *dirp)
858{
859	static struct dirent de;
860	WIN32_FIND_DATA find_data;
861
862	if (dirp == NULL)
863		return NULL;
864
865	if (dirp->find_handle == INVALID_HANDLE_VALUE) {
866		char search_pattern[MAX_PATH];
867		StringCchPrintfA(search_pattern, MAX_PATH, "%s\\*", dirp->dirname);
868		dirp->find_handle = FindFirstFileA(search_pattern, &find_data);
869		if (dirp->find_handle == INVALID_HANDLE_VALUE)
870			return NULL;
871	} else {
872		if (!FindNextFile(dirp->find_handle, &find_data))
873			return NULL;
874	}
875
876	StringCchCopyA(de.d_name, MAX_PATH, find_data.cFileName);
877	de.d_ino = 0;
878
879	return &de;
880}
881
882uid_t geteuid(void)
883{
884	log_err("%s is not implemented\n", __func__);
885	errno = ENOSYS;
886	return -1;
887}
888
889in_addr_t inet_network(const char *cp)
890{
891	in_addr_t hbo;
892	in_addr_t nbo = inet_addr(cp);
893	hbo = ((nbo & 0xFF) << 24) + ((nbo & 0xFF00) << 8) + ((nbo & 0xFF0000) >> 8) + ((nbo & 0xFF000000) >> 24);
894	return hbo;
895}
896
897const char* inet_ntop(int af, const void *restrict src,
898		char *restrict dst, socklen_t size)
899{
900	INT status = SOCKET_ERROR;
901	WSADATA wsd;
902	char *ret = NULL;
903
904	if (af != AF_INET && af != AF_INET6) {
905		errno = EAFNOSUPPORT;
906		return NULL;
907	}
908
909	WSAStartup(MAKEWORD(2,2), &wsd);
910
911	if (af == AF_INET) {
912		struct sockaddr_in si;
913		DWORD len = size;
914		memset(&si, 0, sizeof(si));
915		si.sin_family = af;
916		memcpy(&si.sin_addr, src, sizeof(si.sin_addr));
917		status = WSAAddressToString((struct sockaddr*)&si, sizeof(si), NULL, dst, &len);
918	} else if (af == AF_INET6) {
919		struct sockaddr_in6 si6;
920		DWORD len = size;
921		memset(&si6, 0, sizeof(si6));
922		si6.sin6_family = af;
923		memcpy(&si6.sin6_addr, src, sizeof(si6.sin6_addr));
924		status = WSAAddressToString((struct sockaddr*)&si6, sizeof(si6), NULL, dst, &len);
925	}
926
927	if (status != SOCKET_ERROR)
928		ret = dst;
929	else
930		errno = ENOSPC;
931
932	WSACleanup();
933
934	return ret;
935}
936
937int inet_pton(int af, const char *restrict src, void *restrict dst)
938{
939	INT status = SOCKET_ERROR;
940	WSADATA wsd;
941	int ret = 1;
942
943	if (af != AF_INET && af != AF_INET6) {
944		errno = EAFNOSUPPORT;
945		return -1;
946	}
947
948	WSAStartup(MAKEWORD(2,2), &wsd);
949
950	if (af == AF_INET) {
951		struct sockaddr_in si;
952		INT len = sizeof(si);
953		memset(&si, 0, sizeof(si));
954		si.sin_family = af;
955		status = WSAStringToAddressA((char*)src, af, NULL, (struct sockaddr*)&si, &len);
956		if (status != SOCKET_ERROR)
957			memcpy(dst, &si.sin_addr, sizeof(si.sin_addr));
958	} else if (af == AF_INET6) {
959		struct sockaddr_in6 si6;
960		INT len = sizeof(si6);
961		memset(&si6, 0, sizeof(si6));
962		si6.sin6_family = af;
963		status = WSAStringToAddressA((char*)src, af, NULL, (struct sockaddr*)&si6, &len);
964		if (status != SOCKET_ERROR)
965			memcpy(dst, &si6.sin6_addr, sizeof(si6.sin6_addr));
966	}
967
968	if (status == SOCKET_ERROR) {
969		errno = ENOSPC;
970		ret = 0;
971	}
972
973	WSACleanup();
974
975	return ret;
976}
977