Logo Search packages:      
Sourcecode: ccache version File versions

util.c

/*
   Copyright (C) Andrew Tridgell 2002
   
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
   
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "ccache.h"

static FILE *logfile;

/* log a message to the CCACHE_LOGFILE location */
void cc_log(const char *format, ...)
{
      va_list ap;
      extern char *cache_logfile;

      if (!cache_logfile) return;

      if (!logfile) logfile = fopen(cache_logfile, "a");
      if (!logfile) return;
      
      va_start(ap, format);
      vfprintf(logfile, format, ap);
      va_end(ap);
      fflush(logfile);
}

/* something went badly wrong! */
void fatal(const char *msg)
{
      cc_log("FATAL: %s\n", msg);
      exit(1);
}

/* copy all data from one file descriptor to another */
void copy_fd(int fd_in, int fd_out)
{
      char buf[10240];
      int n;

      while ((n = read(fd_in, buf, sizeof(buf))) > 0) {
            if (write(fd_out, buf, n) != n) {
                  fatal("Failed to copy fd");
            }
      }
}

/* copy a file - used when hard links don't work 
   the copy is done via a temporary file and atomic rename
*/
int copy_file(const char *src, const char *dest)
{
      int fd1, fd2;
      char buf[10240];
      int n;
      char *tmp_name;
      mode_t mask;

      x_asprintf(&tmp_name, "%s.XXXXXX", dest);

      fd1 = open(src, O_RDONLY);
      if (fd1 == -1) {
            free(tmp_name);
            return -1;
      }

      fd2 = mkstemp(tmp_name);
      if (fd2 == -1) {
            close(fd1);
            free(tmp_name);
            return -1;
      }

      while ((n = read(fd1, buf, sizeof(buf))) > 0) {
            if (write(fd2, buf, n) != n) {
                  close(fd2);
                  close(fd1);
                  unlink(tmp_name);
                  free(tmp_name);
                  return -1;
            }
      }

      close(fd1);

      /* get perms right on the tmp file */
      mask = umask(0);
      fchmod(fd2, 0666 & ~mask);
      umask(mask);

      /* the close can fail on NFS if out of space */
      if (close(fd2) == -1) {
            unlink(tmp_name);
            free(tmp_name);
            return -1;
      }

      unlink(dest);

      if (rename(tmp_name, dest) == -1) {
            unlink(tmp_name);
            free(tmp_name);
            return -1;
      }

      free(tmp_name);

      return 0;
}


/* make sure a directory exists */
int create_dir(const char *dir)
{
      struct stat st;
      if (stat(dir, &st) == 0) {
            if (S_ISDIR(st.st_mode)) {
                  return 0;
            }
            errno = ENOTDIR;
            return 1;
      }
      if (mkdir(dir, 0777) != 0 && errno != EEXIST) {
            return 1;
      }
      return 0;
}

/*
  this is like asprintf() but dies if the malloc fails
  note that we use vsnprintf in a rather poor way to make this more portable
*/
void x_asprintf(char **ptr, const char *format, ...)
{
      va_list ap;

      *ptr = NULL;
      va_start(ap, format);
      vasprintf(ptr, format, ap);
      va_end(ap);
      
      if (!ptr) fatal("out of memory in x_asprintf");
}

/*
  this is like strdup() but dies if the malloc fails
*/
char *x_strdup(const char *s)
{
      char *ret;
      ret = strdup(s);
      if (!ret) {
            fatal("out of memory in strdup\n");
      }
      return ret;
}

/*
  this is like malloc() but dies if the malloc fails
*/
void *x_malloc(size_t size)
{
      void *ret;
      ret = malloc(size);
      if (!ret) {
            fatal("out of memory in malloc\n");
      }
      return ret;
}

/*
  this is like realloc() but dies if the malloc fails
*/
void *x_realloc(void *ptr, size_t size)
{
      void *p2;
      if (!ptr) return x_malloc(size);
      p2 = malloc(size);
      if (!p2) {
            fatal("out of memory in x_realloc");
      }
      if (ptr) {
            memcpy(p2, ptr, size);
            free(ptr);
      }
      return p2;
}


/* 
   revsusive directory traversal - used for cleanup
   fn() is called on all files/dirs in the tree
 */
void traverse(const char *dir, void (*fn)(const char *, struct stat *))
{
      DIR *d;
      struct dirent *de;

      d = opendir(dir);
      if (!d) return;

      while ((de = readdir(d))) {
            char *fname;
            struct stat st;

            if (strcmp(de->d_name,".") == 0) continue;
            if (strcmp(de->d_name,"..") == 0) continue;

            if (strlen(de->d_name) == 0) continue;

            x_asprintf(&fname, "%s/%s", dir, de->d_name);
            if (lstat(fname, &st)) {
                  if (errno != ENOENT) {
                        perror(fname);
                  }
                  free(fname);
                  continue;
            }

            if (S_ISDIR(st.st_mode)) {
                  traverse(fname, fn);
            }

            fn(fname, &st);
            free(fname);
      }

      closedir(d);
}


/* return the base name of a file - caller frees */
char *str_basename(const char *s)
{
      char *p = strrchr(s, '/');
      if (p) {
            return x_strdup(p+1);
      } 

      return x_strdup(s);
}

/* return the dir name of a file - caller frees */
char *dirname(char *s)
{
      char *p;
      s = x_strdup(s);
      p = strrchr(s, '/');
      if (p) {
            *p = 0;
      } 
      return s;
}

int lock_fd(int fd)
{
      struct flock fl;
      int ret;

      fl.l_type = F_WRLCK;
      fl.l_whence = SEEK_SET;
      fl.l_start = 0;
      fl.l_len = 1;
      fl.l_pid = 0;

      /* not sure why we would be getting a signal here,
         but one user claimed it is possible */
      do {
            ret = fcntl(fd, F_SETLKW, &fl);
      } while (ret == -1 && errno == EINTR);
      return ret;
}

/* return size on disk of a file */
size_t file_size(struct stat *st)
{
      size_t size = st->st_blocks * 512;
      if ((size_t)st->st_size > size) {
            /* probably a broken stat() call ... */
            size = (st->st_size + 1023) & ~1023;
      }
      return size;
}


/* a safe open/create for read-write */
int safe_open(const char *fname)
{
      int fd = open(fname, O_RDWR);
      if (fd == -1 && errno == ENOENT) {
            fd = open(fname, O_RDWR|O_CREAT|O_EXCL, 0666);
            if (fd == -1 && errno == EEXIST) {
                  fd = open(fname, O_RDWR);
            }
      }
      return fd;
}

/* display a kilobyte unsigned value in M, k or G */
void display_size(unsigned v)
{
      if (v > 1024*1024) {
            printf("%8.1f Gbytes", v/((double)(1024*1024)));
      } else if (v > 1024) {
            printf("%8.1f Mbytes", v/((double)(1024)));
      } else {
            printf("%8u Kbytes", v);
      }
}

/* return a value in multiples of 1024 give a string that can end
   in K, M or G
*/
size_t value_units(const char *s)
{
      char m;
      double v = atof(s);
      m = s[strlen(s)-1];
      switch (m) {
      case 'G':
      case 'g':
      default:
            v *= 1024*1024;
            break;
      case 'M':
      case 'm':
            v *= 1024;
            break;
      case 'K':
      case 'k':
            v *= 1;
            break;
      }
      return (size_t)v;
}


/*
  a sane realpath() function, trying to cope with stupid path limits and 
  a broken API
*/
char *x_realpath(const char *path)
{
      int maxlen;
      char *ret, *p;
#ifdef PATH_MAX
      maxlen = PATH_MAX;
#elif defined(MAXPATHLEN)
      maxlen = MAXPATHLEN;
#elif defined(_PC_PATH_MAX)
      maxlen = pathconf(path, _PC_PATH_MAX);
#endif
      if (maxlen < 4096) maxlen = 4096;
      
      ret = x_malloc(maxlen);

#if HAVE_REALPATH
      p = realpath(path, ret);
#else
      /* yes, there are such systems. This replacement relies on
         the fact that when we call x_realpath we only care about symlinks */
      {
            int len = readlink(path, ret, maxlen-1);
            if (len == -1) {
                  free(ret);
                  return NULL;
            }
            ret[len] = 0;
            p = ret;
      }
#endif
      if (p) {
            p = x_strdup(p);
            free(ret);
            return p;
      }
      free(ret);
      return NULL;
}

/* a getcwd that will returns an allocated buffer */
char *gnu_getcwd(void)
{
      unsigned size = 128;

      while (1) {
            char *buffer = (char *)x_malloc(size);
            if (getcwd(buffer, size) == buffer) {
                  return buffer;
            }
            free(buffer);
            if (errno != ERANGE) {
                  return 0;
            }
            size *= 2;
      }
}

#ifndef HAVE_MKSTEMP
/* cheap and nasty mkstemp replacement */
int mkstemp(char *template)
{
      mktemp(template);
      return open(template, O_RDWR | O_CREAT | O_EXCL, 0600);
}
#endif


/* create an empty file */
int create_empty_file(const char *fname)
{
      int fd;

      fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0666);
      if (fd == -1) {
            return -1;
      }
      close(fd);
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index