summaryrefslogtreecommitdiff
path: root/CCache/util.c
diff options
context:
space:
mode:
authorWilliam S Fulton <wsf@fultondesigns.co.uk>2008-11-03 13:37:28 +0000
committerWilliam S Fulton <wsf@fultondesigns.co.uk>2008-11-03 13:37:28 +0000
commit482d91951a09969d371ec7b5aa3ec65dd9fbccdb (patch)
tree0359fb2db32776aae57f3312b9554d341f920af6 /CCache/util.c
parentd63f23bb84160ba2c5e77add2d97c8f140f9d687 (diff)
downloadswig-482d91951a09969d371ec7b5aa3ec65dd9fbccdb.tar.gz
Import ccache-2.4 source
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10900 626c5289-ae23-0410-ae9c-e8d60b6d4f22
Diffstat (limited to 'CCache/util.c')
-rw-r--r--CCache/util.c454
1 files changed, 454 insertions, 0 deletions
diff --git a/CCache/util.c b/CCache/util.c
new file mode 100644
index 000000000..ec5ccdd49
--- /dev/null
+++ b/CCache/util.c
@@ -0,0 +1,454 @@
+/*
+ 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|O_BINARY);
+ 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|O_BINARY);
+ if (fd == -1 && errno == ENOENT) {
+ fd = open(fname, O_RDWR|O_CREAT|O_EXCL|O_BINARY, 0666);
+ if (fd == -1 && errno == EEXIST) {
+ fd = open(fname, O_RDWR|O_BINARY);
+ }
+ }
+ 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 | O_BINARY, 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|O_BINARY, 0666);
+ if (fd == -1) {
+ return -1;
+ }
+ close(fd);
+ return 0;
+}
+
+/*
+ return current users home directory or die
+*/
+const char *get_home_directory(void)
+{
+ const char *p = getenv("HOME");
+ if (p) {
+ return p;
+ }
+#ifdef HAVE_GETPWUID
+ {
+ struct passwd *pwd = getpwuid(getuid());
+ if (pwd) {
+ return pwd->pw_dir;
+ }
+ }
+#endif
+ fatal("Unable to determine home directory");
+ return NULL;
+}
+