1 //
2 /**************************************************************************************************
3 * IOWOW library
4 *
5 * MIT License
6 *
7 * Copyright (c) 2012-2020 Softmotions Ltd <info@softmotions.com>
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a copy
10 * of this software and associated documentation files (the "Software"), to deal
11 * in the Software without restriction, including without limitation the rights
12 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 * copies of the Software, and to permit persons to whom the Software is
14 * furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included in all
17 * copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 * SOFTWARE.
26 *************************************************************************************************/
27
28 #include "iwcfg.h"
29 #include "log/iwlog.h"
30 #include "platform/iwp.h"
31 #include "utils/iwutils.h"
32
33 #include <time.h>
34 #include <math.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 #include <ftw.h>
40
41
42 #ifdef __APPLE__
43 #define st_atim st_atimespec
44 #define st_ctim st_ctimespec
45 #define st_mtim st_mtimespec
46 #endif
47
48 #define _IW_TIMESPEC2MS(IW_ts) (((IW_ts).tv_sec * 1000ULL) + (uint64_t) round((IW_ts).tv_nsec / 1.0e6))
49
50
iwp_clock_get_time(int clock_id,struct timespec * t)51 IW_EXPORT iwrc iwp_clock_get_time(int clock_id, struct timespec *t) {
52 #if (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED < 101200)
53 struct timeval now;
54 int rci = gettimeofday(&now, NULL);
55 if (rci) {
56 return iwrc_set_errno(IW_ERROR_ERRNO, errno);
57 }
58 t->tv_sec = now.tv_sec;
59 t->tv_nsec = now.tv_usec * 1000ULL;
60 #else
61 int rci = clock_gettime(clock_id, t);
62 if (rci) {
63 return iwrc_set_errno(IW_ERROR_ERRNO, errno);
64 }
65 #endif
66 return 0;
67 }
68
iwp_current_time_ms(uint64_t * time,bool monotonic)69 iwrc iwp_current_time_ms(uint64_t *time, bool monotonic) {
70 struct timespec spec;
71 #ifdef IW_HAVE_CLOCK_MONOTONIC
72 iwrc rc = iwp_clock_get_time(monotonic ? CLOCK_MONOTONIC : CLOCK_REALTIME, &spec);
73 #else
74 iwrc rc = iwp_clock_get_time(CLOCK_REALTIME, &spec);
75 #endif
76 if (rc) {
77 *time = 0;
78 return rc;
79 }
80 *time = _IW_TIMESPEC2MS(spec);
81 return 0;
82 }
83
_iwp_fstat(const char * path,HANDLE fd,IWP_FILE_STAT * fs)84 static iwrc _iwp_fstat(const char *path, HANDLE fd, IWP_FILE_STAT *fs) {
85 assert(fs);
86 iwrc rc = 0;
87 struct stat st = {0};
88 memset(fs, 0, sizeof(*fs));
89 if (path) {
90 if (stat(path, &st)) {
91 return (errno == ENOENT) ? IW_ERROR_NOT_EXISTS : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
92 }
93 } else {
94 if (fstat(fd, &st)) {
95 return (errno == ENOENT) ? IW_ERROR_NOT_EXISTS : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
96 }
97 }
98 fs->atime = _IW_TIMESPEC2MS(st.st_atim);
99 fs->mtime = _IW_TIMESPEC2MS(st.st_mtim);
100 fs->ctime = _IW_TIMESPEC2MS(st.st_ctim);
101 fs->size = (uint64_t) st.st_size;
102
103 if (S_ISREG(st.st_mode)) {
104 fs->ftype = IWP_TYPE_FILE;
105 } else if (S_ISDIR(st.st_mode)) {
106 fs->ftype = IWP_TYPE_DIR;
107 } else if (S_ISLNK(st.st_mode)) {
108 fs->ftype = IWP_LINK;
109 } else {
110 fs->ftype = IWP_OTHER;
111 }
112 return rc;
113 }
114
iwp_fstat(const char * path,IWP_FILE_STAT * fs)115 iwrc iwp_fstat(const char *path, IWP_FILE_STAT *fs) {
116 return _iwp_fstat(path, 0, fs);
117 }
118
iwp_fstath(HANDLE fh,IWP_FILE_STAT * fs)119 iwrc iwp_fstath(HANDLE fh, IWP_FILE_STAT *fs) {
120 return _iwp_fstat(0, fh, fs);
121 }
122
iwp_flock(HANDLE fh,iwp_lockmode lmode)123 iwrc iwp_flock(HANDLE fh, iwp_lockmode lmode) {
124 if (INVALIDHANDLE(fh)) {
125 return IW_ERROR_INVALID_HANDLE;
126 }
127 if (lmode == IWP_NOLOCK) {
128 return 0;
129 }
130 struct flock lock = {.l_type = (lmode & IWP_WLOCK) ? F_WRLCK : F_RDLCK, .l_whence = SEEK_SET};
131 while (fcntl(fh, (lmode & IWP_NBLOCK) ? F_SETLK : F_SETLKW, &lock) == -1) {
132 if (errno != EINTR) {
133 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
134 }
135 }
136 return 0;
137 }
138
iwp_unlock(HANDLE fh)139 iwrc iwp_unlock(HANDLE fh) {
140 if (INVALIDHANDLE(fh)) {
141 return IW_ERROR_INVALID_HANDLE;
142 }
143 struct flock lock = {.l_type = F_UNLCK, .l_whence = SEEK_SET};
144 while (fcntl(fh, F_SETLKW, &lock) == -1) {
145 if (errno != EINTR) {
146 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
147 }
148 }
149 return 0;
150 }
151
iwp_closefh(HANDLE fh)152 iwrc iwp_closefh(HANDLE fh) {
153 if (INVALIDHANDLE(fh)) {
154 return 0;
155 }
156 if (close(fh) == -1) {
157 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
158 }
159 return 0;
160 }
161
iwp_pread(HANDLE fh,off_t off,void * buf,size_t siz,size_t * sp)162 iwrc iwp_pread(HANDLE fh, off_t off, void *buf, size_t siz, size_t *sp) {
163 if (INVALIDHANDLE(fh)) {
164 return IW_ERROR_INVALID_HANDLE;
165 }
166 if (!buf || !sp) {
167 return IW_ERROR_INVALID_ARGS;
168 }
169 ssize_t rs;
170 again:
171 rs = pread(fh, buf, siz, off);
172 if (rs == -1) {
173 if (errno == EINTR) {
174 goto again;
175 }
176 *sp = 0;
177 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
178 } else {
179 *sp = rs;
180 return 0;
181 }
182 }
183
iwp_read(HANDLE fh,void * buf,size_t count,size_t * sp)184 iwrc iwp_read(HANDLE fh, void *buf, size_t count, size_t *sp) {
185 if (INVALIDHANDLE(fh)) {
186 return IW_ERROR_INVALID_HANDLE;
187 }
188 if (!buf || !sp) {
189 return IW_ERROR_INVALID_ARGS;
190 }
191 ssize_t rs;
192 again:
193 rs = read(fh, buf, count);
194 if (rs == -1) {
195 if (errno == EINTR) {
196 goto again;
197 }
198 *sp = 0;
199 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
200 } else {
201 *sp = rs;
202 return 0;
203 }
204 }
205
iwp_pwrite(HANDLE fh,off_t off,const void * buf,size_t siz,size_t * sp)206 iwrc iwp_pwrite(HANDLE fh, off_t off, const void *buf, size_t siz, size_t *sp) {
207 if (INVALIDHANDLE(fh)) {
208 return IW_ERROR_INVALID_HANDLE;
209 }
210 if (!buf || !sp) {
211 return IW_ERROR_INVALID_ARGS;
212 }
213 ssize_t ws;
214 again:
215 ws = pwrite(fh, buf, siz, off);
216 if (ws == -1) {
217 if (errno == EINTR) {
218 goto again;
219 }
220 *sp = 0;
221 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
222 } else {
223 *sp = ws;
224 return 0;
225 }
226 }
227
iwp_write(HANDLE fh,const void * buf,size_t size)228 iwrc iwp_write(HANDLE fh, const void *buf, size_t size) {
229 if (INVALIDHANDLE(fh)) {
230 return IW_ERROR_INVALID_HANDLE;
231 }
232 const char *rp = buf;
233 do {
234 ssize_t wb = write(fh, rp, size);
235 switch (wb) {
236 case -1:
237 if (errno == EINTR) {
238 continue;
239 }
240 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
241 case 0:
242 break;
243 default:
244 rp += wb;
245 size -= wb;
246 break;
247 }
248 } while (size > 0);
249 return 0;
250 }
251
iwp_lseek(HANDLE fh,off_t offset,iwp_seek_origin origin,off_t * pos)252 iwrc iwp_lseek(HANDLE fh, off_t offset, iwp_seek_origin origin, off_t *pos) {
253 if (pos) {
254 *pos = 0;
255 }
256 if (INVALIDHANDLE(fh)) {
257 return IW_ERROR_INVALID_HANDLE;
258 }
259 int whence = SEEK_SET;
260 if (origin == IWP_SEEK_CUR) {
261 whence = SEEK_CUR;
262 } else if (origin == IWP_SEEK_END) {
263 whence = SEEK_END;
264 }
265 off_t off = lseek(fh, offset, whence);
266 if (off < 0) {
267 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
268 } else {
269 if (pos) {
270 *pos = off;
271 }
272 return 0;
273 }
274 }
275
iwp_page_size(void)276 size_t iwp_page_size(void) {
277 static long int _iwp_pagesize = 0;
278 if (!_iwp_pagesize) {
279 _iwp_pagesize = sysconf(_SC_PAGESIZE);
280 }
281 return (size_t) _iwp_pagesize;
282 }
283
iwp_alloc_unit(void)284 size_t iwp_alloc_unit(void) {
285 return iwp_page_size();
286 }
287
iwp_ftruncate(HANDLE fh,off_t len)288 iwrc iwp_ftruncate(HANDLE fh, off_t len) {
289 int rci = ftruncate(fh, len);
290 return !rci ? 0 : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
291 }
292
iwp_fallocate(HANDLE fh,off_t len)293 iwrc iwp_fallocate(HANDLE fh, off_t len) {
294 #ifndef __APPLE__
295 int rci = posix_fallocate(fh, 0, len);
296 return !rci ? 0 : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
297 #else
298 fstore_t fstore = {
299 .fst_flags = F_ALLOCATECONTIG,
300 .fst_posmode = F_PEOFPOSMODE,
301 .fst_length = len
302 };
303 fcntl(fh, F_PREALLOCATE, &fstore);
304 int rci = ftruncate(fh, len);
305 return !rci ? 0 : iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
306 #endif
307 }
308
iwp_sleep(uint64_t ms)309 iwrc iwp_sleep(uint64_t ms) {
310 iwrc rc = 0;
311 struct timespec req;
312 req.tv_sec = ms / 1000UL;
313 req.tv_nsec = (ms % 1000UL) * 1000UL * 1000UL;
314 if (nanosleep(&req, NULL)) {
315 rc = iwrc_set_errno(IW_ERROR_THREADING_ERRNO, errno);
316 }
317 return rc;
318 }
319
_rmfile(const char * pathname,const struct stat * sbuf,int type,struct FTW * ftwb)320 static int _rmfile(const char *pathname, const struct stat *sbuf, int type, struct FTW *ftwb) {
321 if (remove(pathname) < 0) {
322 perror(pathname);
323 return -1;
324 }
325 return 0;
326 }
327
iwp_removedir(const char * path)328 iwrc iwp_removedir(const char *path) {
329 if (nftw(path, _rmfile, 10, FTW_DEPTH | FTW_MOUNT | FTW_PHYS) < 0) {
330 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
331 }
332 return 0;
333 }
334
iwp_exec_path(char * opath)335 iwrc iwp_exec_path(char *opath) {
336 #ifdef __linux
337 pid_t pid;
338 char path[MAXPATHLEN];
339 char epath[MAXPATHLEN];
340 memset(epath, 0, sizeof(epath));
341 pid = getpid();
342 sprintf(path, "/proc/%d/exe", pid);
343 if (readlink(path, epath, MAXPATHLEN - 1) == -1) {
344 return iwrc_set_errno(IW_ERROR_ERRNO, errno);
345 } else {
346 strncpy(opath, epath, MAXPATHLEN);
347 }
348 return 0;
349 #else
350 // todo
351 return IW_ERROR_NOT_IMPLEMENTED;
352 #endif
353 }
354
iwp_num_cpu_cores()355 uint16_t iwp_num_cpu_cores() {
356 long res = sysconf(_SC_NPROCESSORS_ONLN);
357 return (uint16_t)(res > 0 ? res : 1);
358 }
359
iwp_fsync(HANDLE fh)360 iwrc iwp_fsync(HANDLE fh) {
361 int rci = fsync(fh);
362 return rci ? iwrc_set_errno(IW_ERROR_IO_ERRNO, errno) : 0;
363 }
364
iwp_fdatasync(HANDLE fh)365 iwrc iwp_fdatasync(HANDLE fh) {
366 #ifdef __APPLE__
367 if (fcntl(fh, F_FULLFSYNC) == -1) {
368 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
369 }
370 #else
371 if (fdatasync(fh) == -1) {
372 return iwrc_set_errno(IW_ERROR_IO_ERRNO, errno);
373 }
374 #endif
375 return 0;
376 }
377
iwp_tmpdir(char * out,size_t len)378 size_t iwp_tmpdir(char *out, size_t len) {
379 const char *tdir;
380 #ifdef IW_TMPDIR
381 tdir = IW_TMPDIR;
382 #else
383 tdir = getenv("TMPDIR");
384 if (!tdir) {
385 #ifdef P_tmpdir
386 tdir = P_tmpdir;
387 #else
388 tdir = "/tmp";
389 #endif
390 }
391 #endif
392 size_t tlen = strlen(tdir);
393 size_t nw = MIN(len, tlen);
394 memcpy(out, tdir, nw);
395 return nw;
396 }
397
_iwp_init_impl()398 static iwrc _iwp_init_impl() {
399 iwp_page_size(); // init statics
400 return 0;
401 }
402