From 59988d94745de4e5940ffe9b516224d4a0191530 Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Wed, 5 Nov 2008 12:34:15 +0000 Subject: [PATCH] initial modifications for ccache to support SWIG git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@10915 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- CCache/README.swig | 3 + CCache/ccache.c | 362 ++++++++++++++++++++++++++++++++------------- CCache/ccache.h | 11 +- CCache/execute.c | 18 +++ CCache/stats.c | 10 +- CCache/util.c | 122 ++++++++++++--- 6 files changed, 400 insertions(+), 126 deletions(-) create mode 100644 CCache/README.swig diff --git a/CCache/README.swig b/CCache/README.swig new file mode 100644 index 000000000..24bd4ff24 --- /dev/null +++ b/CCache/README.swig @@ -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. diff --git a/CCache/ccache.c b/CCache/ccache.c index e87c1516c..b08c4cda1 100644 --- a/CCache/ccache.c +++ b/CCache/ccache.c @@ -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; iargc, 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", diff --git a/CCache/ccache.h b/CCache/ccache.h index bd67cbc67..07d79f8b0 100644 --- a/CCache/ccache.h +++ b/CCache/ccache.h @@ -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 diff --git a/CCache/execute.c b/CCache/execute.c index 4b98ab735..1694f6681 100644 --- a/CCache/execute.c +++ b/CCache/execute.c @@ -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); + } +} diff --git a/CCache/stats.c b/CCache/stats.c index ddaf768db..8be1879d1 100644 --- a/CCache/stats.c +++ b/CCache/stats.c @@ -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 */ diff --git a/CCache/util.c b/CCache/util.c index 6056d36f7..06b290954 100644 --- a/CCache/util.c +++ b/CCache/util.c @@ -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 +} +