Branch data Line data Source code
1 : : /*
2 : : * Copyright (C) 2002 Andrew Tridgell
3 : : * Copyright (C) 2009-2015 Joel Rosdahl
4 : : *
5 : : * This program is free software; you can redistribute it and/or modify it
6 : : * under the terms of the GNU General Public License as published by the Free
7 : : * Software Foundation; either version 3 of the License, or (at your option)
8 : : * any later version.
9 : : *
10 : : * This program is distributed in the hope that it will be useful, but WITHOUT
11 : : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 : : * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 : : * more details.
14 : : *
15 : : * You should have received a copy of the GNU General Public License along with
16 : : * this program; if not, write to the Free Software Foundation, Inc., 51
17 : : * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : : */
19 : :
20 : : #include "ccache.h"
21 : :
22 : : #include <zlib.h>
23 : :
24 : : #ifdef HAVE_PWD_H
25 : : #include <pwd.h>
26 : : #endif
27 : : #ifdef HAVE_SYS_TIME_H
28 : : #include <sys/time.h>
29 : : #endif
30 : :
31 : : #ifdef _WIN32
32 : : #include <windows.h>
33 : : #include <sys/locking.h>
34 : : #endif
35 : :
36 : : static FILE *logfile;
37 : :
38 : : static bool
39 : 110 : init_log(void)
40 : : {
41 : : extern struct conf *conf;
42 : :
43 [ + + ]: 110 : if (logfile) {
44 : 47 : return true;
45 : : }
46 [ - + ]: 63 : assert(conf);
47 [ + + ]: 63 : if (str_eq(conf->log_file, "")) {
48 : 56 : return false;
49 : : }
50 : 7 : logfile = fopen(conf->log_file, "a");
51 [ + - ]: 7 : if (logfile) {
52 : : #ifndef _WIN32
53 : 7 : int fd = fileno(logfile);
54 : 7 : int flags = fcntl(fd, F_GETFD, 0);
55 [ + - ]: 7 : if (flags >= 0) {
56 : 7 : fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
57 : : }
58 : : #endif
59 : 7 : return true;
60 : : } else {
61 : 110 : return false;
62 : : }
63 : : }
64 : :
65 : : static void
66 : 54 : log_prefix(bool log_updated_time)
67 : : {
68 : : #ifdef HAVE_GETTIMEOFDAY
69 : : char timestamp[100];
70 : : struct timeval tv;
71 : : struct tm *tm;
72 : : static char prefix[200];
73 : :
74 [ + + ]: 54 : if (log_updated_time) {
75 : 27 : gettimeofday(&tv, NULL);
76 : : #ifdef __MINGW64_VERSION_MAJOR
77 : : tm = localtime((time_t*)&tv.tv_sec);
78 : : #else
79 : 27 : tm = localtime(&tv.tv_sec);
80 : : #endif
81 : 27 : strftime(timestamp, sizeof(timestamp), "%Y-%m-%dT%H:%M:%S", tm);
82 : 27 : snprintf(prefix, sizeof(prefix),
83 : : "[%s.%06d %-5d] ", timestamp, (int)tv.tv_usec, (int)getpid());
84 : : }
85 : 54 : fputs(prefix, logfile);
86 : : #else
87 : : fprintf(logfile, "[%-5d] ", (int)getpid());
88 : : #endif
89 : 54 : }
90 : :
91 : : static long
92 : 13 : path_max(const char *path)
93 : : {
94 : : #ifdef PATH_MAX
95 : : (void)path;
96 : 13 : return PATH_MAX;
97 : : #elif defined(MAXPATHLEN)
98 : : (void)path;
99 : : return MAXPATHLEN;
100 : : #elif defined(_PC_PATH_MAX)
101 : : long maxlen = pathconf(path, _PC_PATH_MAX);
102 : : if (maxlen >= 4096) {
103 : : return maxlen;
104 : : } else {
105 : : return 4096;
106 : : }
107 : : #endif
108 : : }
109 : :
110 : : /*
111 : : * Warn about failure writing to the log file and then exit.
112 : : */
113 : : static void
114 : 0 : warn_log_fail(void)
115 : : {
116 : : extern struct conf *conf;
117 : :
118 : : /* Note: Can't call fatal() since that would lead to recursion. */
119 : 0 : fprintf(stderr, "ccache: error: Failed to write to %s: %s\n",
120 : 0 : conf->log_file, strerror(errno));
121 : 0 : x_exit(EXIT_FAILURE);
122 : : }
123 : :
124 : : static void
125 : 92 : vlog(const char *format, va_list ap, bool log_updated_time)
126 : : {
127 : : int rc1, rc2;
128 [ + + ]: 92 : if (!init_log()) {
129 : 41 : return;
130 : : }
131 : :
132 : 51 : log_prefix(log_updated_time);
133 : 51 : rc1 = vfprintf(logfile, format, ap);
134 : 51 : rc2 = fprintf(logfile, "\n");
135 [ + - ][ - + ]: 51 : if (rc1 < 0 || rc2 < 0) {
136 : 92 : warn_log_fail();
137 : : }
138 : : }
139 : :
140 : : /*
141 : : * Write a message to the log file (adding a newline) and flush.
142 : : */
143 : : void
144 : 65 : cc_log(const char *format, ...)
145 : : {
146 : : va_list ap;
147 : 65 : va_start(ap, format);
148 : 65 : vlog(format, ap, true);
149 : 65 : va_end(ap);
150 [ + + ]: 65 : if (logfile) {
151 : 24 : fflush(logfile);
152 : : }
153 : 65 : }
154 : :
155 : : /*
156 : : * Write a message to the log file (adding a newline) without flushing and with
157 : : * a reused timestamp.
158 : : */
159 : : void
160 : 27 : cc_bulklog(const char *format, ...)
161 : : {
162 : : va_list ap;
163 : 27 : va_start(ap, format);
164 : 27 : vlog(format, ap, false);
165 : 27 : va_end(ap);
166 : 27 : }
167 : :
168 : : /*
169 : : * Log an executed command to the CCACHE_LOGFILE location.
170 : : */
171 : : void
172 : 18 : cc_log_argv(const char *prefix, char **argv)
173 : : {
174 : : int rc;
175 [ + + ]: 18 : if (!init_log()) {
176 : 15 : return;
177 : : }
178 : :
179 : 3 : log_prefix(true);
180 : 3 : fputs(prefix, logfile);
181 : 3 : print_command(logfile, argv);
182 : 3 : rc = fflush(logfile);
183 [ - + ]: 3 : if (rc) {
184 : 18 : warn_log_fail();
185 : : }
186 : : }
187 : :
188 : : /* something went badly wrong! */
189 : : void
190 : 0 : fatal(const char *format, ...)
191 : : {
192 : : va_list ap;
193 : : char msg[1000];
194 : :
195 : 0 : va_start(ap, format);
196 : 0 : vsnprintf(msg, sizeof(msg), format, ap);
197 : 0 : va_end(ap);
198 : :
199 : 0 : cc_log("FATAL: %s", msg);
200 : 0 : fprintf(stderr, "ccache: error: %s\n", msg);
201 : :
202 : 0 : x_exit(1);
203 : : }
204 : :
205 : : /*
206 : : * Copy all data from fd_in to fd_out, decompressing data from fd_in if needed.
207 : : */
208 : : void
209 : 3 : copy_fd(int fd_in, int fd_out)
210 : : {
211 : : char buf[10240];
212 : : int n;
213 : : gzFile gz_in;
214 : :
215 : 3 : gz_in = gzdopen(dup(fd_in), "rb");
216 : :
217 [ - + ]: 3 : if (!gz_in) {
218 : 0 : fatal("Failed to copy fd");
219 : : }
220 : :
221 [ + + ]: 6 : while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
222 : 3 : ssize_t count, written = 0;
223 : : do {
224 : 3 : count = write(fd_out, buf + written, n - written);
225 [ - + ]: 3 : if (count == -1) {
226 [ # # ][ # # ]: 0 : if (errno != EAGAIN && errno != EINTR) {
227 : 0 : fatal("Failed to copy fd");
228 : : }
229 : : } else {
230 : 3 : written += count;
231 : : }
232 [ - + ]: 3 : } while (written < n);
233 : : }
234 : :
235 : 3 : gzclose(gz_in);
236 : 3 : }
237 : :
238 : : #ifndef HAVE_MKSTEMP
239 : : /* cheap and nasty mkstemp replacement */
240 : : int
241 : : mkstemp(char *template)
242 : : {
243 : : mktemp(template);
244 : : return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
245 : : }
246 : : #endif
247 : :
248 : : #ifndef _WIN32
249 : : static mode_t
250 : 10 : get_umask(void)
251 : : {
252 : : static bool mask_retrieved = false;
253 : : static mode_t mask;
254 [ + + ]: 10 : if (!mask_retrieved) {
255 : 2 : mask = umask(0);
256 : 2 : umask(mask);
257 : 2 : mask_retrieved = true;
258 : : }
259 : 10 : return mask;
260 : : }
261 : : #endif
262 : :
263 : : /*
264 : : * Copy src to dest, decompressing src if needed. compress_level > 0 decides
265 : : * whether dest will be compressed, and with which compression level. Returns 0
266 : : * on success and -1 on failure. On failure, errno represents the error.
267 : : */
268 : : int
269 : 1 : copy_file(const char *src, const char *dest, int compress_level)
270 : : {
271 : : int fd_in, fd_out;
272 : 1 : gzFile gz_in = NULL, gz_out = NULL;
273 : : char buf[10240];
274 : : int n, written;
275 : : char *tmp_name;
276 : : struct stat st;
277 : : int errnum;
278 : 1 : int saved_errno = 0;
279 : :
280 : : /* open destination file */
281 : 1 : tmp_name = x_strdup(dest);
282 : 1 : fd_out = create_tmp_fd(&tmp_name);
283 [ - + ]: 1 : cc_log("Copying %s to %s via %s (%scompressed)",
284 : : src, dest, tmp_name, compress_level > 0 ? "" : "un");
285 : :
286 : : /* open source file */
287 : 1 : fd_in = open(src, O_RDONLY | O_BINARY);
288 [ - + ]: 1 : if (fd_in == -1) {
289 : 0 : saved_errno = errno;
290 : 0 : cc_log("open error: %s", strerror(saved_errno));
291 : 0 : goto error;
292 : : }
293 : :
294 : 1 : gz_in = gzdopen(fd_in, "rb");
295 [ - + ]: 1 : if (!gz_in) {
296 : 0 : saved_errno = errno;
297 : 0 : cc_log("gzdopen(src) error: %s", strerror(saved_errno));
298 : 0 : close(fd_in);
299 : 0 : goto error;
300 : : }
301 : :
302 [ - + ]: 1 : if (compress_level > 0) {
303 : : /*
304 : : * A gzip file occupies at least 20 bytes, so it will always
305 : : * occupy an entire filesystem block, even for empty files.
306 : : * Turn off compression for empty files to save some space.
307 : : */
308 [ # # ]: 0 : if (x_fstat(fd_in, &st) != 0) {
309 : 0 : goto error;
310 : : }
311 [ # # ]: 0 : if (file_size(&st) == 0) {
312 : 0 : compress_level = 0;
313 : : }
314 : : }
315 : :
316 [ - + ]: 1 : if (compress_level > 0) {
317 : 0 : gz_out = gzdopen(dup(fd_out), "wb");
318 [ # # ]: 0 : if (!gz_out) {
319 : 0 : saved_errno = errno;
320 : 0 : cc_log("gzdopen(dest) error: %s", strerror(saved_errno));
321 : 0 : goto error;
322 : : }
323 : 0 : gzsetparams(gz_out, compress_level, Z_DEFAULT_STRATEGY);
324 : : }
325 : :
326 [ + + ]: 2 : while ((n = gzread(gz_in, buf, sizeof(buf))) > 0) {
327 [ - + ]: 1 : if (compress_level > 0) {
328 : 0 : written = gzwrite(gz_out, buf, n);
329 : : } else {
330 : : ssize_t count;
331 : 1 : written = 0;
332 : : do {
333 : 1 : count = write(fd_out, buf + written, n - written);
334 [ - + ][ # # ]: 1 : if (count == -1 && errno != EINTR) {
335 : 0 : saved_errno = errno;
336 : 0 : break;
337 : : }
338 : 1 : written += count;
339 [ - + ]: 1 : } while (written < n);
340 : : }
341 [ - + ]: 1 : if (written != n) {
342 [ # # ]: 0 : if (compress_level > 0) {
343 : 0 : cc_log("gzwrite error: %s (errno: %s)",
344 : : gzerror(gz_in, &errnum),
345 : : strerror(saved_errno));
346 : : } else {
347 : 0 : cc_log("write error: %s", strerror(saved_errno));
348 : : }
349 : 0 : goto error;
350 : : }
351 : : }
352 : :
353 : : /*
354 : : * gzeof won't tell if there's an error in the trailing CRC, so we must check
355 : : * gzerror before considering everything OK.
356 : : */
357 : 1 : gzerror(gz_in, &errnum);
358 [ + - ][ - + ]: 1 : if (!gzeof(gz_in) || (errnum != Z_OK && errnum != Z_STREAM_END)) {
[ # # ]
359 : 0 : saved_errno = errno;
360 : 0 : cc_log("gzread error: %s (errno: %s)",
361 : : gzerror(gz_in, &errnum), strerror(saved_errno));
362 : 0 : gzclose(gz_in);
363 [ # # ]: 0 : if (gz_out) {
364 : 0 : gzclose(gz_out);
365 : : }
366 : 0 : close(fd_out);
367 : 0 : tmp_unlink(tmp_name);
368 : 0 : free(tmp_name);
369 : 0 : return -1;
370 : : }
371 : :
372 : 1 : gzclose(gz_in);
373 : 1 : gz_in = NULL;
374 [ - + ]: 1 : if (gz_out) {
375 : 0 : gzclose(gz_out);
376 : 0 : gz_out = NULL;
377 : : }
378 : :
379 : : #ifndef _WIN32
380 : 1 : fchmod(fd_out, 0666 & ~get_umask());
381 : : #endif
382 : :
383 : : /* the close can fail on NFS if out of space */
384 [ - + ]: 1 : if (close(fd_out) == -1) {
385 : 0 : saved_errno = errno;
386 : 0 : cc_log("close error: %s", strerror(saved_errno));
387 : 0 : goto error;
388 : : }
389 : :
390 [ - + ]: 1 : if (x_rename(tmp_name, dest) == -1) {
391 : 0 : saved_errno = errno;
392 : 0 : cc_log("rename error: %s", strerror(saved_errno));
393 : 0 : goto error;
394 : : }
395 : :
396 : 1 : free(tmp_name);
397 : :
398 : 1 : return 0;
399 : :
400 : : error:
401 [ # # ]: 0 : if (gz_in) {
402 : 0 : gzclose(gz_in);
403 : : }
404 [ # # ]: 0 : if (gz_out) {
405 : 0 : gzclose(gz_out);
406 : : }
407 [ # # ]: 0 : if (fd_out != -1) {
408 : 0 : close(fd_out);
409 : : }
410 : 0 : tmp_unlink(tmp_name);
411 : 0 : free(tmp_name);
412 : 0 : errno = saved_errno;
413 : 1 : return -1;
414 : : }
415 : :
416 : : /* Run copy_file() and, if successful, delete the source file. */
417 : : int
418 : 0 : move_file(const char *src, const char *dest, int compress_level)
419 : : {
420 : : int ret;
421 : :
422 : 0 : ret = copy_file(src, dest, compress_level);
423 [ # # ]: 0 : if (ret != -1) {
424 : 0 : x_unlink(src);
425 : : }
426 : 0 : return ret;
427 : : }
428 : :
429 : : /*
430 : : * Like move_file(), but assumes that src is uncompressed and that src and dest
431 : : * are on the same file system.
432 : : */
433 : : int
434 : 1 : move_uncompressed_file(const char *src, const char *dest, int compress_level)
435 : : {
436 [ - + ]: 1 : if (compress_level > 0) {
437 : 0 : return move_file(src, dest, compress_level);
438 : : } else {
439 : 1 : return x_rename(src, dest);
440 : : }
441 : : }
442 : :
443 : : /* test if a file is zlib compressed */
444 : : bool
445 : 0 : file_is_compressed(const char *filename)
446 : : {
447 : : FILE *f;
448 : :
449 : 0 : f = fopen(filename, "rb");
450 [ # # ]: 0 : if (!f) {
451 : 0 : return false;
452 : : }
453 : :
454 : : /* test if file starts with 1F8B, which is zlib's
455 : : * magic number */
456 [ # # ][ # # ]: 0 : if ((fgetc(f) != 0x1f) || (fgetc(f) != 0x8b)) {
457 : 0 : fclose(f);
458 : 0 : return false;
459 : : }
460 : :
461 : 0 : fclose(f);
462 : 0 : return true;
463 : : }
464 : :
465 : : /* make sure a directory exists */
466 : : int
467 : 98 : create_dir(const char *dir)
468 : : {
469 : : struct stat st;
470 [ - + ]: 98 : if (stat(dir, &st) == 0) {
471 [ # # ]: 0 : if (S_ISDIR(st.st_mode)) {
472 : 0 : return 0;
473 : : }
474 : 0 : errno = ENOTDIR;
475 : 0 : return 1;
476 : : }
477 [ - + ][ # # ]: 98 : if (mkdir(dir, 0777) != 0 && errno != EEXIST) {
478 : 0 : return 1;
479 : : }
480 : 98 : return 0;
481 : : }
482 : :
483 : : /* Create directories leading to path. Returns 0 on success, otherwise -1. */
484 : : int
485 : 5 : create_parent_dirs(const char *path)
486 : : {
487 : : struct stat st;
488 : : int res;
489 : 5 : char *parent = dirname(path);
490 : :
491 [ + + ]: 5 : if (stat(parent, &st) == 0) {
492 [ + - ]: 2 : if (S_ISDIR(st.st_mode)) {
493 : 2 : res = 0;
494 : : } else {
495 : 0 : res = -1;
496 : 2 : errno = ENOTDIR;
497 : : }
498 : : } else {
499 : 3 : res = create_parent_dirs(parent);
500 [ + - ]: 3 : if (res == 0) {
501 : 3 : res = mkdir(parent, 0777);
502 : : /* Have to handle the condition of the directory already existing because
503 : : * the file system could have changed in between calling stat and
504 : : * actually creating the directory. This can happen when there are
505 : : * multiple instances of ccache running and trying to create the same
506 : : * directory chain, which usually is the case when the cache root does
507 : : * not initially exist. As long as one of the processes creates the
508 : : * directories then our condition is satisfied and we avoid a race
509 : : * condition.
510 : : */
511 [ - + ][ # # ]: 3 : if (res != 0 && errno == EEXIST) {
512 : 3 : res = 0;
513 : : }
514 : : } else {
515 : 0 : res = -1;
516 : : }
517 : : }
518 : 5 : free(parent);
519 : 5 : return res;
520 : : }
521 : :
522 : : /*
523 : : * Return a static string with the current hostname.
524 : : */
525 : : const char *
526 : 9 : get_hostname(void)
527 : : {
528 : : static char hostname[260] = "";
529 : :
530 [ + + ]: 9 : if (hostname[0]) {
531 : 7 : return hostname;
532 : : }
533 : :
534 : 2 : strcpy(hostname, "unknown");
535 : : #if HAVE_GETHOSTNAME
536 : 2 : gethostname(hostname, sizeof(hostname) - 1);
537 : : #elif defined(_WIN32)
538 : : const char *computer_name = getenv("COMPUTERNAME");
539 : : if (computer_name) {
540 : : snprintf(hostname, sizeof(hostname), "%s", computer_name);
541 : : return hostname;
542 : : }
543 : :
544 : : WORD wVersionRequested;
545 : : WSADATA wsaData;
546 : : int err;
547 : :
548 : : wVersionRequested = MAKEWORD(2, 2);
549 : :
550 : : err = WSAStartup(wVersionRequested, &wsaData);
551 : : if (err != 0) {
552 : : /* Tell the user that we could not find a usable Winsock DLL. */
553 : : cc_log("WSAStartup failed with error: %d", err);
554 : : return hostname;
555 : : }
556 : :
557 : : if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2) {
558 : : /* Tell the user that we could not find a usable WinSock DLL. */
559 : : cc_log("Could not find a usable version of Winsock.dll");
560 : : WSACleanup();
561 : : return hostname;
562 : : }
563 : :
564 : : int result = gethostname(hostname, sizeof(hostname) - 1);
565 : : if (result != 0) {
566 : : int last_error = WSAGetLastError();
567 : : LPVOID lpMsgBuf;
568 : : LPVOID lpDisplayBuf;
569 : : DWORD dw = last_error;
570 : :
571 : : FormatMessage(
572 : : FORMAT_MESSAGE_ALLOCATE_BUFFER |
573 : : FORMAT_MESSAGE_FROM_SYSTEM |
574 : : FORMAT_MESSAGE_IGNORE_INSERTS,
575 : : NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
576 : : (LPTSTR) &lpMsgBuf, 0, NULL);
577 : :
578 : : lpDisplayBuf = (LPVOID) LocalAlloc(
579 : : LMEM_ZEROINIT,
580 : : (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) __FILE__) + 200)
581 : : * sizeof(TCHAR));
582 : : _snprintf((LPTSTR) lpDisplayBuf,
583 : : LocalSize(lpDisplayBuf) / sizeof(TCHAR),
584 : : TEXT("%s failed with error %d: %s"), __FILE__, dw,
585 : : lpMsgBuf);
586 : :
587 : : cc_log("can't get hostname OS returned error: %s", (char*)lpDisplayBuf);
588 : :
589 : : LocalFree(lpMsgBuf);
590 : : LocalFree(lpDisplayBuf);
591 : : }
592 : : WSACleanup();
593 : : #endif
594 : :
595 : 2 : hostname[sizeof(hostname) - 1] = 0;
596 : 9 : return hostname;
597 : : }
598 : :
599 : : /*
600 : : * Return a string to be passed to mkstemp to create a temporary file. Also
601 : : * tries to cope with NFS by adding the local hostname.
602 : : */
603 : : const char *
604 : 11 : tmp_string(void)
605 : : {
606 : : static char *ret;
607 : :
608 [ + + ]: 11 : if (!ret) {
609 : 2 : ret = format("%s.%u.XXXXXX", get_hostname(), (unsigned)getpid());
610 : : }
611 : :
612 : 11 : return ret;
613 : : }
614 : :
615 : : /*
616 : : * Return the hash result as a hex string. Size -1 means don't include size
617 : : * suffix. Caller frees.
618 : : */
619 : : char *
620 : 10 : format_hash_as_string(const unsigned char *hash, int size)
621 : : {
622 : : char *ret;
623 : : int i;
624 : :
625 : 10 : ret = x_malloc(53);
626 [ + + ]: 170 : for (i = 0; i < 16; i++) {
627 : 160 : sprintf(&ret[i*2], "%02x", (unsigned) hash[i]);
628 : : }
629 [ + + ]: 10 : if (size >= 0) {
630 : 9 : sprintf(&ret[i*2], "-%u", size);
631 : : }
632 : :
633 : 10 : return ret;
634 : : }
635 : :
636 : : char const CACHEDIR_TAG[] =
637 : : "Signature: 8a477f597d28d172789f06886806bc55\n"
638 : : "# This file is a cache directory tag created by ccache.\n"
639 : : "# For information about cache directory tags, see:\n"
640 : : "# http://www.brynosaurus.com/cachedir/\n";
641 : :
642 : : int
643 : 1 : create_cachedirtag(const char *dir)
644 : : {
645 : : struct stat st;
646 : : FILE *f;
647 : 1 : char *filename = format("%s/CACHEDIR.TAG", dir);
648 [ - + ]: 1 : if (stat(filename, &st) == 0) {
649 [ # # ]: 0 : if (S_ISREG(st.st_mode)) {
650 : 0 : goto success;
651 : : }
652 : 0 : errno = EEXIST;
653 : 0 : goto error;
654 : : }
655 : 1 : f = fopen(filename, "w");
656 [ - + ]: 1 : if (!f) {
657 : 0 : goto error;
658 : : }
659 [ - + ]: 1 : if (fwrite(CACHEDIR_TAG, sizeof(CACHEDIR_TAG)-1, 1, f) != 1) {
660 : 0 : fclose(f);
661 : 0 : goto error;
662 : : }
663 [ - + ]: 1 : if (fclose(f)) {
664 : 0 : goto error;
665 : : }
666 : : success:
667 : 1 : free(filename);
668 : 1 : return 0;
669 : : error:
670 : 0 : free(filename);
671 : 1 : return 1;
672 : : }
673 : :
674 : : /* Construct a string according to a format. Caller frees. */
675 : : char *
676 : 453 : format(const char *format, ...)
677 : : {
678 : : va_list ap;
679 : 453 : char *ptr = NULL;
680 : :
681 : 453 : va_start(ap, format);
682 [ - + ]: 453 : if (vasprintf(&ptr, format, ap) == -1) {
683 : 0 : fatal("Out of memory in format");
684 : : }
685 : 453 : va_end(ap);
686 : :
687 [ - + ]: 453 : if (!*ptr) {
688 : 0 : fatal("Internal error in format");
689 : : }
690 : 453 : return ptr;
691 : : }
692 : :
693 : : /*
694 : : this is like strdup() but dies if the malloc fails
695 : : */
696 : : char *
697 : 2180 : x_strdup(const char *s)
698 : : {
699 : : char *ret;
700 : 2180 : ret = strdup(s);
701 [ - + ]: 2180 : if (!ret) {
702 : 0 : fatal("Out of memory in x_strdup");
703 : : }
704 : 2180 : return ret;
705 : : }
706 : :
707 : : /*
708 : : this is like strndup() but dies if the malloc fails
709 : : */
710 : : char *
711 : 189 : x_strndup(const char *s, size_t n)
712 : : {
713 : : char *ret;
714 : : #ifndef HAVE_STRNDUP
715 : : size_t m;
716 : :
717 : : if (!s)
718 : : return NULL;
719 : : m = 0;
720 : : while (m < n && s[m]) {
721 : : m++;
722 : : }
723 : : ret = malloc(m + 1);
724 : : if (ret) {
725 : : memcpy(ret, s, m);
726 : : ret[m] = '\0';
727 : : }
728 : : #else
729 : 189 : ret = strndup(s, n);
730 : : #endif
731 [ - + ]: 189 : if (!ret) {
732 : 0 : fatal("x_strndup: Could not allocate %lu bytes", (unsigned long)n);
733 : : }
734 : 189 : return ret;
735 : : }
736 : :
737 : : /*
738 : : this is like malloc() but dies if the malloc fails
739 : : */
740 : : void *
741 : 764 : x_malloc(size_t size)
742 : : {
743 : : void *ret;
744 [ - + ]: 764 : if (size == 0) {
745 : : /*
746 : : * malloc() may return NULL if size is zero, so always do this to make sure
747 : : * that the code handles it regardless of platform.
748 : : */
749 : 0 : return NULL;
750 : : }
751 : 764 : ret = malloc(size);
752 [ - + ]: 764 : if (!ret) {
753 : 0 : fatal("x_malloc: Could not allocate %lu bytes", (unsigned long)size);
754 : : }
755 : 764 : return ret;
756 : : }
757 : :
758 : : /* This is like calloc() but dies if the allocation fails. */
759 : : void *
760 : 0 : x_calloc(size_t nmemb, size_t size)
761 : : {
762 : : void *ret;
763 [ # # ]: 0 : if (nmemb * size == 0) {
764 : : /*
765 : : * calloc() may return NULL if nmemb or size is 0, so always do this to
766 : : * make sure that the code handles it regardless of platform.
767 : : */
768 : 0 : return NULL;
769 : : }
770 : 0 : ret = calloc(nmemb, size);
771 [ # # ]: 0 : if (!ret) {
772 : 0 : fatal("x_calloc: Could not allocate %lu bytes", (unsigned long)size);
773 : : }
774 : 0 : return ret;
775 : : }
776 : :
777 : : /*
778 : : this is like realloc() but dies if the malloc fails
779 : : */
780 : : void *
781 : 913 : x_realloc(void *ptr, size_t size)
782 : : {
783 : : void *p2;
784 [ + + ]: 913 : if (!ptr) {
785 : 12 : return x_malloc(size);
786 : : }
787 : 901 : p2 = realloc(ptr, size);
788 [ - + ]: 901 : if (!p2) {
789 : 0 : fatal("x_realloc: Could not allocate %lu bytes", (unsigned long)size);
790 : : }
791 : 913 : return p2;
792 : : }
793 : :
794 : : /* This is like unsetenv. */
795 : 3 : void x_unsetenv(const char *name)
796 : : {
797 : : #ifdef HAVE_UNSETENV
798 : 3 : unsetenv(name);
799 : : #else
800 : : putenv(x_strdup(name)); /* Leak to environment. */
801 : : #endif
802 : 3 : }
803 : :
804 : : /* Like fstat() but also call cc_log on failure. */
805 : : int
806 : 0 : x_fstat(int fd, struct stat *buf)
807 : : {
808 : 0 : int result = fstat(fd, buf);
809 [ # # ]: 0 : if (result != 0) {
810 : 0 : cc_log("Failed to fstat fd %d: %s", fd, strerror(errno));
811 : : }
812 : 0 : return result;
813 : : }
814 : :
815 : : /* Like lstat() but also call cc_log on failure. */
816 : : int
817 : 0 : x_lstat(const char *pathname, struct stat *buf)
818 : : {
819 : 0 : int result = lstat(pathname, buf);
820 [ # # ]: 0 : if (result != 0) {
821 : 0 : cc_log("Failed to lstat %s: %s", pathname, strerror(errno));
822 : : }
823 : 0 : return result;
824 : : }
825 : :
826 : : /* Like stat() but also call cc_log on failure. */
827 : : int
828 : 9 : x_stat(const char *pathname, struct stat *buf)
829 : : {
830 : 9 : int result = stat(pathname, buf);
831 [ - + ]: 9 : if (result != 0) {
832 : 0 : cc_log("Failed to stat %s: %s", pathname, strerror(errno));
833 : : }
834 : 9 : return result;
835 : : }
836 : :
837 : : /*
838 : : * Construct a string according to the format and store it in *ptr. The
839 : : * original *ptr is then freed.
840 : : */
841 : : void
842 : 147 : reformat(char **ptr, const char *format, ...)
843 : : {
844 : 147 : char *saved = *ptr;
845 : : va_list ap;
846 : :
847 : 147 : *ptr = NULL;
848 : 147 : va_start(ap, format);
849 [ - + ]: 147 : if (vasprintf(ptr, format, ap) == -1) {
850 : 0 : fatal("Out of memory in reformat");
851 : : }
852 : 147 : va_end(ap);
853 : :
854 [ - + ]: 147 : if (!ptr) {
855 : 0 : fatal("Out of memory in reformat");
856 : : }
857 [ + - ]: 147 : if (saved) {
858 : 147 : free(saved);
859 : : }
860 : 147 : }
861 : :
862 : : /*
863 : : * Recursive directory traversal. fn() is called on all entries in the tree.
864 : : */
865 : : void
866 : 0 : traverse(const char *dir, void (*fn)(const char *, struct stat *))
867 : : {
868 : : DIR *d;
869 : : struct dirent *de;
870 : :
871 : 0 : d = opendir(dir);
872 [ # # ]: 0 : if (!d) {
873 : 0 : return;
874 : : }
875 : :
876 [ # # ]: 0 : while ((de = readdir(d))) {
877 : : char *fname;
878 : : struct stat st;
879 : :
880 [ # # ]: 0 : if (str_eq(de->d_name, ".")) {
881 : 0 : continue;
882 : : }
883 [ # # ]: 0 : if (str_eq(de->d_name, "..")) {
884 : 0 : continue;
885 : : }
886 : :
887 [ # # ]: 0 : if (strlen(de->d_name) == 0) {
888 : 0 : continue;
889 : : }
890 : :
891 : 0 : fname = format("%s/%s", dir, de->d_name);
892 [ # # ]: 0 : if (lstat(fname, &st)) {
893 [ # # ]: 0 : if (errno != ENOENT) {
894 : 0 : fatal("lstat %s failed: %s", fname, strerror(errno));
895 : : }
896 : 0 : free(fname);
897 : 0 : continue;
898 : : }
899 : :
900 [ # # ]: 0 : if (S_ISDIR(st.st_mode)) {
901 : 0 : traverse(fname, fn);
902 : : }
903 : :
904 : 0 : fn(fname, &st);
905 : 0 : free(fname);
906 : : }
907 : :
908 : 0 : closedir(d);
909 : : }
910 : :
911 : :
912 : : /* return the base name of a file - caller frees */
913 : : char *
914 : : basename(const char *path)
915 : : {
916 : : char *p;
917 : 25 : p = strrchr(path, '/');
918 [ + + ]: 25 : if (p) {
919 : 14 : path = p + 1;
920 : : }
921 : : #ifdef _WIN32
922 : : p = strrchr(path, '\\');
923 : : if (p) {
924 : : path = p + 1;
925 : : }
926 : : #endif
927 : :
928 : 25 : return x_strdup(path);
929 : : }
930 : :
931 : : /* return the dir name of a file - caller frees */
932 : : char *
933 : 15 : dirname(const char *path)
934 : : {
935 : : char *p;
936 : : #ifdef _WIN32
937 : : char *p2;
938 : : #endif
939 : : char *s;
940 : 15 : s = x_strdup(path);
941 : 15 : p = strrchr(s, '/');
942 : : #ifdef _WIN32
943 : : p2 = strrchr(s, '\\');
944 : : if (!p || (p2 && p < p2)) {
945 : : p = p2;
946 : : }
947 : : #endif
948 [ + + ]: 15 : if (!p) {
949 : 2 : free(s);
950 : 2 : s = x_strdup(".");
951 [ + + ]: 13 : } else if (p == s) {
952 : 2 : *(p + 1) = 0;
953 : : } else {
954 : 11 : *p = 0;
955 : : }
956 : 15 : return s;
957 : : }
958 : :
959 : : /*
960 : : * Return the file extension (including the dot) of a path as a pointer into
961 : : * path. If path has no file extension, the empty string and the end of path is
962 : : * returned.
963 : : */
964 : : const char *
965 : 14 : get_extension(const char *path)
966 : : {
967 : 14 : size_t len = strlen(path);
968 : : const char *p;
969 : :
970 [ + - ]: 28 : for (p = &path[len - 1]; p >= path; --p) {
971 [ + + ]: 28 : if (*p == '.') {
972 : 14 : return p;
973 : : }
974 [ - + ]: 14 : if (*p == '/') {
975 : 0 : break;
976 : : }
977 : : }
978 : 14 : return &path[len];
979 : : }
980 : :
981 : : /*
982 : : * Return a string containing the given path without the filename extension.
983 : : * Caller frees.
984 : : */
985 : : char *
986 : 0 : remove_extension(const char *path)
987 : : {
988 : 0 : return x_strndup(path, strlen(path) - strlen(get_extension(path)));
989 : : }
990 : :
991 : : /* return size on disk of a file */
992 : : size_t
993 : 2 : file_size(struct stat *st)
994 : : {
995 : : #ifdef _WIN32
996 : : return (st->st_size + 1023) & ~1023;
997 : : #else
998 : 2 : size_t size = st->st_blocks * 512;
999 [ - + ]: 2 : if ((size_t)st->st_size > size) {
1000 : : /* probably a broken stat() call ... */
1001 : 0 : size = (st->st_size + 1023) & ~1023;
1002 : : }
1003 : 2 : return size;
1004 : : #endif
1005 : : }
1006 : :
1007 : : /* Format a size as a human-readable string. Caller frees. */
1008 : : char *
1009 : 21 : format_human_readable_size(uint64_t v)
1010 : : {
1011 : : char *s;
1012 [ + + ]: 21 : if (v >= 1000*1000*1000) {
1013 : 8 : s = format("%.1f GB", v/((double)(1000*1000*1000)));
1014 [ + + ]: 13 : } else if (v >= 1000*1000) {
1015 : 3 : s = format("%.1f MB", v/((double)(1000*1000)));
1016 : : } else {
1017 : 10 : s = format("%.1f kB", v/((double)(1000)));
1018 : : }
1019 : 21 : return s;
1020 : : }
1021 : :
1022 : : /* Format a size as a parsable string. Caller frees. */
1023 : : char *
1024 : 9 : format_parsable_size_with_suffix(uint64_t size)
1025 : : {
1026 : : char *s;
1027 [ + + ]: 9 : if (size >= 1000*1000*1000) {
1028 : 3 : s = format("%.1fG", size / ((double)(1000*1000*1000)));
1029 [ + + ]: 6 : } else if (size >= 1000*1000) {
1030 : 4 : s = format("%.1fM", size / ((double)(1000*1000)));
1031 [ + + ]: 2 : } else if (size >= 1000) {
1032 : 1 : s = format("%.1fk", size / ((double)(1000)));
1033 : : } else {
1034 : 1 : s = format("%u", (unsigned)size);
1035 : : }
1036 : 9 : return s;
1037 : : }
1038 : :
1039 : : /*
1040 : : * Parse a "size value", i.e. a string that can end in k, M, G, T (10-based
1041 : : * suffixes) or Ki, Mi, Gi, Ti (2-based suffixes). For backward compatibility,
1042 : : * K is also recognized as a synonym of k.
1043 : : */
1044 : : bool
1045 : 15 : parse_size_with_suffix(const char *str, uint64_t *size)
1046 : : {
1047 : : char *p;
1048 : : double x;
1049 : :
1050 : 15 : errno = 0;
1051 : 15 : x = strtod(str, &p);
1052 [ + - ][ + - ]: 15 : if (errno != 0 || x < 0 || p == str || *str == '\0') {
[ + + ][ - + ]
1053 : 1 : return false;
1054 : : }
1055 : :
1056 [ + + ]: 19 : while (isspace(*p)) {
1057 : 5 : ++p;
1058 : : }
1059 : :
1060 [ + + ]: 14 : if (*p != '\0') {
1061 : : unsigned multiplier;
1062 [ + + ]: 12 : if (*(p+1) == 'i') {
1063 : 5 : multiplier = 1024;
1064 : : } else {
1065 : 7 : multiplier = 1000;
1066 : : }
1067 [ + + + + : 12 : switch (*p) {
- ]
1068 : : case 'T':
1069 : 2 : x *= multiplier;
1070 : : case 'G':
1071 : 4 : x *= multiplier;
1072 : : case 'M':
1073 : 9 : x *= multiplier;
1074 : : case 'K':
1075 : : case 'k':
1076 : 12 : x *= multiplier;
1077 : : break;
1078 : : default:
1079 : 0 : return false;
1080 : : }
1081 : : } else {
1082 : : /* Default suffix: G. */
1083 : 2 : x *= 1000 * 1000 * 1000;
1084 : : }
1085 : 14 : *size = x;
1086 : 15 : return true;
1087 : : }
1088 : :
1089 : :
1090 : : /*
1091 : : a sane realpath() function, trying to cope with stupid path limits and
1092 : : a broken API
1093 : : */
1094 : : char *
1095 : 5 : x_realpath(const char *path)
1096 : : {
1097 : 5 : long maxlen = path_max(path);
1098 : : char *ret, *p;
1099 : : #ifdef _WIN32
1100 : : HANDLE path_handle;
1101 : : #endif
1102 : :
1103 : 5 : ret = x_malloc(maxlen);
1104 : :
1105 : : #if HAVE_REALPATH
1106 : 5 : p = realpath(path, ret);
1107 : : #elif defined(_WIN32)
1108 : : path_handle = CreateFile(
1109 : : path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
1110 : : FILE_ATTRIBUTE_NORMAL, NULL);
1111 : : if (INVALID_HANDLE_VALUE != path_handle) {
1112 : : GetFinalPathNameByHandle(path_handle, ret, maxlen, FILE_NAME_NORMALIZED);
1113 : : CloseHandle(path_handle);
1114 : : p = ret + 4; /* strip \\?\ from the file name */
1115 : : } else {
1116 : : snprintf(ret, maxlen, "%s", path);
1117 : : p = ret;
1118 : : }
1119 : : #else
1120 : : /* yes, there are such systems. This replacement relies on
1121 : : the fact that when we call x_realpath we only care about symlinks */
1122 : : {
1123 : : int len = readlink(path, ret, maxlen-1);
1124 : : if (len == -1) {
1125 : : free(ret);
1126 : : return NULL;
1127 : : }
1128 : : ret[len] = 0;
1129 : : p = ret;
1130 : : }
1131 : : #endif
1132 [ + + ]: 5 : if (p) {
1133 : 4 : p = x_strdup(p);
1134 : 4 : free(ret);
1135 : 4 : return p;
1136 : : }
1137 : 1 : free(ret);
1138 : 5 : return NULL;
1139 : : }
1140 : :
1141 : : /* a getcwd that will returns an allocated buffer */
1142 : : char *
1143 : 101 : gnu_getcwd(void)
1144 : : {
1145 : 101 : unsigned size = 128;
1146 : :
1147 : : while (true) {
1148 : 101 : char *buffer = (char *)x_malloc(size);
1149 [ + - ]: 101 : if (getcwd(buffer, size) == buffer) {
1150 : 101 : return buffer;
1151 : : }
1152 : 0 : free(buffer);
1153 [ # # ]: 0 : if (errno != ERANGE) {
1154 : 0 : cc_log("getcwd error: %d (%s)", errno, strerror(errno));
1155 : 0 : return NULL;
1156 : : }
1157 : 0 : size *= 2;
1158 : 101 : }
1159 : : }
1160 : :
1161 : : #ifndef HAVE_STRTOK_R
1162 : : /* strtok_r replacement */
1163 : : char *
1164 : : strtok_r(char *str, const char *delim, char **saveptr)
1165 : : {
1166 : : int len;
1167 : : char *ret;
1168 : : if (!str)
1169 : : str = *saveptr;
1170 : : len = strlen(str);
1171 : : ret = strtok(str, delim);
1172 : : if (ret) {
1173 : : char *save = ret;
1174 : : while (*save++);
1175 : : if ((len + 1) == (intptr_t) (save - str))
1176 : : save--;
1177 : : *saveptr = save;
1178 : : }
1179 : : return ret;
1180 : : }
1181 : : #endif
1182 : :
1183 : : /*
1184 : : * Create an empty temporary file. *fname will be reallocated and set to the
1185 : : * resulting filename. Returns an open file descriptor to the file.
1186 : : */
1187 : : int
1188 : 9 : create_tmp_fd(char **fname)
1189 : : {
1190 : 9 : char *template = format("%s.%s", *fname, tmp_string());
1191 : 9 : int fd = mkstemp(template);
1192 [ + + ][ + - ]: 9 : if (fd == -1 && errno == ENOENT) {
1193 [ - + ]: 2 : if (create_parent_dirs(template) != 0) {
1194 : 0 : fatal("Failed to create directory %s: %s",
1195 : : dirname(template), strerror(errno));
1196 : : }
1197 : 2 : reformat(&template, "%s.%s", *fname, tmp_string());
1198 : 2 : fd = mkstemp(template);
1199 : : }
1200 [ - + ]: 9 : if (fd == -1) {
1201 : 0 : fatal("Failed to create file %s: %s", template, strerror(errno));
1202 : : }
1203 : :
1204 : : #ifndef _WIN32
1205 : 9 : fchmod(fd, 0666 & ~get_umask());
1206 : : #endif
1207 : :
1208 : 9 : free(*fname);
1209 : 9 : *fname = template;
1210 : 9 : return fd;
1211 : : }
1212 : :
1213 : : /*
1214 : : * Create an empty temporary file. *fname will be reallocated and set to the
1215 : : * resulting filename. Returns an open FILE*.
1216 : : */
1217 : : FILE *
1218 : 4 : create_tmp_file(char **fname, const char *mode)
1219 : : {
1220 : 4 : FILE *file = fdopen(create_tmp_fd(fname), mode);
1221 [ - + ]: 4 : if (!file) {
1222 : 0 : fatal("Failed to create file %s: %s", *fname, strerror(errno));
1223 : : }
1224 : 4 : return file;
1225 : : }
1226 : :
1227 : : /*
1228 : : * Create an empty temporary file. *fname will be reallocated and set to the
1229 : : * resulting filename.
1230 : : */
1231 : : void
1232 : 0 : create_empty_tmp_file(char **fname)
1233 : : {
1234 : 0 : close(create_tmp_fd(fname));
1235 : 0 : }
1236 : :
1237 : : /*
1238 : : * Return current user's home directory, or NULL if it can't be determined.
1239 : : */
1240 : : const char *
1241 : 109 : get_home_directory(void)
1242 : : {
1243 : 109 : const char *p = getenv("HOME");
1244 [ + - ]: 109 : if (p) {
1245 : 109 : return p;
1246 : : }
1247 : : #ifdef _WIN32
1248 : : p = getenv("APPDATA");
1249 : : if (p) {
1250 : : return p;
1251 : : }
1252 : : #endif
1253 : : #ifdef HAVE_GETPWUID
1254 : : {
1255 : 0 : struct passwd *pwd = getpwuid(getuid());
1256 [ # # ]: 0 : if (pwd) {
1257 : 0 : return pwd->pw_dir;
1258 : : }
1259 : : }
1260 : : #endif
1261 : 109 : return NULL;
1262 : : }
1263 : :
1264 : : /*
1265 : : * Get the current directory by reading $PWD. If $PWD isn't sane, gnu_getcwd()
1266 : : * is used. Caller frees.
1267 : : */
1268 : : char *
1269 : 2 : get_cwd(void)
1270 : : {
1271 : : char *pwd;
1272 : : char *cwd;
1273 : : struct stat st_pwd;
1274 : : struct stat st_cwd;
1275 : :
1276 : 2 : cwd = gnu_getcwd();
1277 [ - + ]: 2 : if (!cwd) {
1278 : 0 : return NULL;
1279 : : }
1280 : 2 : pwd = getenv("PWD");
1281 [ - + ]: 2 : if (!pwd) {
1282 : 0 : return cwd;
1283 : : }
1284 [ - + ]: 2 : if (stat(pwd, &st_pwd) != 0) {
1285 : 0 : return cwd;
1286 : : }
1287 [ - + ]: 2 : if (stat(cwd, &st_cwd) != 0) {
1288 : 0 : return cwd;
1289 : : }
1290 [ + - ][ + + ]: 2 : if (st_pwd.st_dev == st_cwd.st_dev && st_pwd.st_ino == st_cwd.st_ino) {
1291 : 1 : free(cwd);
1292 : 1 : return x_strdup(pwd);
1293 : : } else {
1294 : 2 : return cwd;
1295 : : }
1296 : : }
1297 : :
1298 : : /*
1299 : : * Check whether s1 and s2 have the same executable name.
1300 : : */
1301 : : bool
1302 : 8 : same_executable_name(const char *s1, const char *s2)
1303 : : {
1304 : : #ifdef _WIN32
1305 : : bool eq = strcasecmp(s1, s2) == 0;
1306 : : if (!eq) {
1307 : : char *tmp = format("%s.exe", s2);
1308 : : eq = strcasecmp(s1, tmp) == 0;
1309 : : free(tmp);
1310 : : }
1311 : : return eq;
1312 : : #else
1313 : 8 : return str_eq(s1, s2);
1314 : : #endif
1315 : : }
1316 : :
1317 : : /*
1318 : : * Compute the length of the longest directory path that is common to two
1319 : : * paths. s1 is assumed to be the path to a directory.
1320 : : */
1321 : : size_t
1322 : 21 : common_dir_prefix_length(const char *s1, const char *s2)
1323 : : {
1324 : 21 : const char *p1 = s1;
1325 : 21 : const char *p2 = s2;
1326 : :
1327 [ + + ][ + + ]: 182 : while (*p1 && *p2 && *p1 == *p2) {
[ + + ]
1328 : 161 : ++p1;
1329 : 161 : ++p2;
1330 : : }
1331 [ + + ][ + + ]: 34 : while ((*p1 && *p1 != '/') || (*p2 && *p2 != '/')) {
[ + + ][ + + ]
1332 : 13 : p1--;
1333 : 13 : p2--;
1334 : : }
1335 [ + + ][ + + ]: 21 : if (!*p1 && !*p2 && p2 == s2 + 1) {
[ + + ]
1336 : : /* Special case for s1 and s2 both being "/". */
1337 : 1 : return 0;
1338 : : }
1339 : 21 : return p1 - s1;
1340 : : }
1341 : :
1342 : : /*
1343 : : * Compute a relative path from from (an absolute path to a directory) to to (a
1344 : : * path). Assumes that both from and to are well-formed and canonical. Caller
1345 : : * frees.
1346 : : */
1347 : : char *
1348 : 13 : get_relative_path(const char *from, const char *to)
1349 : : {
1350 : : size_t common_prefix_len;
1351 : : int i;
1352 : : const char *p;
1353 : : char *result;
1354 : :
1355 [ + - ][ - + ]: 13 : assert(from && from[0] == '/');
1356 [ - + ]: 13 : assert(to);
1357 : :
1358 [ + - ][ + + ]: 13 : if (!*to || *to != '/') {
1359 : 2 : return x_strdup(to);
1360 : : }
1361 : :
1362 : 11 : result = x_strdup("");
1363 : 11 : common_prefix_len = common_dir_prefix_length(from, to);
1364 [ + + ][ + + ]: 11 : if (common_prefix_len > 0 || !str_eq(from, "/")) {
1365 [ + + ]: 28 : for (p = from + common_prefix_len; *p; p++) {
1366 [ + + ]: 18 : if (*p == '/') {
1367 : 9 : reformat(&result, "../%s", result);
1368 : : }
1369 : : }
1370 : : }
1371 [ + + ]: 11 : if (strlen(to) > common_prefix_len) {
1372 : 8 : reformat(&result, "%s%s", result, to + common_prefix_len + 1);
1373 : : }
1374 : 11 : i = strlen(result) - 1;
1375 [ + + ][ + + ]: 13 : while (i >= 0 && result[i] == '/') {
1376 : 2 : result[i] = '\0';
1377 : 2 : i--;
1378 : : }
1379 [ + + ]: 11 : if (str_eq(result, "")) {
1380 : 2 : free(result);
1381 : 2 : result = x_strdup(".");
1382 : : }
1383 : 13 : return result;
1384 : : }
1385 : :
1386 : : /*
1387 : : * Return whether path is absolute.
1388 : : */
1389 : : bool
1390 : 3 : is_absolute_path(const char *path)
1391 : : {
1392 : : #ifdef _WIN32
1393 : : return path[0] && path[1] == ':';
1394 : : #else
1395 : 3 : return path[0] == '/';
1396 : : #endif
1397 : : }
1398 : :
1399 : : /*
1400 : : * Return whether the argument is a full path.
1401 : : */
1402 : : bool
1403 : 1 : is_full_path(const char *path)
1404 : : {
1405 [ - + ]: 1 : if (strchr(path, '/'))
1406 : 0 : return true;
1407 : : #ifdef _WIN32
1408 : : if (strchr(path, '\\'))
1409 : : return true;
1410 : : #endif
1411 : 1 : return false;
1412 : : }
1413 : :
1414 : : /*
1415 : : * Update the modification time of a file in the cache to save it from LRU
1416 : : * cleanup.
1417 : : */
1418 : : void
1419 : 0 : update_mtime(const char *path)
1420 : : {
1421 : : #ifdef HAVE_UTIMES
1422 : 0 : utimes(path, NULL);
1423 : : #else
1424 : : utime(path, NULL);
1425 : : #endif
1426 : 0 : }
1427 : :
1428 : : /*
1429 : : * If exit() already has been called, call _exit(), otherwise exit(). This is
1430 : : * used to avoid calling exit() inside an atexit handler.
1431 : : */
1432 : : void
1433 : 1 : x_exit(int status)
1434 : : {
1435 : : static bool first_time = true;
1436 [ + - ]: 1 : if (first_time) {
1437 : 1 : first_time = false;
1438 : 1 : exit(status);
1439 : : } else {
1440 : 0 : _exit(status);
1441 : : }
1442 : : }
1443 : :
1444 : : /*
1445 : : * Rename oldpath to newpath (deleting newpath).
1446 : : */
1447 : : int
1448 : 8 : x_rename(const char *oldpath, const char *newpath)
1449 : : {
1450 : : #ifndef _WIN32
1451 : 8 : return rename(oldpath, newpath);
1452 : : #else
1453 : : /* Windows' rename() refuses to overwrite an existing file. */
1454 : : unlink(newpath); /* not x_unlink, as x_unlink calls x_rename */
1455 : : /* If the function succeeds, the return value is nonzero. */
1456 : : if (MoveFileA(oldpath, newpath) == 0) {
1457 : : LPVOID lpMsgBuf;
1458 : : LPVOID lpDisplayBuf;
1459 : : DWORD dw = GetLastError();
1460 : :
1461 : : FormatMessage(
1462 : : FORMAT_MESSAGE_ALLOCATE_BUFFER |
1463 : : FORMAT_MESSAGE_FROM_SYSTEM |
1464 : : FORMAT_MESSAGE_IGNORE_INSERTS,
1465 : : NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf,
1466 : : 0, NULL);
1467 : :
1468 : : lpDisplayBuf = (LPVOID) LocalAlloc(
1469 : : LMEM_ZEROINIT,
1470 : : (lstrlen((LPCTSTR) lpMsgBuf) + lstrlen((LPCTSTR) __FILE__) + 40)
1471 : : * sizeof(TCHAR));
1472 : : _snprintf((LPTSTR) lpDisplayBuf,
1473 : : LocalSize(lpDisplayBuf) / sizeof(TCHAR),
1474 : : TEXT("%s failed with error %d: %s"), __FILE__, dw, lpMsgBuf);
1475 : :
1476 : : cc_log("can't rename file %s to %s OS returned error: %s",
1477 : : oldpath, newpath, (char*) lpDisplayBuf);
1478 : :
1479 : : LocalFree(lpMsgBuf);
1480 : : LocalFree(lpDisplayBuf);
1481 : : return -1;
1482 : : } else {
1483 : : return 0;
1484 : : }
1485 : : #endif
1486 : : }
1487 : :
1488 : : /*
1489 : : * Remove path, NFS hazardous. Use only for temporary files that will not exist
1490 : : * on other systems. That is, the path should include tmp_string().
1491 : : */
1492 : : int
1493 : 8 : tmp_unlink(const char *path)
1494 : : {
1495 : : int rc;
1496 : 8 : cc_log("Unlink %s", path);
1497 : 8 : rc = unlink(path);
1498 [ - + ]: 8 : if (rc) {
1499 : 0 : cc_log("Unlink failed: %s", strerror(errno));
1500 : : }
1501 : 8 : return rc;
1502 : : }
1503 : :
1504 : : /*
1505 : : * Remove path, NFS safe.
1506 : : */
1507 : : int
1508 : 0 : x_unlink(const char *path)
1509 : : {
1510 : : /*
1511 : : * If path is on an NFS share, unlink isn't atomic, so we rename to a temp
1512 : : * file. We don't care if the temp file is trashed, so it's always safe to
1513 : : * unlink it first.
1514 : : */
1515 : 0 : char *tmp_name = format("%s.rm.%s", path, tmp_string());
1516 : 0 : int result = 0;
1517 : 0 : int saved_errno = 0;
1518 : 0 : cc_log("Unlink %s via %s", path, tmp_name);
1519 [ # # ]: 0 : if (x_rename(path, tmp_name) == -1) {
1520 : 0 : result = -1;
1521 : 0 : saved_errno = errno;
1522 : 0 : goto out;
1523 : : }
1524 [ # # ]: 0 : if (unlink(tmp_name) == -1) {
1525 : : /* If it was released in a race, that's OK. */
1526 [ # # ]: 0 : if (errno != ENOENT) {
1527 : 0 : result = -1;
1528 : 0 : saved_errno = errno;
1529 : : }
1530 : : }
1531 : : out:
1532 : 0 : free(tmp_name);
1533 [ # # ]: 0 : if (result) {
1534 : 0 : cc_log("x_unlink failed: %s", strerror(saved_errno));
1535 : : }
1536 : 0 : errno = saved_errno;
1537 : 0 : return result;
1538 : : }
1539 : :
1540 : : #ifndef _WIN32
1541 : : /* Like readlink() but returns the string or NULL on failure. Caller frees. */
1542 : : char *
1543 : 8 : x_readlink(const char *path)
1544 : : {
1545 : 8 : long maxlen = path_max(path);
1546 : : ssize_t len;
1547 : : char *buf;
1548 : :
1549 : 8 : buf = x_malloc(maxlen);
1550 : 8 : len = readlink(path, buf, maxlen-1);
1551 [ + + ]: 8 : if (len == -1) {
1552 : 1 : free(buf);
1553 : 1 : return NULL;
1554 : : }
1555 : 7 : buf[len] = 0;
1556 : 8 : return buf;
1557 : : }
1558 : : #endif
1559 : :
1560 : : /*
1561 : : * Reads the content of a file. Size hint 0 means no hint. Returns true on
1562 : : * success, otherwise false.
1563 : : */
1564 : : bool
1565 : 108 : read_file(const char *path, size_t size_hint, char **data, size_t *size)
1566 : : {
1567 : : int fd, ret;
1568 : 108 : size_t pos = 0, allocated;
1569 : :
1570 [ + + ]: 108 : if (size_hint == 0) {
1571 : : struct stat st;
1572 [ + - ]: 4 : if (x_stat(path, &st) == 0) {
1573 : 4 : size_hint = st.st_size;
1574 : : }
1575 : : }
1576 : 108 : size_hint = (size_hint < 1024) ? 1024 : size_hint;
1577 : :
1578 : 108 : fd = open(path, O_RDONLY | O_BINARY);
1579 [ + + ]: 108 : if (fd == -1) {
1580 : 94 : return false;
1581 : : }
1582 : 14 : allocated = size_hint;
1583 : 14 : *data = x_malloc(allocated);
1584 : : while (true) {
1585 [ - + ]: 28 : if (pos > allocated / 2) {
1586 : 0 : allocated *= 2;
1587 : 0 : *data = x_realloc(*data, allocated);
1588 : : }
1589 : 28 : ret = read(fd, *data + pos, allocated - pos);
1590 [ + + ][ - + ]: 28 : if (ret == 0 || (ret == -1 && errno != EINTR)) {
[ # # ]
1591 : : break;
1592 : : }
1593 [ + - ]: 14 : if (ret > 0) {
1594 : 14 : pos += ret;
1595 : : }
1596 : 14 : }
1597 : 14 : close(fd);
1598 [ - + ]: 14 : if (ret == -1) {
1599 : 0 : cc_log("Failed reading %s", path);
1600 : 0 : free(*data);
1601 : 0 : *data = NULL;
1602 : 0 : return false;
1603 : : }
1604 : :
1605 : 14 : *size = pos;
1606 : 108 : return true;
1607 : : }
1608 : :
1609 : : /*
1610 : : * Return the content (with NUL termination) of a text file, or NULL on error.
1611 : : * Caller frees. Size hint 0 means no hint.
1612 : : */
1613 : : char *
1614 : 107 : read_text_file(const char *path, size_t size_hint)
1615 : : {
1616 : : size_t size;
1617 : : char *data;
1618 : :
1619 [ + + ]: 107 : if (read_file(path, size_hint, &data, &size)) {
1620 : 13 : data = x_realloc(data, size + 1);
1621 : 13 : data[size] = '\0';
1622 : 13 : return data;
1623 : : } else {
1624 : 107 : return NULL;
1625 : : }
1626 : : }
1627 : :
1628 : : static bool
1629 : 21 : expand_variable(const char **str, char **result, char **errmsg)
1630 : : {
1631 : : bool curly;
1632 : : const char *p, *q;
1633 : : char *name;
1634 : : const char *value;
1635 : :
1636 [ - + ]: 21 : assert(**str == '$');
1637 : 21 : p = *str + 1;
1638 [ + + ]: 21 : if (*p == '{') {
1639 : 7 : curly = true;
1640 : 7 : ++p;
1641 : : } else {
1642 : 14 : curly = false;
1643 : : }
1644 : 21 : q = p;
1645 [ + + ][ - + ]: 116 : while (isalnum(*q) || *q == '_') {
1646 : 95 : ++q;
1647 : : }
1648 [ + + ]: 21 : if (curly) {
1649 [ + + ]: 7 : if (*q != '}') {
1650 : 2 : *errmsg = format("syntax error: missing '}' after \"%s\"", p);
1651 : 2 : return NULL;
1652 : : }
1653 : : }
1654 : :
1655 [ + + ]: 19 : if (q == p) {
1656 : : /* Special case: don't consider a single $ the start of a variable. */
1657 : 2 : reformat(result, "%s$", *result);
1658 : 2 : return true;
1659 : : }
1660 : :
1661 : 17 : name = x_strndup(p, q - p);
1662 : 17 : value = getenv(name);
1663 [ + + ]: 17 : if (!value) {
1664 : 1 : *errmsg = format("environment variable \"%s\" not set", name);
1665 : 1 : free(name);
1666 : 1 : return false;
1667 : : }
1668 : 16 : reformat(result, "%s%s", *result, value);
1669 [ + + ]: 16 : if (!curly) {
1670 : 11 : --q;
1671 : : }
1672 : 16 : *str = q;
1673 : 16 : free(name);
1674 : 21 : return true;
1675 : : }
1676 : :
1677 : : /*
1678 : : * Substitute all instances of $VAR or ${VAR}, where VAR is an environment
1679 : : * variable, in a string. Caller frees. If one of the environment variables
1680 : : * doesn't exist, NULL will be returned and *errmsg will be an appropriate
1681 : : * error message (caller frees).
1682 : : */
1683 : : char *
1684 : 32 : subst_env_in_string(const char *str, char **errmsg)
1685 : : {
1686 : : const char *p; /* Interval start. */
1687 : : const char *q; /* Interval end. */
1688 : : char *result;
1689 : :
1690 [ - + ]: 32 : assert(errmsg);
1691 : 32 : *errmsg = NULL;
1692 : :
1693 : 32 : result = x_strdup("");
1694 : 32 : p = str;
1695 : 32 : q = str;
1696 [ + + ]: 956 : for (q = str; *q; ++q) {
1697 [ + + ]: 927 : if (*q == '$') {
1698 : 21 : reformat(&result, "%s%.*s", result, (int)(q - p), p);
1699 [ + + ]: 21 : if (!expand_variable(&q, &result, errmsg)) {
1700 : 3 : free(result);
1701 : 3 : return NULL;
1702 : : }
1703 : 18 : p = q + 1;
1704 : : }
1705 : : }
1706 : 29 : reformat(&result, "%s%.*s", result, (int)(q - p), p);
1707 : 32 : return result;
1708 : : }
|