• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include <io.h>
2 #include <math.h>
3 #include <sys/types.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6 #include <pthread.h>
7 
8 #include "iwcfg.h"
9 
10 #define _NANOSECONDS_PER_TICK   100ULL
11 #define _NANOSECONDS_PER_SECOND 1000000000ULL
12 #define _TICKS_PER_SECOND       10000000ULL
13 #define _TICKS_PER_MILLISECOND  10000ULL
14 #define _SEC_TO_UNIX_EPOCH      11644473600ULL
15 #define _TICKS_TO_UNIX_EPOCH    (_TICKS_PER_SECOND * _SEC_TO_UNIX_EPOCH)
16 #define _TIMESPEC2MS(IW_ts) ((IW_ts).tv_sec * 1000) + (uint64_t) round((IW_ts).tv_nsec / 1.0e6)
17 
_iwp_filetime2ticks(const FILETIME * ft)18 IW_INLINE uint64_t _iwp_filetime2ticks(const FILETIME *ft) {
19   uint64_t ticks = ((uint64_t) ft->dwHighDateTime << 32) + ft->dwLowDateTime;
20   if (ticks < _TICKS_TO_UNIX_EPOCH) {
21     return 0;
22   }
23   ticks -= _TICKS_TO_UNIX_EPOCH;
24   return ticks;
25 }
26 
_iwp_filetime2timespec(const FILETIME * ft,struct timespec * spec)27 IW_INLINE void _iwp_filetime2timespec(const FILETIME *ft, struct timespec *spec) {
28   uint64_t ticks = _iwp_filetime2ticks(ft);
29   spec->tv_sec = ticks / _TICKS_PER_SECOND;
30   spec->tv_nsec = (ticks % _TICKS_PER_SECOND) * _NANOSECONDS_PER_TICK;
31 }
32 
_iwp_filetime2millisecons(const FILETIME * ft)33 IW_INLINE uint64_t _iwp_filetime2millisecons(const FILETIME *ft) {
34   uint64_t ticks = _iwp_filetime2ticks(ft);
35   return ticks / _TICKS_PER_MILLISECOND;
36 }
37 
iwp_clock_get_time(int clock_id,struct timespec * spec)38 iwrc iwp_clock_get_time(int clock_id, struct timespec *spec) {
39   int rci = clock_gettime(clock_id, spec);
40   if (rci) {
41     return iwrc_set_errno(IW_ERROR_ERRNO, errno);
42   }
43   return 0;
44 }
45 
iwp_current_time_ms(uint64_t * time,bool monotonic)46 iwrc iwp_current_time_ms(uint64_t *time, bool monotonic) {
47   FILETIME ft;
48   GetSystemTimeAsFileTime(&ft);
49   *time = _iwp_filetime2millisecons(&ft);
50   return 0;
51 }
52 
iwp_fsync(HANDLE h)53 iwrc iwp_fsync(HANDLE h) {
54   if (INVALIDHANDLE(h)) {
55     return IW_ERROR_INVALID_HANDLE;
56   }
57   if (!FlushFileBuffers(h)) {
58     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
59   }
60   return 0;
61 }
62 
iwp_fdatasync(HANDLE fh)63 iwrc iwp_fdatasync(HANDLE fh) {
64   return iwp_fsync(fh);
65 }
66 
67 static SYSTEM_INFO sysinfo;
68 
_iwp_getsysinfo(void)69 static void _iwp_getsysinfo(void) {
70   GetSystemInfo(&sysinfo);
71 }
72 
iwp_page_size(void)73 size_t iwp_page_size(void) {
74   return sysinfo.dwPageSize;
75 }
76 
iwp_alloc_unit(void)77 size_t iwp_alloc_unit(void) {
78   return sysinfo.dwAllocationGranularity;
79 }
80 
iwp_num_cpu_cores(void)81 uint16_t iwp_num_cpu_cores(void) {
82   return sysinfo.dwNumberOfProcessors;
83 }
84 
iwp_ftruncate(HANDLE fh,off_t len)85 iwrc iwp_ftruncate(HANDLE fh, off_t len) {
86   LARGE_INTEGER size;
87   size.QuadPart = len;
88   if (!SetFilePointerEx(fh, size, NULL, FILE_BEGIN)) {
89     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
90   }
91   if (!SetEndOfFile(fh)) {
92     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
93   }
94   return 0;
95 }
96 
iwp_fallocate(HANDLE fh,off_t len)97 iwrc iwp_fallocate(HANDLE fh, off_t len) {
98   return iwp_ftruncate(fh, len);
99 }
100 
iwp_sleep(uint64_t ms)101 iwrc iwp_sleep(uint64_t ms) {
102   iwrc rc = 0;
103   struct timespec req;
104   req.tv_sec = ms / 1000UL;
105   req.tv_nsec = (ms % 1000UL) * 1000UL * 1000UL;
106   if (nanosleep(&req, NULL)) {
107     rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, errno);
108   }
109   return rc;
110 }
111 
iwp_fstat(const char * path,IWP_FILE_STAT * fs)112 iwrc iwp_fstat(const char *path, IWP_FILE_STAT *fs) {
113   memset(fs, 0, sizeof(*fs));
114   struct stat st = { 0 };
115   if (stat(path, &st)) {
116     return (errno == ENOENT) ? IW_ERROR_NOT_EXISTS : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
117   }
118   fs->atime = 1000ULL * st.st_atime;
119   fs->mtime = 1000ULL * st.st_mtime;
120   fs->ctime = 1000ULL * st.st_ctime;
121   fs->size = st.st_size;
122   if (S_ISREG(st.st_mode)) {
123     fs->ftype = IWP_TYPE_FILE;
124   } else if (S_ISDIR(st.st_mode)) {
125     fs->ftype = IWP_TYPE_DIR;
126   } else {
127     fs->ftype = IWP_OTHER;
128   }
129   return 0;
130 }
131 
iwp_fstath(HANDLE fh,IWP_FILE_STAT * fs)132 iwrc iwp_fstath(HANDLE fh, IWP_FILE_STAT *fs) {
133   memset(fs, 0, sizeof(*fs));
134   BY_HANDLE_FILE_INFORMATION info;
135   if (INVALIDHANDLE(fh)) {
136     return IW_ERROR_INVALID_HANDLE;
137   }
138   if (!GetFileInformationByHandle(fh, &info)) {
139     uint32_t err = GetLastError();
140     if (err == ERROR_FILE_NOT_FOUND) {
141       return IW_ERROR_NOT_EXISTS;
142     }
143     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
144   }
145   fs->atime = _iwp_filetime2millisecons(&info.ftLastAccessTime);
146   fs->ctime = _iwp_filetime2millisecons(&info.ftCreationTime);
147   fs->mtime = _iwp_filetime2millisecons(&info.ftLastWriteTime);
148   ULARGE_INTEGER ul = {
149     .LowPart  = info.nFileSizeLow,
150     .HighPart = info.nFileSizeHigh
151   };
152   fs->size = ul.QuadPart;
153   if (info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
154     fs->ftype = IWP_TYPE_DIR;
155   } else {
156     fs->ftype = IWP_TYPE_FILE;
157   }
158   return 0;
159 }
160 
iwp_closefh(HANDLE fh)161 iwrc iwp_closefh(HANDLE fh) {
162   if (INVALIDHANDLE(fh)) {
163     return 0;
164   }
165   if (!CloseHandle(fh)) {
166     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
167   }
168   return 0;
169 }
170 
iwp_flock(HANDLE fh,iwp_lockmode lmode)171 iwrc iwp_flock(HANDLE fh, iwp_lockmode lmode) {
172   if (INVALIDHANDLE(fh)) {
173     return IW_ERROR_INVALID_HANDLE;
174   }
175   if (lmode == IWP_NOLOCK) {
176     return 0;
177   }
178   DWORD type = 0; /* shared lock with waiting */
179   OVERLAPPED offset = { 0 };
180   if (lmode & IWP_WLOCK) {
181     type = LOCKFILE_EXCLUSIVE_LOCK;
182   }
183   if (lmode & IWP_NBLOCK) {
184     type |= LOCKFILE_FAIL_IMMEDIATELY;
185   }
186   if (!LockFileEx(fh, type, 0, ULONG_MAX, ULONG_MAX, &offset)) {
187     return iwrc_set_werror(IW_ERROR_ERRNO, GetLastError());
188   }
189   return 0;
190 }
191 
iwp_unlock(HANDLE fh)192 iwrc iwp_unlock(HANDLE fh) {
193   if (INVALIDHANDLE(fh)) {
194     return IW_ERROR_INVALID_HANDLE;
195   }
196   OVERLAPPED offset = { 0 };
197   if (!UnlockFileEx(fh, 0, ULONG_MAX, ULONG_MAX, &offset)) {
198     return iwrc_set_werror(IW_ERROR_ERRNO, GetLastError());
199   } else {
200     return 0;
201   }
202 }
203 
iwp_pread(HANDLE fh,off_t off,void * buf,size_t siz,size_t * sp)204 iwrc iwp_pread(HANDLE fh, off_t off, void *buf, size_t siz, size_t *sp) {
205   if (INVALIDHANDLE(fh)) {
206     return IW_ERROR_INVALID_HANDLE;
207   }
208   if (!buf || !sp) {
209     return IW_ERROR_INVALID_ARGS;
210   }
211   DWORD rdb;
212   ULARGE_INTEGER bigint;
213   OVERLAPPED offset = { 0 };
214   bigint.QuadPart = off;
215   offset.Offset = bigint.LowPart;
216   offset.OffsetHigh = bigint.HighPart;
217   if (!ReadFile(fh, buf, siz, &rdb, &offset)) {
218     uint32_t err = GetLastError();
219     if (err == ERROR_HANDLE_EOF) {
220       *sp = rdb;
221       return 0;
222     }
223     *sp = 0;
224     return iwrc_set_werror(IW_ERROR_IO_ERRNO, err);
225   }
226   *sp = rdb;
227   return 0;
228 }
229 
iwp_read(HANDLE fh,void * buf,size_t siz,size_t * sp)230 iwrc iwp_read(HANDLE fh, void *buf, size_t siz, size_t *sp) {
231   if (INVALIDHANDLE(fh)) {
232     return IW_ERROR_INVALID_HANDLE;
233   }
234   if (!buf || !sp) {
235     return IW_ERROR_INVALID_ARGS;
236   }
237   DWORD rdb;
238   if (!ReadFile(fh, buf, siz, &rdb, NULL)) {
239     uint32_t err = GetLastError();
240     if (err == ERROR_HANDLE_EOF) {
241       *sp = rdb;
242       return 0;
243     }
244     *sp = 0;
245     return iwrc_set_werror(IW_ERROR_IO_ERRNO, err);
246   }
247   *sp = rdb;
248   return 0;
249 }
250 
iwp_pwrite(HANDLE fh,off_t off,const void * buf,size_t siz,size_t * sp)251 iwrc iwp_pwrite(HANDLE fh, off_t off, const void *buf, size_t siz, size_t *sp) {
252   if (INVALIDHANDLE(fh)) {
253     return IW_ERROR_INVALID_HANDLE;
254   }
255   if (!buf || !sp) {
256     return IW_ERROR_INVALID_ARGS;
257   }
258   DWORD wrb;
259   ULARGE_INTEGER bigint;
260   OVERLAPPED offset = { 0 };
261   bigint.QuadPart = off;
262   offset.Offset = bigint.LowPart;
263   offset.OffsetHigh = bigint.HighPart;
264   if (!WriteFile(fh, buf, siz, &wrb, &offset)) {
265     *sp = 0;
266     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
267   }
268   *sp = wrb;
269   return 0;
270 }
271 
iwp_write(HANDLE fh,const void * buf,size_t size)272 iwrc iwp_write(HANDLE fh, const void *buf, size_t size) {
273   if (INVALIDHANDLE(fh)) {
274     return IW_ERROR_INVALID_HANDLE;
275   }
276   DWORD written;
277   if (!WriteFile(fh, buf, size, &written, NULL)) {
278     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
279   }
280   return 0;
281 }
282 
iwp_lseek(HANDLE fh,off_t offset,iwp_seek_origin origin,off_t * pos)283 iwrc iwp_lseek(HANDLE fh, off_t offset, iwp_seek_origin origin, off_t *pos) {
284   if (INVALIDHANDLE(fh)) {
285     return IW_ERROR_INVALID_HANDLE;
286   }
287   if (pos) {
288     *pos = 0;
289   }
290   int w;
291   LARGE_INTEGER loff, noff;
292   loff.QuadPart = offset;
293   if (origin == IWP_SEEK_CUR) {
294     w = FILE_CURRENT;
295   } else if (origin == IWP_SEEK_END) {
296     w = FILE_END;
297   } else {
298     w = FILE_BEGIN;
299   }
300   if (!SetFilePointerEx(fh, loff, &noff, w)) {
301     return iwrc_set_werror(IW_ERROR_IO_ERRNO, GetLastError());
302   }
303   if (pos) {
304     *pos = noff.QuadPart;
305   }
306   return 0;
307 }
308 
iwp_set_current_thread_name(const char * name)309 void iwp_set_current_thread_name(const char *name) {
310   pthread_setname_np(pthread_self(), name);
311 }
312 
iwp_tmpdir(char * out,size_t len)313 size_t iwp_tmpdir(char *out, size_t len) {
314   return GetTempPathA(len, out);
315 }
316 
_iwp_init_impl(void)317 static iwrc _iwp_init_impl(void) {
318   _iwp_getsysinfo();
319   return 0;
320 }
321