• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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