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