diff options
author | William S Fulton <wsf@fultondesigns.co.uk> | 2008-11-03 13:37:28 +0000 |
---|---|---|
committer | William S Fulton <wsf@fultondesigns.co.uk> | 2008-11-03 13:37:28 +0000 |
commit | 482d91951a09969d371ec7b5aa3ec65dd9fbccdb (patch) | |
tree | 0359fb2db32776aae57f3312b9554d341f920af6 /CCache/util.c | |
parent | d63f23bb84160ba2c5e77add2d97c8f140f9d687 (diff) | |
download | swig-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.c | 454 |
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; +} + |