1 //
2 /**************************************************************************************************
3 * IOWOW library
4 *
5 * MIT License
6 *
7 * Copyright (c) 2012-2022 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
29 #include "log/iwlog.h"
30 #include "platform/iwp.h"
31 #include "utils/iwutils.h"
32 #include "utils/iwuuid.h"
33 #include <stdio.h>
34
35 #if defined(_WIN32)
36 #include <libiberty/libiberty.h>
37 #include <direct.h>
38 #else
39 #include <libgen.h>
40 #endif
41
42 #include <string.h>
43
44 unsigned int iwcpuflags = 0;
45 static iwrc _iwp_init_impl(void);
46
47 #if defined(__linux) || defined(__unix) || defined(__APPLE__)
48 #include "unix/unix.c"
49 #elif defined(_WIN32)
50 #include "win32/win32.c"
51 #else
52 #error Unsupported platform
53 #endif
54
55 // Thanks to https://attractivechaos.wordpress.com/2017/09/04/on-cpu-dispatch
x86_simd(void)56 static unsigned int x86_simd(void) {
57 #if defined(__i386__) || defined(__amd64__)
58 unsigned int eax, ebx, ecx, edx, flag = 0;
59 # ifdef _MSC_VER
60 int cpuid[4];
61 __cpuid(cpuid, 1);
62 eax = cpuid[0], ebx = cpuid[1], ecx = cpuid[2], edx = cpuid[3];
63 # else
64 __asm volatile ("cpuid" : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) : "a" (1));
65 # endif
66 if (edx >> 25 & 1) {
67 flag |= IWCPU_SSE;
68 }
69 if (edx >> 26 & 1) {
70 flag |= IWCPU_SSE2;
71 }
72 if (ecx >> 0 & 1) {
73 flag |= IWCPU_SSE3;
74 }
75 if (ecx >> 19 & 1) {
76 flag |= IWCPU_SSE4_1;
77 }
78 if (ecx >> 20 & 1) {
79 flag |= IWCPU_SSE4_2;
80 }
81 if (ecx >> 28 & 1) {
82 flag |= IWCPU_AVX;
83 }
84 if (ebx >> 5 & 1) {
85 flag |= IWCPU_AVX2;
86 }
87 if (ebx >> 16 & 1) {
88 flag |= IWCPU_AVX512F;
89 }
90 return flag;
91 #else
92 return 0;
93 #endif
94 }
95
iwp_copy_bytes(HANDLE fh,off_t off,size_t siz,off_t noff)96 iwrc iwp_copy_bytes(HANDLE fh, off_t off, size_t siz, off_t noff) {
97 if (INVALIDHANDLE(fh)) {
98 return IW_ERROR_INVALID_HANDLE;
99 }
100 int overlap = IW_RANGES_OVERLAP(off, off + siz, noff, noff + siz);
101 size_t sp, sp2;
102 iwrc rc = 0;
103 off_t pos = 0;
104 uint8_t buf[4096];
105 if (overlap && (noff > off)) {
106 // todo resolve it!!
107 return IW_ERROR_OVERFLOW;
108 }
109 #if !defined(__APPLE__) && !defined(_WIN32)
110 if (siz > sizeof(buf)) {
111 posix_fadvise(fh, off, siz, POSIX_FADV_SEQUENTIAL);
112 }
113 #endif
114 while (pos < siz) {
115 rc = iwp_pread(fh, off + pos, buf, MIN(sizeof(buf), (siz - pos)), &sp);
116 if (rc || !sp) {
117 break;
118 } else {
119 rc = iwp_pwrite(fh, noff + pos, buf, sp, &sp2);
120 pos += sp;
121 if (rc) {
122 break;
123 }
124 if (sp != sp2) {
125 rc = IW_ERROR_INVALID_STATE;
126 break;
127 }
128 }
129 }
130 #if !defined(__APPLE__) && !defined(_WIN32)
131 if (siz > sizeof(buf)) {
132 posix_fadvise(fh, off, siz, POSIX_FADV_NORMAL);
133 }
134 #endif
135 return rc;
136 }
137
iwp_allocate_tmpfile_path(const char * prefix)138 char* iwp_allocate_tmpfile_path(const char *prefix) {
139 size_t plen = prefix ? strlen(prefix) : 0;
140 char tmpdir[PATH_MAX + 1];
141 size_t tlen = iwp_tmpdir(tmpdir, sizeof(tmpdir));
142 if (!tlen) {
143 return 0;
144 }
145 char *res = malloc(tlen + sizeof(IW_PATH_STR) - 1 + plen + IW_UUID_STR_LEN + 1 /*NULL*/);
146 if (!res) {
147 return 0;
148 }
149 char *wp = res;
150 memcpy(wp, tmpdir, tlen);
151 wp += tlen;
152 memcpy(wp, IW_PATH_STR, sizeof(IW_PATH_STR) - 1);
153 wp += sizeof(IW_PATH_STR) - 1;
154 if (plen && prefix) {
155 memcpy(wp, prefix, plen);
156 wp += plen;
157 }
158 iwu_uuid4_fill(wp);
159 wp += IW_UUID_STR_LEN;
160 *wp = 0;
161 return res;
162 }
163
iwp_dirname(char * path)164 char* iwp_dirname(char *path) {
165 return dirname(path);
166 }
167
iwp_basename(char * path)168 char* iwp_basename(char *path) {
169 size_t i;
170 if (!path || !*path) {
171 return ".";
172 }
173 i = strlen(path) - 1;
174 #ifdef _WIN32
175 for ( ; i && (path[i] == '/' || path[i] == '\\'); i--) path[i] = 0;
176 for ( ; i && (path[i - 1] != '/' && path[i - 1] != '\\'); i--);
177 #else
178 for ( ; i && path[i] == '/'; i--) path[i] = 0;
179 for ( ; i && path[i - 1] != '/'; i--);
180 #endif
181 return path + i;
182 }
183
iwp_mkdirs(const char * path)184 iwrc iwp_mkdirs(const char *path) {
185 /* Adapted from http://stackoverflow.com/a/2336245/119527 */
186 iwrc rc = 0;
187 const size_t len = strlen(path);
188 char buf[PATH_MAX];
189 char *p, *ppath = buf;
190
191 errno = 0;
192 /* Copy string so its mutable */
193 if (len >= sizeof(buf)) {
194 ppath = malloc(len + 1);
195 if (!ppath) {
196 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
197 }
198 }
199 memcpy(ppath, path, len + 1);
200
201 /* Iterate the string */
202 for (p = ppath + 1; *p; p++) {
203 #ifdef _WIN32
204 if (*p == '/' || *p == '\\') {
205 #else
206 if (*p == '/') {
207 #endif
208 /* Temporarily truncate */
209 *p = '\0';
210 #if (defined(_WIN32) || defined(__WIN32__))
211 if (_mkdir(_path) != 0) {
212 #else
213 if (mkdir(ppath, S_IRWXU) != 0) {
214 #endif
215 if (errno != EEXIST) {
216 rc = iwrc_set_errno(IW_ERROR_ERRNO, errno);
217 goto finish;
218 }
219 }
220 *p = '/';
221 }
222 }
223 #if (defined(_WIN32) || defined(__WIN32__))
224 if (_mkdir(_path) != 0) {
225 #else
226 if (mkdir(ppath, S_IRWXU) != 0) {
227 #endif
228 if (errno != EEXIST) {
229 rc = iwrc_set_errno(IW_ERROR_ERRNO, errno);
230 goto finish;
231 }
232 }
233
234 finish:
235 if (ppath != buf) {
236 free(ppath);
237 }
238 return rc;
239 }
240
241 iwrc iwp_mkdirs_for_file(const char *path) {
242 char buf[PATH_MAX];
243 char *ppath = buf;
244 const size_t len = strlen(path);
245 if (len >= sizeof(buf)) {
246 ppath = malloc(len + 1);
247 if (!ppath) {
248 return iwrc_set_errno(IW_ERROR_ALLOC, errno);
249 }
250 }
251 memcpy(ppath, path, len + 1);
252 iwp_dirname(ppath);
253 iwrc rc = iwp_mkdirs(ppath);
254 if (ppath != buf) {
255 free(ppath);
256 }
257 return rc;
258 }
259
260 iwrc iwp_init(void) {
261 iwcpuflags = x86_simd();
262 _iwp_init_impl();
263 return 0;
264 }
265