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