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