1 #ifndef _WIN32
2 #define _GNU_SOURCE
3 #define _DEFAULT_SOURCE
4 #define _BSD_SOURCE
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <dirent.h>
8 #else
9 #include "vccompat.hpp"
10 #ifdef __MINGW32__
11 #include <dirent.h>
12 #include <fcntl.h>
13 #include <unistd.h>
14 #endif
15 #endif
16
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #include <assert.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <errno.h>
23 #include <string.h>
24
25 #include "pocl.h"
26 #include "pocl_debug.h"
27 #include "pocl_file_util.h"
28
29 #ifdef __ANDROID__
30
31 int pocl_mkstemp(char *path);
32
33 #endif
34
35 /*****************************************************************************/
36
37 int
pocl_rm_rf(const char * path)38 pocl_rm_rf(const char* path)
39 {
40 DIR *d = opendir(path);
41 size_t path_len = strlen(path);
42 int error = -1;
43
44 if(d)
45 {
46 struct dirent *p = readdir(d);
47 error = 0;
48 while (!error && p)
49 {
50 char *buf;
51 if (!strcmp(p->d_name, ".") || !strcmp(p->d_name, ".."))
52 {
53 p = readdir (d);
54 continue;
55 }
56
57 size_t len = path_len + strlen(p->d_name) + 2;
58 buf = malloc(len);
59 if (buf)
60 {
61 struct stat statbuf;
62 snprintf(buf, len, "%s/%s", path, p->d_name);
63
64 if (stat (buf, &statbuf) < 0)
65 POCL_ABORT ("Can't get stat() on %s\n", buf);
66 if (S_ISDIR (statbuf.st_mode))
67 error = pocl_rm_rf (buf);
68 if (S_ISREG (statbuf.st_mode) || S_ISLNK (statbuf.st_mode))
69 error = remove (buf);
70
71 free(buf);
72 }
73 else
74 POCL_ABORT ("out of memory");
75
76 p = readdir(d);
77 }
78 closedir(d);
79
80 if (!error)
81 error = remove (path);
82 }
83 return error;
84 }
85
86
87 int
pocl_mkdir_p(const char * path)88 pocl_mkdir_p (const char* path)
89 {
90 size_t len = strlen (path);
91 if (len >= POCL_FILENAME_LENGTH - 1)
92 {
93 return -1;
94 }
95 if (len <= 1)
96 return -1;
97
98 char path_copy[POCL_FILENAME_LENGTH];
99 memcpy (path_copy, path, len);
100 path_copy[len] = 0;
101
102 for (char *tmp = path_copy + 1; *tmp; tmp++)
103 {
104 if (*tmp == '/')
105 {
106 *tmp = '\0';
107 errno = 0;
108 if (mkdir (path_copy, S_IRWXU) != 0)
109 {
110 if (errno != EEXIST)
111 return -1;
112 }
113 *tmp = '/';
114 }
115 }
116
117 if (mkdir (path_copy, S_IRWXU) != 0)
118 {
119 if (errno != EEXIST)
120 return -1;
121 }
122
123 return 0;
124 }
125
126 int
pocl_remove(const char * path)127 pocl_remove(const char* path)
128 {
129 return remove(path);
130 }
131
132 int
pocl_exists(const char * path)133 pocl_exists(const char* path)
134 {
135 return !access(path, R_OK);
136 }
137
138 int
pocl_touch_file(const char * path)139 pocl_touch_file(const char* path)
140 {
141 FILE *f = fopen(path, "w");
142 if (f)
143 {
144 fclose(f);
145 return 0;
146 }
147 return -1;
148 }
149 /****************************************************************************/
150
151 #define CHUNK_SIZE (2 * 1024 * 1024)
152
153 int
pocl_read_file(const char * path,char ** content,uint64_t * filesize)154 pocl_read_file(const char* path, char** content, uint64_t *filesize)
155 {
156 assert(content);
157 assert(path);
158 assert(filesize);
159 *content = NULL;
160 *filesize = 0;
161
162 /* files in /proc return zero size, while
163 files in /sys return size larger than actual actual content size;
164 this reads the content sequentially. */
165 size_t total_size = 0;
166 size_t actually_read = 0;
167 char *ptr = (char *)malloc (CHUNK_SIZE + 1);
168 if (ptr == NULL)
169 return -1;
170
171 FILE *f = fopen (path, "r");
172 if (f == NULL) {
173 POCL_MSG_ERR ("fopen( %s ) failed\n", path);
174 goto ERROR;
175 }
176
177 do
178 {
179 char *reallocated = (char *)realloc (ptr, (total_size + CHUNK_SIZE + 1));
180 if (reallocated == NULL)
181 goto ERROR;
182 ptr = reallocated;
183
184 actually_read = fread (ptr + total_size, 1, CHUNK_SIZE, f);
185 total_size += actually_read;
186 }
187 while (actually_read == CHUNK_SIZE);
188
189 if (ferror (f))
190 goto ERROR;
191
192 if (fclose (f))
193 goto ERROR;
194
195 /* add an extra NULL character for strings */
196 ptr[total_size] = 0;
197 *content = ptr;
198 *filesize = (uint64_t)total_size;
199 return 0;
200
201 ERROR:
202 free (ptr);
203 return -1;
204 }
205
206 /* Atomic write - with rename() */
207 int
pocl_write_file(const char * path,const char * content,uint64_t count,int append,int dont_rewrite)208 pocl_write_file (const char *path, const char *content, uint64_t count,
209 int append, int dont_rewrite)
210 {
211 assert(path);
212 assert(content);
213 char path2[POCL_FILENAME_LENGTH];
214 int err, fd = -1;
215
216 if (pocl_exists(path))
217 {
218 if (dont_rewrite)
219 {
220 if (!append)
221 return 0;
222 }
223 else
224 {
225 int res = pocl_remove(path);
226 if (res)
227 {
228 POCL_MSG_ERR ("pocl_remove(%s) failed\n", path);
229 return res;
230 }
231 }
232 }
233
234 if (append)
235 {
236 fd = open (path, O_RDWR | O_APPEND | O_CREAT, 0660);
237 err = fd < 0;
238 }
239 else
240 {
241 err = pocl_mk_tempname (path2, path, ".temp", &fd);
242 }
243
244 if (err)
245 {
246 POCL_MSG_ERR ("open(%s) failed\n", path);
247 return -1;
248 }
249
250 ssize_t res = write (fd, content, (size_t)count);
251 if (res < 0 || (size_t)res < (size_t)count)
252 {
253 POCL_MSG_ERR ("write(%s) failed\n", path);
254 return -1;
255 }
256
257 #ifdef HAVE_FDATASYNC
258 if (fdatasync (fd))
259 {
260 POCL_MSG_ERR ("fdatasync() failed\n");
261 return errno;
262 }
263 #elif defined(HAVE_FSYNC)
264 if (fsync (fd))
265 {
266 POCL_MSG_ERR ("fsync() failed\n");
267 return errno;
268 }
269 #endif
270
271 if (close (fd) < 0)
272 return errno;
273
274 if (append)
275 return 0;
276 else
277 return pocl_rename (path2, path);
278 }
279
280 /****************************************************************************/
281
pocl_rename(const char * oldpath,const char * newpath)282 int pocl_rename(const char *oldpath, const char *newpath) {
283 return rename (oldpath, newpath);
284 }
285
286 int
pocl_mk_tempname(char * output,const char * prefix,const char * suffix,int * ret_fd)287 pocl_mk_tempname (char *output, const char *prefix, const char *suffix,
288 int *ret_fd)
289 {
290 #if defined(_WIN32)
291 char buf[256];
292 int ok = GetTempFileName(getenv("TEMP"), prefix, 0, buf);
293 return ok ? 0 : 1;
294 #elif defined(HAVE_MKOSTEMPS) || defined(HAVE_MKSTEMPS) || defined(__ANDROID__)
295 /* using mkstemp() instead of tmpnam() has no real benefit
296 * here, as we have to pass the filename to llvm,
297 * but tmpnam() generates an annoying warning... */
298 int fd;
299
300 strncpy (output, prefix, POCL_FILENAME_LENGTH);
301 size_t len = strlen (prefix);
302 strncpy (output + len, "_XXXXXX", (POCL_FILENAME_LENGTH - len));
303
304 #ifdef __ANDROID__
305 fd = pocl_mkstemp (output);
306 #else
307 if (suffix)
308 {
309 len += 7;
310 strncpy (output + len, suffix, (POCL_FILENAME_LENGTH - len));
311 #ifdef HAVE_MKOSTEMPS
312 fd = mkostemps (output, strlen (suffix), O_CLOEXEC);
313 #else
314 fd = mkstemps (output, strlen (suffix));
315 #endif
316 }
317 else
318 #ifdef HAVE_MKOSTEMPS
319 fd = mkostemp (output, O_CLOEXEC);
320 #else
321 fd = mkstemp (output);
322 #endif
323 #endif
324
325 if (fd < 0)
326 {
327 POCL_MSG_ERR ("mkstemp() failed\n");
328 return errno;
329 }
330
331 int err = 0;
332 if (ret_fd)
333 *ret_fd = fd;
334 else
335 err = close (fd);
336
337 return err ? errno : 0;
338
339 #else
340 #error mkostemps() / mkstemps() both unavailable
341 #endif
342 }
343
344 int
pocl_mk_tempdir(char * output,const char * prefix)345 pocl_mk_tempdir (char *output, const char *prefix)
346 {
347 #if defined(_WIN32)
348 assert (0);
349 #elif defined(HAVE_MKDTEMP)
350 /* TODO mkdtemp() might not be portable outside Linux */
351 strncpy (output, prefix, POCL_FILENAME_LENGTH);
352 size_t len = strlen (prefix);
353 strncpy (output + len, "_XXXXXX", (POCL_FILENAME_LENGTH - len));
354 return (mkdtemp (output) == NULL);
355 #else
356 #error mkdtemp() not available
357 #endif
358 }
359
360 /* write content[count] into a temporary file, and return the tempfile name in
361 * output_path */
362 int
pocl_write_tempfile(char * output_path,const char * prefix,const char * suffix,const char * content,unsigned long count,int * ret_fd)363 pocl_write_tempfile (char *output_path, const char *prefix, const char *suffix,
364 const char *content, unsigned long count, int *ret_fd)
365 {
366 assert (output_path);
367 assert (prefix);
368 assert (suffix);
369 assert (content);
370
371 int fd = -1, err = 0;
372
373 err = pocl_mk_tempname (output_path, prefix, suffix, &fd);
374 if (err)
375 {
376 POCL_MSG_ERR ("pocl_mk_tempname() failed\n");
377 return err;
378 }
379
380 size_t bytes = count;
381 ssize_t res;
382 while (bytes > 0)
383 {
384 res = write (fd, content, bytes);
385 if (res < 0)
386 {
387 POCL_MSG_ERR ("write(%s) failed\n", output_path);
388 return errno;
389 }
390 else
391 {
392 bytes -= res;
393 content += res;
394 }
395 }
396
397 #ifdef HAVE_FDATASYNC
398 if (fdatasync (fd))
399 {
400 POCL_MSG_ERR ("fdatasync() failed\n");
401 return errno;
402 }
403 #elif defined(HAVE_FSYNC)
404 if (fsync (fd))
405 return errno;
406 #endif
407
408 err = 0;
409 if (ret_fd)
410 *ret_fd = fd;
411 else
412 err = close (fd);
413
414 return err ? errno : 0;
415 }
416