initial modifications for ccache to support SWIG

git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10915 626c5289-ae23-0410-ae9c-e8d60b6d4f22
This commit is contained in:
William S Fulton 2008-11-05 12:34:15 +00:00
commit 59988d9474
6 changed files with 400 additions and 126 deletions

3
CCache/README.swig Normal file
View file

@ -0,0 +1,3 @@
This directory contains a version of ccache. The initial version was based on ccache-2.4 plus
debian patches 01-02, 04-12, see the debian/patches subdirectory. Changes have been made to
support cacheing the output from SWIG. The ability to cache c/c++ compiler output has been retained.

View file

@ -23,6 +23,9 @@
#include "ccache.h"
/* verbose mode */
int ccache_verbose = 0;
/* the base cache directory */
char *cache_dir = NULL;
@ -65,6 +68,9 @@ char *stats_file = NULL;
/* can we safely use the unification hashing backend? */
static int enable_unify;
/* customisation for using the SWIG compiler */
static int swig;
/* a list of supported file extensions, and the equivalent
extension for code that has been through the pre-processor
*/
@ -122,6 +128,14 @@ static void failed(void)
args_add_prefix(orig_args, p);
}
if (ccache_verbose) {
display_execute_args(orig_args->argv);
}
if (swig) {
putenv("CCACHE_OUTFILES");
}
execv(orig_args->argv[0], orig_args->argv);
cc_log("execv returned (%s)!\n", strerror(errno));
perror(orig_args->argv[0]);
@ -149,21 +163,43 @@ static const char *tmp_string(void)
return ret;
}
/* update cached file sizes and count helper function for to_cache() */
static void to_cache_stats_helper(struct stat *pstat, char *cached_filename, char *tmp_outfiles, int *files_size, int *cached_files_count)
{
#if ENABLE_ZLIB
/* do an extra stat on the cache file for the size statistics */
if (stat(cached_filename, pstat) != 0) {
cc_log("failed to stat cache files - %s\n", strerror(errno));
stats_update(STATS_ERROR);
if (tmp_outfiles) {
unlink(tmp_outfiles);
}
failed();
}
#endif
(*files_size) += file_size(pstat);
(*cached_files_count)++;
}
/* run the real compiler and put the result in cache */
static void to_cache(ARGS *args)
{
char *path_stderr;
char *tmp_stdout, *tmp_stderr, *tmp_hashname;
struct stat st1, st2;
char *tmp_stdout, *tmp_stderr, *tmp_outfiles;
struct stat st1;
int status;
int cached_files_count = 0;
int files_size = 0;
x_asprintf(&tmp_stdout, "%s/tmp.stdout.%s", temp_dir, tmp_string());
x_asprintf(&tmp_stderr, "%s/tmp.stderr.%s", temp_dir, tmp_string());
x_asprintf(&tmp_hashname, "%s/tmp.hash.%s.o", temp_dir, tmp_string());
x_asprintf(&tmp_outfiles, "%s/tmp.outfiles.%s", temp_dir, tmp_string());
args_add(args, "-o");
args_add(args, tmp_hashname);
/* TODO swig */
if (output_file) {
args_add(args, "-o");
args_add(args, output_file);
}
/* Turn off DEPENDENCIES_OUTPUT when running cc1, because
* otherwise it will emit a line like
@ -172,90 +208,155 @@ static void to_cache(ARGS *args)
*
* unsetenv() is on BSD and Linux but not portable. */
putenv("DEPENDENCIES_OUTPUT");
/* Give SWIG a filename for it to create and populate with a list of files that it generates */
if (swig) {
char *ccache_outfiles;
x_asprintf(&ccache_outfiles, "CCACHE_OUTFILES=%s", tmp_outfiles);
unlink(tmp_outfiles);
if (getenv("CCACHE_OUTFILES") || putenv(ccache_outfiles) == -1) {
stats_update(STATS_ERROR);
failed();
}
}
if (getenv("CCACHE_CPP2")) {
args_add(args, input_file);
} else {
if (swig) {
args_add(args, "-nopreprocess");
}
args_add(args, i_tmpfile);
}
status = execute(args->argv, tmp_stdout, tmp_stderr);
args_pop(args, 3);
if (stat(tmp_stdout, &st1) != 0 || st1.st_size != 0) {
cc_log("compiler produced stdout for %s\n", output_file);
cc_log("compiler produced stdout for %s\n", input_file);
stats_update(STATS_STDOUT);
unlink(tmp_stdout);
unlink(tmp_stderr);
unlink(tmp_hashname);
unlink(tmp_outfiles);
if (!swig) unlink(output_file);
failed();
}
unlink(tmp_stdout);
if (status != 0) {
int fd;
cc_log("compile of %s gave status = %d\n", output_file, status);
cc_log("compile of %s gave status = %d\n", input_file, status);
stats_update(STATS_STATUS);
fd = open(tmp_stderr, O_RDONLY | O_BINARY);
if (fd != -1) {
if (strcmp(output_file, "/dev/null") == 0 ||
move_file(tmp_hashname, output_file) == 0 || errno == ENOENT) {
if (cpp_stderr) {
/* we might have some stderr from cpp */
int fd2 = open(cpp_stderr, O_RDONLY | O_BINARY);
if (fd2 != -1) {
copy_fd(fd2, 2);
close(fd2);
unlink(cpp_stderr);
cpp_stderr = NULL;
}
if (cpp_stderr) {
/* we might have some stderr from cpp */
int fd2 = open(cpp_stderr, O_RDONLY | O_BINARY);
if (fd2 != -1) {
copy_fd(fd2, 2);
close(fd2);
unlink(cpp_stderr);
cpp_stderr = NULL;
}
/* we can use a quick method of
getting the failed output */
copy_fd(fd, 2);
close(fd);
unlink(tmp_stderr);
if (i_tmpfile && !direct_i_file) {
unlink(i_tmpfile);
}
exit(status);
}
/* we can use a quick method of
getting the failed output */
copy_fd(fd, 2);
close(fd);
unlink(tmp_stderr);
if (i_tmpfile && !direct_i_file) {
unlink(i_tmpfile);
}
exit(status);
}
unlink(tmp_stderr);
unlink(tmp_hashname);
unlink(tmp_outfiles);
if (!swig) unlink(output_file);
failed();
} else {
int hardlink = (getenv("CCACHE_NOCOMPRESS") != 0) && (getenv("CCACHE_HARDLINK") != 0);
if (swig) {
/* read the list of generated files and copy each of them into the cache */
FILE *file;
file = fopen(tmp_outfiles, "r");
if (file) {
char out_filename[FILENAME_MAX + 1];
char out_filename_cache[FILENAME_MAX + 1];
while (fgets(out_filename, FILENAME_MAX, file)) {
char *linefeed = strchr(out_filename, '\n');
if (linefeed) {
*linefeed = 0;
if (cached_files_count == 0) {
strcpy(out_filename_cache, hashname);
} else {
sprintf(out_filename_cache, "%s.%d", hashname, cached_files_count);
}
if (stat(out_filename, &st1) != 0 ||
commit_to_cache(out_filename, out_filename_cache, hardlink) != 0) {
fclose(file);
unlink(tmp_outfiles);
failed();
}
to_cache_stats_helper(&st1, out_filename_cache, tmp_outfiles, &files_size, &cached_files_count);
} else {
cached_files_count = 0;
break;
}
}
fclose(file);
if (cached_files_count == 0) {
cc_log("failed to copy output files to cache - internal error\n");
stats_update(STATS_ERROR);
unlink(tmp_outfiles);
failed();
}
/* also copy the (uncompressed) file containing the list of generated files into the cache */
sprintf(out_filename_cache, "%s.outfiles", hashname);
if (stat(tmp_outfiles, &st1) != 0 ||
safe_rename(tmp_outfiles, out_filename_cache) != 0) {
cc_log("failed to copy outfiles file to cache - %s\n", strerror(errno));
stats_update(STATS_ERROR);
unlink(tmp_outfiles);
failed();
}
to_cache_stats_helper(&st1, out_filename_cache, tmp_outfiles, &files_size, &cached_files_count);
unlink(tmp_outfiles);
} else {
cc_log("failed to open temp outfiles file - %s\n", strerror(errno));
stats_update(STATS_ERROR);
failed();
}
} else {
if (stat(output_file, &st1) != 0 ||
commit_to_cache(output_file, hashname, hardlink) != 0) {
failed();
}
to_cache_stats_helper(&st1, hashname, 0, &files_size, &cached_files_count);
}
}
x_asprintf(&path_stderr, "%s.stderr", hashname);
if (stat(tmp_stderr, &st1) != 0 ||
stat(tmp_hashname, &st2) != 0 ||
move_file(tmp_hashname, hashname) != 0 ||
move_file(tmp_stderr, path_stderr) != 0) {
cc_log("failed to rename tmp files - %s\n", strerror(errno));
stats_update(STATS_ERROR);
failed();
}
#if ENABLE_ZLIB
/* do an extra stat on the cache files for
the size statistics */
if (stat(path_stderr, &st1) != 0 ||
stat(hashname, &st2) != 0) {
cc_log("failed to stat cache files - %s\n", strerror(errno));
stats_update(STATS_ERROR);
failed();
}
#endif
to_cache_stats_helper(&st1, path_stderr, 0, &files_size, &cached_files_count);
cc_log("Placed %s into cache\n", output_file);
stats_tocache(file_size(&st1) + file_size(&st2));
cc_log("Placed %d files for %s into cache\n", cached_files_count, input_file);
stats_tocache(files_size, cached_files_count);
free(tmp_hashname);
free(tmp_stderr);
free(tmp_stdout);
free(tmp_outfiles);
free(path_stderr);
}
@ -288,7 +389,7 @@ static void find_hash(ARGS *args)
}
/* we have to hash the extension, as a .i file isn't treated the same
by the compiler as a .ii file */
by the compiler as a .ii file (Note: not strictly necessary for SWIG) */
hash_string(i_extension);
/* first the arguments */
@ -383,7 +484,7 @@ static void find_hash(ARGS *args)
/* we are compiling a .i or .ii file - that means we
can skip the cpp stage and directly form the
correct i_tmpfile */
path_stdout = input_file;
path_stdout = x_strdup(input_file);
if (create_empty_file(path_stderr) != 0) {
stats_update(STATS_ERROR);
cc_log("failed to create empty stderr file\n");
@ -456,7 +557,6 @@ static void find_hash(ARGS *args)
free(hash_dir);
}
/*
try to return the compile result from cache. If we can return from
cache then this function exits with the correct status code,
@ -465,7 +565,6 @@ static void from_cache(int first)
{
int fd_stderr, fd_cpp_stderr;
char *stderr_file;
int ret;
struct stat st;
x_asprintf(&stderr_file, "%s.stderr", hashname);
@ -488,56 +587,81 @@ static void from_cache(int first)
#ifndef ENABLE_ZLIB
/* if the cache file is compressed we must recache */
if ((first && getenv("CCACHE_RECACHE")) ||
test_if_compressed(hashname) == 1) {
test_if_compressed(hashname) == 1)
#else
if (first && getenv("CCACHE_RECACHE")) {
if (first && getenv("CCACHE_RECACHE"))
#endif
{
close(fd_stderr);
unlink(stderr_file);
free(stderr_file);
return;
}
/* update timestamps for LRU cleanup
also gives output_file a sensible mtime when hard-linking (for make) */
#ifdef HAVE_UTIMES
utimes(hashname, NULL);
utimes(stderr_file, NULL);
#else
utime(hashname, NULL);
utime(stderr_file, NULL);
#endif
if (first) {
int hardlink;
int passfail = -1;
if (strcmp(output_file, "/dev/null") == 0) {
ret = 0;
} else {
unlink(output_file);
/* only make a hardlink if the cache file is uncompressed */
if (getenv("CCACHE_HARDLINK") &&
test_if_compressed(hashname) == 0) {
ret = link(hashname, output_file);
/* update timestamps for LRU cleanup
also gives output_file a sensible mtime when hard-linking (for make) */
x_utimes(stderr_file);
hardlink = (getenv("CCACHE_HARDLINK") != 0);
if (swig) {
/* read the list of generated files and copy each of them out of the cache */
FILE *file;
char *outfiles;
x_asprintf(&outfiles, "%s.outfiles", hashname);
file = fopen(outfiles, "r");
if (file) {
char out_filename[FILENAME_MAX + 1];
char out_filename_cache[FILENAME_MAX + 1];
int retrieved_files_count = 0;
x_utimes(outfiles);
while (fgets(out_filename, FILENAME_MAX, file)) {
char *linefeed = strchr(out_filename, '\n');
if (linefeed) {
*linefeed = 0;
if (retrieved_files_count == 0) {
strcpy(out_filename_cache, hashname);
} else {
sprintf(out_filename_cache, "%s.%d", hashname, retrieved_files_count);
}
passfail = retrieve_from_cache(out_filename_cache, out_filename, hardlink);
if (passfail == -1) {
break;
}
retrieved_files_count++;
} else {
cc_log("failed to copy output files from cache - internal error\n");
stats_update(STATS_ERROR);
passfail = -1;
break;
}
}
if (retrieved_files_count == 0) {
cc_log("failed to copy output files from cache - internal error\n");
stats_update(STATS_ERROR);
passfail = -1;
}
fclose(file);
} else {
cc_log("failed to open cached outfiles file - %s\n", strerror(errno));
stats_update(STATS_ERROR);
}
} else {
ret = copy_file(hashname, output_file);
passfail = retrieve_from_cache(hashname, output_file, hardlink);
}
}
/* the hash file might have been deleted by some external process */
if (ret == -1 && errno == ENOENT) {
cc_log("hashfile missing for %s\n", output_file);
stats_update(STATS_MISSING);
close(fd_stderr);
unlink(stderr_file);
return;
}
free(stderr_file);
if (ret == -1) {
ret = copy_file(hashname, output_file);
if (ret == -1) {
cc_log("failed to copy %s -> %s (%s)\n",
hashname, output_file, strerror(errno));
stats_update(STATS_ERROR);
failed();
free(stderr_file);
if (passfail == -1) {
close(fd_stderr);
unlink(stderr_file);
return;
}
}
@ -566,7 +690,7 @@ static void from_cache(int first)
/* and exit with the right status code */
if (first) {
cc_log("got cached result for %s\n", output_file);
cc_log("got cached result for %s\n", input_file);
stats_update(STATS_CACHED);
}
@ -597,7 +721,7 @@ static void find_compiler(int argc, char **argv)
/* support user override of the compiler */
if ((path=getenv("CCACHE_CC"))) {
base = strdup(path);
base = x_strdup(path);
}
orig_args->argv[0] = find_executable(base, MYNAME);
@ -622,6 +746,8 @@ static const char *check_extension(const char *fname, int *direct_i)
*direct_i = 0;
}
if (swig) return "ii"; /* any file extension is acceptable as input for SWIG */
p = strrchr(fname, '.');
if (!p) return NULL;
p++;
@ -662,6 +788,11 @@ static void process_args(int argc, char **argv)
args_add(stripped_args, argv[0]);
/* -c not required for SWIG */
if (swig) {
found_c_opt = 1;
}
for (i=1; i<argc; i++) {
/* some options will never work ... */
if (strcmp(argv[i], "-E") == 0) {
@ -709,9 +840,11 @@ static void process_args(int argc, char **argv)
}
/* alternate form of -o, with no space */
if (strncmp(argv[i], "-o", 2) == 0) {
output_file = &argv[i][2];
continue;
if (!swig) { /* some of SWIG's arguments begin with -o */
if (strncmp(argv[i], "-o", 2) == 0) {
output_file = &argv[i][2];
continue;
}
}
/* debugging is handled specially, so that we know if we
@ -747,6 +880,13 @@ static void process_args(int argc, char **argv)
dependency_target_specified = 1;
}
/* the input file is already preprocessed */
if (swig && strcmp(argv[i], "-nopreprocess") == 0) {
args_add(stripped_args, argv[i]);
direct_i_file = 1;
continue;
}
/* options that take an argument */
{
const char *opts[] = {"-I", "-include", "-imacros", "-iprefix",
@ -817,7 +957,11 @@ static void process_args(int argc, char **argv)
failed();
}
i_extension = check_extension(input_file, &direct_i_file);
if (swig) {
i_extension = check_extension(input_file, NULL);
} else {
i_extension = check_extension(input_file, &direct_i_file);
}
if (i_extension == NULL) {
cc_log("Not a C/C++ file - %s\n", input_file);
stats_update(STATS_NOTC);
@ -843,7 +987,7 @@ static void process_args(int argc, char **argv)
failed();
}
if (!output_file) {
if (!swig && !output_file) {
char *p;
output_file = x_strdup(input_file);
if ((p = strrchr(output_file, '/'))) {
@ -895,7 +1039,7 @@ static void process_args(int argc, char **argv)
}
/* cope with -o /dev/null */
if (strcmp(output_file,"/dev/null") != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {
if (output_file && strcmp(output_file,"/dev/null") != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {
cc_log("Not a regular file %s\n", output_file);
stats_update(STATS_DEVICE);
failed();
@ -934,6 +1078,10 @@ static void ccache(int argc, char *argv[])
enable_unify = 1;
}
if (getenv("CCACHE_SWIG")) {
swig = 1;
}
/* process argument list, returning a new set of arguments for pre-processing */
process_args(orig_args->argc, orig_args->argv);
@ -963,7 +1111,7 @@ static void ccache(int argc, char *argv[])
static void usage(void)
{
printf("ccache, a compiler cache. Version %s\n", CCACHE_VERSION);
printf("ccache, a compiler cache, with modifications for SWIG. Version %s\n", CCACHE_VERSION);
printf("Copyright Andrew Tridgell, 2002\n\n");
printf("Usage:\n");
@ -998,7 +1146,7 @@ static int ccache_main(int argc, char *argv[])
while ((c = getopt(argc, argv, "hszcCF:M:V")) != -1) {
switch (c) {
case 'V':
printf("ccache version %s\n", CCACHE_VERSION);
printf("ccache with modifications for SWIG version %s\n", CCACHE_VERSION);
printf("Copyright Andrew Tridgell 2002\n");
printf("Released under the GNU GPL v2 or later\n");
exit(0);
@ -1097,13 +1245,12 @@ int main(int argc, char *argv[])
}
}
temp_dir = getenv("CCACHE_TEMPDIR");
if (!temp_dir) {
temp_dir = cache_dir;
}
cache_logfile = getenv("CCACHE_LOGFILE");
if (getenv("CCACHE_VERBOSE")) {
ccache_verbose = 1;
}
setup_uncached_err();
@ -1140,6 +1287,17 @@ int main(int argc, char *argv[])
exit(1);
}
temp_dir = getenv("CCACHE_TEMPDIR");
if (!temp_dir) {
x_asprintf(&temp_dir, "%s/temp", cache_dir);
/* make sure temp dir exists if not supplied by user */
if (temp_dir && create_dir(temp_dir) != 0) {
fprintf(stderr,"ccache: failed to create %s (%s)\n",
temp_dir, strerror(errno));
exit(1);
}
}
if (!getenv("CCACHE_READONLY")) {
if (create_cachedirtag(cache_dir) != 0) {
fprintf(stderr,"ccache: failed to create %s/CACHEDIR.TAG (%s)\n",

View file

@ -92,10 +92,13 @@ void cc_log(const char *format, ...);
void fatal(const char *msg);
void copy_fd(int fd_in, int fd_out);
int copy_file(const char *src, const char *dest);
int safe_rename(const char* oldpath, const char* newpath);
int move_file(const char *src, const char *dest);
int test_if_compressed(const char *filename);
int commit_to_cache(const char *src, const char *dest, int hardlink);
int retrieve_from_cache(const char *src, const char *dest, int hardlink);
int create_dir(const char *dir);
int create_cachedirtag(const char *dir);
void x_asprintf(char **ptr, const char *format, ...);
@ -112,11 +115,12 @@ char *x_realpath(const char *path);
char *gnu_getcwd(void);
int create_empty_file(const char *fname);
const char *get_home_directory(void);
int x_utimes(const char *filename);
void stats_update(enum stats stat);
void stats_zero(void);
void stats_summary(void);
void stats_tocache(size_t size);
void stats_tocache(size_t size, size_t numfiles);
void stats_read(const char *stats_file, unsigned counters[STATS_END]);
int stats_set_limits(long maxfiles, long maxsize);
size_t value_units(const char *s);
@ -144,6 +148,7 @@ int execute(char **argv,
const char *path_stdout,
const char *path_stderr);
char *find_executable(const char *name, const char *exclude_name);
void display_execute_args(char **argv);
typedef struct {
char **argv;
@ -158,6 +163,8 @@ void args_pop(ARGS *args, int n);
void args_strip(ARGS *args, const char *prefix);
void args_remove_first(ARGS *args);
extern int ccache_verbose;
#if HAVE_COMPAR_FN_T
#define COMPAR_FN_T __compar_fn_t
#else

View file

@ -36,6 +36,11 @@ int execute(char **argv,
if (pid == 0) {
int fd;
/* TODO: needs moving after possible exit() below, but before stdout is redirected */
if (ccache_verbose) {
display_execute_args(argv);
}
unlink(path_stdout);
fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
if (fd == -1) {
@ -127,3 +132,16 @@ char *find_executable(const char *name, const char *exclude_name)
return NULL;
}
void display_execute_args(char **argv)
{
if (argv) {
printf("ccache executing: ");
while (*argv) {
printf("%s ", *argv);
++argv;
}
printf("\n");
fflush(stdout);
}
}

View file

@ -116,7 +116,7 @@ static void stats_read_fd(int fd, unsigned counters[STATS_END])
}
/* update the stats counter for this compile */
static void stats_update_size(enum stats stat, size_t size)
static void stats_update_size(enum stats stat, size_t size, size_t numfiles)
{
int fd;
unsigned counters[STATS_END];
@ -147,7 +147,7 @@ static void stats_update_size(enum stats stat, size_t size)
/* on a cache miss we up the file count and size */
if (stat == STATS_TOCACHE) {
counters[STATS_NUMFILES] += 2;
counters[STATS_NUMFILES] += numfiles;
counters[STATS_TOTALSIZE] += size;
}
@ -173,18 +173,18 @@ static void stats_update_size(enum stats stat, size_t size)
}
/* record a cache miss */
void stats_tocache(size_t size)
void stats_tocache(size_t size, size_t numfiles)
{
/* convert size to kilobytes */
size = size / 1024;
stats_update_size(STATS_TOCACHE, size);
stats_update_size(STATS_TOCACHE, size, numfiles);
}
/* update a normal stat */
void stats_update(enum stats stat)
{
stats_update_size(stat, 0);
stats_update_size(stat, 0, 0);
}
/* read in the stats from one dir and add to the counters */

View file

@ -44,21 +44,7 @@ void fatal(const char *msg)
exit(1);
}
#ifndef ENABLE_ZLIB
/* 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");
}
}
}
static int safe_rename(const char* oldpath, const char* newpath)
int safe_rename(const char* oldpath, const char* newpath)
{
/* safe_rename is for creating entries in the cache.
@ -75,6 +61,20 @@ static int safe_rename(const char* oldpath, const char* newpath)
}
}
#ifndef ENABLE_ZLIB
/* 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");
}
}
}
/* move a file using rename */
int move_file(const char *src, const char *dest) {
return safe_rename(src, dest);
@ -83,7 +83,7 @@ int move_file(const char *src, const char *dest) {
/* 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)
static int copy_file(const char *src, const char *dest)
{
int fd1, fd2;
char buf[10240];
@ -143,6 +143,16 @@ int copy_file(const char *src, const char *dest)
return 0;
}
/* copy a file to the cache */
static int copy_file_to_cache(const char *src, const char *dest) {
return copy_file(src, dest);
}
/* copy a file from the cache */
static int copy_file_from_cache(const char *src, const char *dest) {
return copy_file(src, dest);
}
#else /* ENABLE_ZLIB */
/* copy all data from one file descriptor to another
@ -286,8 +296,13 @@ int move_file(const char *src, const char *dest) {
return ret;
}
/* copy a file to the cache, compressing it */
static int copy_file_to_cache(const char *src, const char *dest) {
return _copy_file(src, dest, COPY_TO_CACHE);
}
/* copy a file from the cache, decompressing it */
int copy_file(const char *src, const char *dest) {
static int copy_file_from_cache(const char *src, const char *dest) {
return _copy_file(src, dest, COPY_FROM_CACHE);
}
#endif /* ENABLE_ZLIB */
@ -312,6 +327,61 @@ int test_if_compressed(const char *filename) {
return 1;
}
/* copy file to the cache with error checking taking into account compression and hard linking if desired */
int commit_to_cache(const char *src, const char *dest, int hardlink)
{
int ret = -1;
unlink(dest);
if (hardlink) {
ret = link(src, dest);
}
if (ret == -1) {
ret = copy_file_to_cache(src, dest);
if (ret == -1) {
cc_log("failed to commit %s -> %s (%s)\n", src, dest, strerror(errno));
stats_update(STATS_ERROR);
}
}
return ret;
}
/* copy file out of the cache with error checking taking into account compression and hard linking if desired */
int retrieve_from_cache(const char *src, const char *dest, int hardlink)
{
int ret = 0;
x_utimes(src);
if (strcmp(dest, "/dev/null") == 0) {
ret = 0;
} else {
unlink(dest);
/* only make a hardlink if the cache file is uncompressed */
if (hardlink && test_if_compressed(src) == 0) {
ret = link(src, dest);
} else {
ret = copy_file_from_cache(src, dest);
}
}
/* the cached file might have been deleted by some external process */
if (ret == -1 && errno == ENOENT) {
cc_log("hashfile missing for %s\n", dest);
stats_update(STATS_MISSING);
return -1;
}
if (ret == -1) {
ret = copy_file_from_cache(src, dest);
if (ret == -1) {
cc_log("failed to retrieve %s -> %s (%s)\n", src, dest, strerror(errno));
stats_update(STATS_ERROR);
return -1;
}
}
return ret;
}
/* make sure a directory exists */
int create_dir(const char *dir)
{
@ -410,15 +480,24 @@ void *x_malloc(size_t size)
void *x_realloc(void *ptr, size_t size)
{
void *p2;
#if 1
/* Avoid invalid read in memcpy below */
p2 = realloc(ptr, size);
if (!p2) {
fatal("out of memory in x_realloc");
}
#else
if (!ptr) return x_malloc(size);
p2 = malloc(size);
if (!p2) {
fatal("out of memory in x_realloc");
}
if (ptr) {
/* Note invalid read as the memcpy reads beyond the memory allocated by ptr */
memcpy(p2, ptr, size);
free(ptr);
}
#endif
return p2;
}
@ -676,3 +755,12 @@ const char *get_home_directory(void)
return NULL;
}
int x_utimes(const char *filename)
{
#ifdef HAVE_UTIMES
return utimes(filename, NULL);
#else
return utime(filename, NULL);
#endif
}