LCOV - code coverage report
Current view: top level - ccache - util.c (source / functions) Hit Total Coverage
Test: ccache.lcov.info Lines: 431 628 68.6 %
Date: 2015-06-29 Functions: 50 62 80.6 %
Branches: 210 365 57.5 %

           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                 :            : }

Generated by: LCOV version 1.9