Mercurial > mm7
comparison lib/swig/swigwin-2.0.11/CCache/util.c @ 1899:b3009adc0e2f
Adding swig, gitignore, hgignore
author | Nomad |
---|---|
date | Mon, 21 Oct 2013 10:42:27 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
1867:eb580660bbbb | 1899:b3009adc0e2f |
---|---|
1 /* | |
2 Copyright (C) Andrew Tridgell 2002 | |
3 | |
4 This program is free software; you can redistribute it and/or modify | |
5 it under the terms of the GNU General Public License as published by | |
6 the Free Software Foundation; either version 2 of the License, or | |
7 (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, | |
10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 GNU General Public License for more details. | |
13 | |
14 You should have received a copy of the GNU General Public License | |
15 along with this program; if not, write to the Free Software | |
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
17 */ | |
18 | |
19 #include "ccache.h" | |
20 | |
21 static FILE *logfile; | |
22 | |
23 /* log a message to the CCACHE_LOGFILE location */ | |
24 void cc_log(const char *format, ...) | |
25 { | |
26 va_list ap; | |
27 extern char *cache_logfile; | |
28 | |
29 if (!cache_logfile) return; | |
30 | |
31 if (!logfile) logfile = fopen(cache_logfile, "a"); | |
32 if (!logfile) return; | |
33 | |
34 va_start(ap, format); | |
35 vfprintf(logfile, format, ap); | |
36 va_end(ap); | |
37 fflush(logfile); | |
38 } | |
39 | |
40 /* something went badly wrong! */ | |
41 void fatal(const char *msg) | |
42 { | |
43 cc_log("FATAL: %s\n", msg); | |
44 exit(1); | |
45 } | |
46 | |
47 int safe_rename(const char* oldpath, const char* newpath) | |
48 { | |
49 /* safe_rename is for creating entries in the cache. | |
50 | |
51 Works like rename(), but it never overwrites an existing | |
52 cache entry. This avoids corruption on NFS. */ | |
53 #ifndef _WIN32 | |
54 int status = link(oldpath, newpath); | |
55 if( status == 0 || errno == EEXIST ) | |
56 #else | |
57 int status = CreateHardLinkA(newpath, oldpath, NULL) ? 0 : -1; | |
58 if( status == 0 || GetLastError() == ERROR_ALREADY_EXISTS ) | |
59 #endif | |
60 { | |
61 return unlink( oldpath ); | |
62 } | |
63 else | |
64 { | |
65 return -1; | |
66 } | |
67 } | |
68 | |
69 #ifndef ENABLE_ZLIB | |
70 /* copy all data from one file descriptor to another */ | |
71 void copy_fd(int fd_in, int fd_out) | |
72 { | |
73 char buf[10240]; | |
74 int n; | |
75 | |
76 while ((n = read(fd_in, buf, sizeof(buf))) > 0) { | |
77 if (write(fd_out, buf, n) != n) { | |
78 fatal("Failed to copy fd"); | |
79 } | |
80 } | |
81 } | |
82 | |
83 #ifndef HAVE_MKSTEMP | |
84 /* cheap and nasty mkstemp replacement */ | |
85 int mkstemp(char *template) | |
86 { | |
87 mktemp(template); | |
88 return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); | |
89 } | |
90 #endif | |
91 | |
92 /* move a file using rename */ | |
93 int move_file(const char *src, const char *dest) { | |
94 return safe_rename(src, dest); | |
95 } | |
96 | |
97 /* copy a file - used when hard links don't work | |
98 the copy is done via a temporary file and atomic rename | |
99 */ | |
100 static int copy_file(const char *src, const char *dest) | |
101 { | |
102 int fd1, fd2; | |
103 char buf[10240]; | |
104 int n; | |
105 char *tmp_name; | |
106 mode_t mask; | |
107 | |
108 x_asprintf(&tmp_name, "%s.XXXXXX", dest); | |
109 | |
110 fd1 = open(src, O_RDONLY|O_BINARY); | |
111 if (fd1 == -1) { | |
112 free(tmp_name); | |
113 return -1; | |
114 } | |
115 | |
116 fd2 = mkstemp(tmp_name); | |
117 if (fd2 == -1) { | |
118 close(fd1); | |
119 free(tmp_name); | |
120 return -1; | |
121 } | |
122 | |
123 while ((n = read(fd1, buf, sizeof(buf))) > 0) { | |
124 if (write(fd2, buf, n) != n) { | |
125 close(fd2); | |
126 close(fd1); | |
127 unlink(tmp_name); | |
128 free(tmp_name); | |
129 return -1; | |
130 } | |
131 } | |
132 | |
133 close(fd1); | |
134 | |
135 /* get perms right on the tmp file */ | |
136 #ifndef _WIN32 | |
137 mask = umask(0); | |
138 fchmod(fd2, 0666 & ~mask); | |
139 umask(mask); | |
140 #else | |
141 (void)mask; | |
142 #endif | |
143 | |
144 /* the close can fail on NFS if out of space */ | |
145 if (close(fd2) == -1) { | |
146 unlink(tmp_name); | |
147 free(tmp_name); | |
148 return -1; | |
149 } | |
150 | |
151 unlink(dest); | |
152 | |
153 if (rename(tmp_name, dest) == -1) { | |
154 unlink(tmp_name); | |
155 free(tmp_name); | |
156 return -1; | |
157 } | |
158 | |
159 free(tmp_name); | |
160 | |
161 return 0; | |
162 } | |
163 | |
164 /* copy a file to the cache */ | |
165 static int copy_file_to_cache(const char *src, const char *dest) { | |
166 return copy_file(src, dest); | |
167 } | |
168 | |
169 /* copy a file from the cache */ | |
170 static int copy_file_from_cache(const char *src, const char *dest) { | |
171 return copy_file(src, dest); | |
172 } | |
173 | |
174 #else /* ENABLE_ZLIB */ | |
175 | |
176 /* copy all data from one file descriptor to another | |
177 possibly decompressing it | |
178 */ | |
179 void copy_fd(int fd_in, int fd_out) { | |
180 char buf[10240]; | |
181 int n; | |
182 gzFile gz_in; | |
183 | |
184 gz_in = gzdopen(dup(fd_in), "rb"); | |
185 | |
186 if (!gz_in) { | |
187 fatal("Failed to copy fd"); | |
188 } | |
189 | |
190 while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) { | |
191 if (write(fd_out, buf, n) != n) { | |
192 fatal("Failed to copy fd"); | |
193 } | |
194 } | |
195 } | |
196 | |
197 static int _copy_file(const char *src, const char *dest, int mode) { | |
198 int fd_in, fd_out; | |
199 gzFile gz_in, gz_out = NULL; | |
200 char buf[10240]; | |
201 int n, ret; | |
202 char *tmp_name; | |
203 mode_t mask; | |
204 struct stat st; | |
205 | |
206 x_asprintf(&tmp_name, "%s.XXXXXX", dest); | |
207 | |
208 if (getenv("CCACHE_NOCOMPRESS")) { | |
209 mode = COPY_UNCOMPRESSED; | |
210 } | |
211 | |
212 /* open source file */ | |
213 fd_in = open(src, O_RDONLY); | |
214 if (fd_in == -1) { | |
215 return -1; | |
216 } | |
217 | |
218 gz_in = gzdopen(fd_in, "rb"); | |
219 if (!gz_in) { | |
220 close(fd_in); | |
221 return -1; | |
222 } | |
223 | |
224 /* open destination file */ | |
225 fd_out = mkstemp(tmp_name); | |
226 if (fd_out == -1) { | |
227 gzclose(gz_in); | |
228 free(tmp_name); | |
229 return -1; | |
230 } | |
231 | |
232 if (mode == COPY_TO_CACHE) { | |
233 /* The gzip file format occupies at least 20 bytes. So | |
234 it will always occupy an entire filesystem block, | |
235 even for empty files. | |
236 Since most stderr files will be empty, we turn off | |
237 compression in this case to save space. | |
238 */ | |
239 if (fstat(fd_in, &st) != 0) { | |
240 gzclose(gz_in); | |
241 close(fd_out); | |
242 free(tmp_name); | |
243 return -1; | |
244 } | |
245 if (file_size(&st) == 0) { | |
246 mode = COPY_UNCOMPRESSED; | |
247 } | |
248 } | |
249 | |
250 if (mode == COPY_TO_CACHE) { | |
251 gz_out = gzdopen(dup(fd_out), "wb"); | |
252 if (!gz_out) { | |
253 gzclose(gz_in); | |
254 close(fd_out); | |
255 free(tmp_name); | |
256 return -1; | |
257 } | |
258 } | |
259 | |
260 while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) { | |
261 if (mode == COPY_TO_CACHE) { | |
262 ret = gzwrite(gz_out, buf, n); | |
263 } else { | |
264 ret = write(fd_out, buf, n); | |
265 } | |
266 if (ret != n) { | |
267 gzclose(gz_in); | |
268 if (gz_out) { | |
269 gzclose(gz_out); | |
270 } | |
271 close(fd_out); | |
272 unlink(tmp_name); | |
273 free(tmp_name); | |
274 return -1; | |
275 } | |
276 } | |
277 | |
278 gzclose(gz_in); | |
279 if (gz_out) { | |
280 gzclose(gz_out); | |
281 } | |
282 | |
283 /* get perms right on the tmp file */ | |
284 mask = umask(0); | |
285 fchmod(fd_out, 0666 & ~mask); | |
286 umask(mask); | |
287 | |
288 /* the close can fail on NFS if out of space */ | |
289 if (close(fd_out) == -1) { | |
290 unlink(tmp_name); | |
291 free(tmp_name); | |
292 return -1; | |
293 } | |
294 | |
295 unlink(dest); | |
296 | |
297 if (rename(tmp_name, dest) == -1) { | |
298 unlink(tmp_name); | |
299 free(tmp_name); | |
300 return -1; | |
301 } | |
302 | |
303 free(tmp_name); | |
304 | |
305 return 0; | |
306 } | |
307 | |
308 /* move a file to the cache, compressing it */ | |
309 int move_file(const char *src, const char *dest) { | |
310 int ret; | |
311 | |
312 ret = _copy_file(src, dest, COPY_TO_CACHE); | |
313 if (ret != -1) unlink(src); | |
314 return ret; | |
315 } | |
316 | |
317 /* copy a file to the cache, compressing it */ | |
318 static int copy_file_to_cache(const char *src, const char *dest) { | |
319 return _copy_file(src, dest, COPY_TO_CACHE); | |
320 } | |
321 | |
322 /* copy a file from the cache, decompressing it */ | |
323 static int copy_file_from_cache(const char *src, const char *dest) { | |
324 return _copy_file(src, dest, COPY_FROM_CACHE); | |
325 } | |
326 #endif /* ENABLE_ZLIB */ | |
327 | |
328 /* test if a file is zlib compressed */ | |
329 int test_if_compressed(const char *filename) { | |
330 FILE *f; | |
331 | |
332 f = fopen(filename, "rb"); | |
333 if (!f) { | |
334 return 0; | |
335 } | |
336 | |
337 /* test if file starts with 1F8B, which is zlib's | |
338 * magic number */ | |
339 if ((fgetc(f) != 0x1f) || (fgetc(f) != 0x8b)) { | |
340 fclose(f); | |
341 return 0; | |
342 } | |
343 | |
344 fclose(f); | |
345 return 1; | |
346 } | |
347 | |
348 /* copy file to the cache with error checking taking into account compression and hard linking if desired */ | |
349 int commit_to_cache(const char *src, const char *dest, int hardlink) | |
350 { | |
351 int ret = -1; | |
352 struct stat st; | |
353 if (stat(src, &st) == 0) { | |
354 unlink(dest); | |
355 if (hardlink) { | |
356 #ifdef _WIN32 | |
357 ret = CreateHardLinkA(dest, src, NULL) ? 0 : -1; | |
358 #else | |
359 ret = link(src, dest); | |
360 #endif | |
361 } | |
362 if (ret == -1) { | |
363 ret = copy_file_to_cache(src, dest); | |
364 if (ret == -1) { | |
365 cc_log("failed to commit %s -> %s (%s)\n", src, dest, strerror(errno)); | |
366 stats_update(STATS_ERROR); | |
367 } | |
368 } | |
369 } else { | |
370 cc_log("failed to put %s in the cache (%s)\n", src, strerror(errno)); | |
371 stats_update(STATS_ERROR); | |
372 } | |
373 return ret; | |
374 } | |
375 | |
376 /* copy file out of the cache with error checking taking into account compression and hard linking if desired */ | |
377 int retrieve_from_cache(const char *src, const char *dest, int hardlink) | |
378 { | |
379 int ret = 0; | |
380 | |
381 x_utimes(src); | |
382 | |
383 if (strcmp(dest, "/dev/null") == 0) { | |
384 ret = 0; | |
385 } else { | |
386 unlink(dest); | |
387 /* only make a hardlink if the cache file is uncompressed */ | |
388 if (hardlink && test_if_compressed(src) == 0) { | |
389 #ifdef _WIN32 | |
390 ret = CreateHardLinkA(dest, src, NULL) ? 0 : -1; | |
391 #else | |
392 ret = link(src, dest); | |
393 #endif | |
394 } else { | |
395 ret = copy_file_from_cache(src, dest); | |
396 } | |
397 } | |
398 | |
399 /* the cached file might have been deleted by some external process */ | |
400 if (ret == -1 && errno == ENOENT) { | |
401 cc_log("hashfile missing for %s\n", dest); | |
402 stats_update(STATS_MISSING); | |
403 return -1; | |
404 } | |
405 | |
406 if (ret == -1) { | |
407 ret = copy_file_from_cache(src, dest); | |
408 if (ret == -1) { | |
409 cc_log("failed to retrieve %s -> %s (%s)\n", src, dest, strerror(errno)); | |
410 stats_update(STATS_ERROR); | |
411 return -1; | |
412 } | |
413 } | |
414 return ret; | |
415 } | |
416 | |
417 /* make sure a directory exists */ | |
418 int create_dir(const char *dir) | |
419 { | |
420 struct stat st; | |
421 if (stat(dir, &st) == 0) { | |
422 if (S_ISDIR(st.st_mode)) { | |
423 return 0; | |
424 } | |
425 errno = ENOTDIR; | |
426 return 1; | |
427 } | |
428 #ifdef _WIN32 | |
429 if (mkdir(dir) != 0 && errno != EEXIST) { | |
430 return 1; | |
431 } | |
432 #else | |
433 if (mkdir(dir, 0777) != 0 && errno != EEXIST) { | |
434 return 1; | |
435 } | |
436 #endif | |
437 return 0; | |
438 } | |
439 | |
440 char const CACHEDIR_TAG[] = | |
441 "Signature: 8a477f597d28d172789f06886806bc55\n" | |
442 "# This file is a cache directory tag created by ccache.\n" | |
443 "# For information about cache directory tags, see:\n" | |
444 "# http://www.brynosaurus.com/cachedir/\n"; | |
445 | |
446 int create_cachedirtag(const char *dir) | |
447 { | |
448 char *filename; | |
449 struct stat st; | |
450 FILE *f; | |
451 x_asprintf(&filename, "%s/CACHEDIR.TAG", dir); | |
452 if (stat(filename, &st) == 0) { | |
453 if (S_ISREG(st.st_mode)) { | |
454 goto success; | |
455 } | |
456 errno = EEXIST; | |
457 goto error; | |
458 } | |
459 f = fopen(filename, "w"); | |
460 if (!f) goto error; | |
461 if (fwrite(CACHEDIR_TAG, sizeof(CACHEDIR_TAG)-1, 1, f) != 1) { | |
462 goto error; | |
463 } | |
464 if (fclose(f)) goto error; | |
465 success: | |
466 free(filename); | |
467 return 0; | |
468 error: | |
469 free(filename); | |
470 return 1; | |
471 } | |
472 | |
473 /* | |
474 this is like asprintf() but dies if the malloc fails | |
475 note that we use vsnprintf in a rather poor way to make this more portable | |
476 */ | |
477 void x_asprintf(char **ptr, const char *format, ...) | |
478 { | |
479 va_list ap; | |
480 | |
481 *ptr = NULL; | |
482 va_start(ap, format); | |
483 if (vasprintf(ptr, format, ap) == -1) { | |
484 fatal("out of memory in x_asprintf"); | |
485 } | |
486 va_end(ap); | |
487 | |
488 if (!ptr) fatal("out of memory in x_asprintf"); | |
489 } | |
490 | |
491 /* | |
492 this is like strdup() but dies if the malloc fails | |
493 */ | |
494 char *x_strdup(const char *s) | |
495 { | |
496 char *ret; | |
497 ret = strdup(s); | |
498 if (!ret) { | |
499 fatal("out of memory in strdup\n"); | |
500 } | |
501 return ret; | |
502 } | |
503 | |
504 /* | |
505 this is like malloc() but dies if the malloc fails | |
506 */ | |
507 void *x_malloc(size_t size) | |
508 { | |
509 void *ret; | |
510 ret = malloc(size); | |
511 if (!ret) { | |
512 fatal("out of memory in malloc\n"); | |
513 } | |
514 return ret; | |
515 } | |
516 | |
517 /* | |
518 this is like realloc() but dies if the malloc fails | |
519 */ | |
520 void *x_realloc(void *ptr, size_t size) | |
521 { | |
522 void *p2; | |
523 #if 1 | |
524 /* Avoid invalid read in memcpy below */ | |
525 p2 = realloc(ptr, size); | |
526 if (!p2) { | |
527 fatal("out of memory in x_realloc"); | |
528 } | |
529 #else | |
530 if (!ptr) return x_malloc(size); | |
531 p2 = malloc(size); | |
532 if (!p2) { | |
533 fatal("out of memory in x_realloc"); | |
534 } | |
535 if (ptr) { | |
536 /* Note invalid read as the memcpy reads beyond the memory allocated by ptr */ | |
537 memcpy(p2, ptr, size); | |
538 free(ptr); | |
539 } | |
540 #endif | |
541 return p2; | |
542 } | |
543 | |
544 | |
545 /* | |
546 revsusive directory traversal - used for cleanup | |
547 fn() is called on all files/dirs in the tree | |
548 */ | |
549 void traverse(const char *dir, void (*fn)(const char *, struct stat *)) | |
550 { | |
551 DIR *d; | |
552 struct dirent *de; | |
553 | |
554 d = opendir(dir); | |
555 if (!d) return; | |
556 | |
557 while ((de = readdir(d))) { | |
558 char *fname; | |
559 struct stat st; | |
560 | |
561 if (strcmp(de->d_name,".") == 0) continue; | |
562 if (strcmp(de->d_name,"..") == 0) continue; | |
563 | |
564 if (strlen(de->d_name) == 0) continue; | |
565 | |
566 x_asprintf(&fname, "%s/%s", dir, de->d_name); | |
567 #ifdef _WIN32 | |
568 if (stat(fname, &st)) | |
569 #else | |
570 if (lstat(fname, &st)) | |
571 #endif | |
572 { | |
573 if (errno != ENOENT) { | |
574 perror(fname); | |
575 } | |
576 free(fname); | |
577 continue; | |
578 } | |
579 | |
580 if (S_ISDIR(st.st_mode)) { | |
581 traverse(fname, fn); | |
582 } | |
583 | |
584 fn(fname, &st); | |
585 free(fname); | |
586 } | |
587 | |
588 closedir(d); | |
589 } | |
590 | |
591 | |
592 /* return the base name of a file - caller frees */ | |
593 char *str_basename(const char *s) | |
594 { | |
595 char *p = strrchr(s, '/'); | |
596 if (p) { | |
597 s = (p+1); | |
598 } | |
599 | |
600 #ifdef _WIN32 | |
601 p = strrchr(s, '\\'); | |
602 | |
603 if (p) { | |
604 s = (p+1); | |
605 } | |
606 #endif | |
607 | |
608 return x_strdup(s); | |
609 } | |
610 | |
611 /* return the dir name of a file - caller frees */ | |
612 char *dirname(char *s) | |
613 { | |
614 char *p; | |
615 s = x_strdup(s); | |
616 p = strrchr(s, '/'); | |
617 #ifdef _WIN32 | |
618 p = strrchr(s, '\\'); | |
619 #endif | |
620 if (p) { | |
621 *p = 0; | |
622 } | |
623 return s; | |
624 } | |
625 | |
626 /* | |
627 http://www.ecst.csuchico.edu/~beej/guide/ipc/flock.html | |
628 http://cvs.php.net/viewvc.cgi/php-src/win32/flock.c?revision=1.2&view=markup | |
629 Should return 0 for success, >0 otherwise | |
630 */ | |
631 int lock_fd(int fd) | |
632 { | |
633 #ifdef _WIN32 | |
634 # if 1 | |
635 return _locking(fd, _LK_NBLCK, 1); | |
636 # else | |
637 HANDLE fl = (HANDLE)_get_osfhandle(fd); | |
638 OVERLAPPED o; | |
639 memset(&o, 0, sizeof(o)); | |
640 return (LockFileEx(fl, LOCKFILE_EXCLUSIVE_LOCK, 0, 1, 0, &o)) | |
641 ? 0 : GetLastError(); | |
642 # endif | |
643 #else | |
644 struct flock fl; | |
645 int ret; | |
646 | |
647 fl.l_type = F_WRLCK; | |
648 fl.l_whence = SEEK_SET; | |
649 fl.l_start = 0; | |
650 fl.l_len = 1; | |
651 fl.l_pid = 0; | |
652 | |
653 /* not sure why we would be getting a signal here, | |
654 but one user claimed it is possible */ | |
655 do { | |
656 ret = fcntl(fd, F_SETLKW, &fl); | |
657 } while (ret == -1 && errno == EINTR); | |
658 return ret; | |
659 #endif | |
660 } | |
661 | |
662 /* return size on disk of a file */ | |
663 size_t file_size(struct stat *st) | |
664 { | |
665 #ifdef _WIN32 | |
666 return (st->st_size + 1023) & ~1023; | |
667 #else | |
668 size_t size = st->st_blocks * 512; | |
669 if ((size_t)st->st_size > size) { | |
670 /* probably a broken stat() call ... */ | |
671 size = (st->st_size + 1023) & ~1023; | |
672 } | |
673 return size; | |
674 #endif | |
675 } | |
676 | |
677 | |
678 /* a safe open/create for read-write */ | |
679 int safe_open(const char *fname) | |
680 { | |
681 int fd = open(fname, O_RDWR|O_BINARY); | |
682 if (fd == -1 && errno == ENOENT) { | |
683 fd = open(fname, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0666); | |
684 if (fd == -1 && errno == EEXIST) { | |
685 fd = open(fname, O_RDWR|O_BINARY); | |
686 } | |
687 } | |
688 return fd; | |
689 } | |
690 | |
691 /* display a kilobyte unsigned value in M, k or G */ | |
692 void display_size(unsigned v) | |
693 { | |
694 if (v > 1024*1024) { | |
695 printf("%8.1f Gbytes", v/((double)(1024*1024))); | |
696 } else if (v > 1024) { | |
697 printf("%8.1f Mbytes", v/((double)(1024))); | |
698 } else { | |
699 printf("%8u Kbytes", v); | |
700 } | |
701 } | |
702 | |
703 /* return a value in multiples of 1024 give a string that can end | |
704 in K, M or G | |
705 */ | |
706 size_t value_units(const char *s) | |
707 { | |
708 char m; | |
709 double v = atof(s); | |
710 m = s[strlen(s)-1]; | |
711 switch (m) { | |
712 case 'G': | |
713 case 'g': | |
714 default: | |
715 v *= 1024*1024; | |
716 break; | |
717 case 'M': | |
718 case 'm': | |
719 v *= 1024; | |
720 break; | |
721 case 'K': | |
722 case 'k': | |
723 v *= 1; | |
724 break; | |
725 } | |
726 return (size_t)v; | |
727 } | |
728 | |
729 | |
730 /* | |
731 a sane realpath() function, trying to cope with stupid path limits and | |
732 a broken API | |
733 */ | |
734 char *x_realpath(const char *path) | |
735 { | |
736 #ifdef _WIN32 | |
737 char namebuf[MAX_PATH]; | |
738 DWORD ret; | |
739 | |
740 ret = GetFullPathNameA(path, sizeof(namebuf), namebuf, NULL); | |
741 if (ret == 0 || ret >= sizeof(namebuf)) { | |
742 return NULL; | |
743 } | |
744 | |
745 return x_strdup(namebuf); | |
746 #else | |
747 int maxlen; | |
748 char *ret, *p; | |
749 #ifdef PATH_MAX | |
750 maxlen = PATH_MAX; | |
751 #elif defined(MAXPATHLEN) | |
752 maxlen = MAXPATHLEN; | |
753 #elif defined(_PC_PATH_MAX) | |
754 maxlen = pathconf(path, _PC_PATH_MAX); | |
755 #endif | |
756 if (maxlen < 4096) maxlen = 4096; | |
757 | |
758 ret = x_malloc(maxlen); | |
759 | |
760 #if HAVE_REALPATH | |
761 p = realpath(path, ret); | |
762 #else | |
763 /* yes, there are such systems. This replacement relies on | |
764 the fact that when we call x_realpath we only care about symlinks */ | |
765 { | |
766 int len = readlink(path, ret, maxlen-1); | |
767 if (len == -1) { | |
768 free(ret); | |
769 return NULL; | |
770 } | |
771 ret[len] = 0; | |
772 p = ret; | |
773 } | |
774 #endif | |
775 if (p) { | |
776 p = x_strdup(p); | |
777 free(ret); | |
778 return p; | |
779 } | |
780 free(ret); | |
781 return NULL; | |
782 #endif | |
783 } | |
784 | |
785 /* a getcwd that will returns an allocated buffer */ | |
786 char *gnu_getcwd(void) | |
787 { | |
788 unsigned size = 128; | |
789 | |
790 while (1) { | |
791 char *buffer = (char *)x_malloc(size); | |
792 if (getcwd(buffer, size) == buffer) { | |
793 return buffer; | |
794 } | |
795 free(buffer); | |
796 if (errno != ERANGE) { | |
797 return 0; | |
798 } | |
799 size *= 2; | |
800 } | |
801 } | |
802 | |
803 /* create an empty file */ | |
804 int create_empty_file(const char *fname) | |
805 { | |
806 int fd; | |
807 | |
808 fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666); | |
809 if (fd == -1) { | |
810 return -1; | |
811 } | |
812 close(fd); | |
813 return 0; | |
814 } | |
815 | |
816 /* | |
817 return current users home directory or die | |
818 */ | |
819 const char *get_home_directory(void) | |
820 { | |
821 #ifdef _WIN32 | |
822 static char home_path[MAX_PATH] = {0}; | |
823 HRESULT ret; | |
824 | |
825 /* we already have the path */ | |
826 if (home_path[0] != 0) { | |
827 return home_path; | |
828 } | |
829 | |
830 /* get the path to "Application Data" folder */ | |
831 ret = SHGetFolderPathA(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, home_path); | |
832 if (SUCCEEDED(ret)) { | |
833 return home_path; | |
834 } | |
835 | |
836 fprintf(stderr, "ccache: Unable to determine home directory\n"); | |
837 return NULL; | |
838 #else | |
839 const char *p = getenv("HOME"); | |
840 if (p) { | |
841 return p; | |
842 } | |
843 #ifdef HAVE_GETPWUID | |
844 { | |
845 struct passwd *pwd = getpwuid(getuid()); | |
846 if (pwd) { | |
847 return pwd->pw_dir; | |
848 } | |
849 } | |
850 #endif | |
851 fatal("Unable to determine home directory"); | |
852 return NULL; | |
853 #endif | |
854 } | |
855 | |
856 int x_utimes(const char *filename) | |
857 { | |
858 #ifdef HAVE_UTIMES | |
859 return utimes(filename, NULL); | |
860 #else | |
861 return utime(filename, NULL); | |
862 #endif | |
863 } | |
864 | |
865 #ifdef _WIN32 | |
866 /* perror for Win32 API calls, using GetLastError() instead of errno */ | |
867 void perror_win32(LPTSTR pszFunction) | |
868 { | |
869 LPTSTR pszMessage; | |
870 DWORD dwLastError = GetLastError(); | |
871 | |
872 FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
873 FORMAT_MESSAGE_FROM_SYSTEM | | |
874 FORMAT_MESSAGE_IGNORE_INSERTS, | |
875 NULL, | |
876 dwLastError, | |
877 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), | |
878 (LPTSTR)&pszMessage, | |
879 0, NULL ); | |
880 | |
881 fprintf(stderr, "%s: %s\n", pszFunction, pszMessage); | |
882 LocalFree(pszMessage); | |
883 } | |
884 #endif |