--- /dev/null
+CFLAGS=-W -Wall -g
+CC=gcc
+
+OBJS= ccache.o mdfour.o hash.o execute.o util.o args.o
+HEADERS = ccache.h mdfour.h
+
+ccache: $(OBJS) $(HEADERS)
+ $(CC) -o $@ $(OBJS)
+
+clean:
+ /bin/rm -f $(OBJS) *~ ccache
--- /dev/null
+#include "ccache.h"
+
+ARGS *args_init(void)
+{
+ ARGS *args;
+ args = malloc(sizeof(ARGS));
+ args->argc = 0;
+ args->argv = malloc(sizeof(char *));
+ args->argv[0] = NULL;
+ return args;
+}
+
+
+void args_add(ARGS *args, const char *s)
+{
+ args->argv = realloc(args->argv, (args->argc + 2) * sizeof(char *));
+ args->argv[args->argc] = strdup(s);
+ args->argc++;
+ args->argv[args->argc] = NULL;
+}
+
--- /dev/null
+/*
+ a re-implementation of the compilercache scripts in C
+ Copyright tridge@samba.org 2002
+
+ The idea is based on the shell-script compilercache by Erik Thiele <erikyyy@erikyyy.de>
+*/
+
+#include "ccache.h"
+
+static char *cache_dir = CACHE_BASEDIR;
+
+
+static ARGS *stripped_args;
+static ARGS *orig_args;
+static char *output_file;
+static char *hashname;
+static int found_debug;
+
+static void failed(void)
+{
+ execv(orig_args->argv[0], orig_args->argv);
+ cc_log("execv returned (%s)!\n", strerror(errno));
+ exit(1);
+}
+
+/* run the real compiler and put the result in cache */
+static void to_cache(ARGS *args)
+{
+ char *path_stdout, *path_status, *path_stderr;
+ struct stat st;
+
+ x_asprintf(&path_status, "%s.status", hashname);
+ x_asprintf(&path_stderr, "%s.stderr", hashname);
+ x_asprintf(&path_stdout, "%s.stdout", hashname);
+
+ args_add(args, "-o");
+ args_add(args, hashname);
+
+ execute(args->argv, path_stdout, path_stderr, path_status);
+
+ args->argc -= 2;
+
+ if (stat(path_stdout, &st) != 0 || st.st_size != 0) {
+ cc_log("compiler produced stdout!\n");
+ unlink(path_stdout);
+ unlink(path_stderr);
+ unlink(path_status);
+ unlink(hashname);
+ failed();
+ }
+
+ unlink(path_stdout);
+ cc_log("Placed %s into cache\n", output_file);
+}
+
+static void stabs_hash(const char *fname)
+{
+ FILE *f;
+ char *s;
+ char line[1024];
+
+ line[sizeof(line)-2] = 0;
+
+ f = fopen(fname, "r");
+ if (!f) {
+ cc_log("Failed to open preprocessor output\n");
+ failed();
+ }
+
+ while ((s = fgets(line, sizeof(line), f))) {
+ if (line[sizeof(line)-2]) {
+ cc_log("line too long in preprocessor output!\n");
+ failed();
+ }
+
+ /* ignore debugging output */
+ if (line[0] == '#' && line[1] == ' ' && isdigit(line[2])) {
+ continue;
+ }
+
+ hash_string(s);
+ }
+
+ fclose(f);
+}
+
+
+/* find the hash for a command. The hash includes all argument lists,
+ plus the output from running the compiler with -E */
+static void find_hash(ARGS *args)
+{
+ int i;
+ char *path_stdout, *path_stderr, *path_status;
+
+ hash_start();
+
+ /* first the arguments */
+ for (i=0;i<args->argc;i++) {
+ hash_string(args->argv[i]);
+ }
+
+ /* now the run */
+ x_asprintf(&path_stdout, "%s/tmp.stdout.%d", cache_dir, getpid());
+ x_asprintf(&path_stderr, "%s/tmp.stderr.%d", cache_dir, getpid());
+ x_asprintf(&path_status, "%s/tmp.status.%d", cache_dir, getpid());
+
+ args_add(args, "-E");
+ execute(args->argv, path_stdout, path_stderr, path_status);
+ args->argc--;
+
+ if (found_debug) {
+ hash_file(path_stdout);
+ } else {
+ stabs_hash(path_stdout);
+ }
+ hash_file(path_stderr);
+ hash_file(path_status);
+
+ unlink(path_stdout);
+ unlink(path_stderr);
+ unlink(path_status);
+ free(path_stdout);
+ free(path_stderr);
+ free(path_status);
+
+ x_asprintf(&hashname, "%s/%s", cache_dir, hash_result());
+}
+
+
+/*
+ try to return the compile result from cache. If we can return from
+ cache then this function exits with the correct status code,
+ otherwise it returns */
+static void from_cache(int first)
+{
+ int fd_status, fd_stderr;
+ char *s;
+ int ret, status;
+
+ x_asprintf(&s, "%s.status", hashname);
+ fd_status = open(s, O_RDONLY);
+ free(s);
+ if (fd_status == -1) {
+ /* its not cached */
+ return;
+ }
+ if (read(fd_status, &status, sizeof(status)) != sizeof(status)) {
+ cc_log("status file is too short\n");
+ close(fd_status);
+ return;
+ }
+ close(fd_status);
+
+ x_asprintf(&s, "%s.stderr", hashname);
+ fd_stderr = open(s, O_RDONLY);
+ free(s);
+ if (fd_stderr == -1) {
+ cc_log("stderr file not found\n");
+ return;
+ }
+
+ unlink(output_file);
+ ret = link(hashname, output_file);
+ if (ret == -1 && errno != ENOENT) {
+ /* copy it instead */
+ cc_log("copy not implemented\n");
+ failed();
+ }
+
+ /* send the stderr */
+ copy_fd(fd_stderr, 2);
+ close(fd_stderr);
+
+ /* and exit with the right status code */
+ if (first) {
+ cc_log("got cached result for %s with status = %d\n",
+ output_file, status);
+ }
+ exit(status);
+}
+
+
+static char *find_compiler(const char *argv0)
+{
+ char *p;
+ char *base;
+ char *path, *tok;
+ struct stat st1, st2;
+
+ /* we compare size, device and inode */
+ if (stat("/proc/self/exe", &st1) != 0) {
+ cc_log("Can't stat ccache executable!?\n");
+ exit(1);
+ }
+
+ p = strrchr(argv0, '/');
+ if (p) {
+ base = p+1;
+ } else {
+ base = argv0;
+ }
+
+ path = getenv("PATH");
+ if (!path) return NULL;
+
+ path = x_strdup(path);
+
+ /* search the path looking for the first compiler of the same name
+ that isn't us */
+ for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) {
+ char *fname;
+ x_asprintf(&fname, "%s/%s", tok, base);
+ if (stat(fname, &st2) == 0) {
+ if (st1.st_size != st2.st_size ||
+ st1.st_dev != st2.st_dev ||
+ st1.st_ino != st2.st_ino) {
+ /* found it! */
+ free(path);
+ return fname;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+
+static void process_args(int argc, char **argv)
+{
+ int i;
+ int found_c_opt = 0;
+ char *input_file = NULL;
+
+ stripped_args = args_init();
+
+ args_add(stripped_args, argv[0]);
+
+ for (i=1; i<argc; i++) {
+ if (strcmp(argv[i], "-E") == 0) {
+ cc_log("Tried to do -E\n");
+ failed();
+ }
+
+ if (strcmp(argv[i], "-c") == 0) {
+ args_add(stripped_args, argv[i]);
+ found_c_opt = 1;
+ continue;
+ }
+
+ if (strcmp(argv[i], "-o") == 0) {
+ if (i == argc-1) {
+ cc_log("missing argument to %s\n", argv[i]);
+ failed();
+ }
+ output_file = argv[i+1];
+ i++;
+ continue;
+ }
+
+ if (strncmp(argv[i], "-g", 2) == 0) {
+ args_add(stripped_args, argv[i]);
+ if (strcmp(argv[i], "-g0") != 0) {
+ found_debug = 1;
+ }
+ continue;
+ }
+
+ /* options that take an argument */
+ if (strcmp(argv[i], "-I") == 0 ||
+ strcmp(argv[i], "-include") == 0 ||
+ strcmp(argv[i], "-L") == 0 ||
+ strcmp(argv[i], "-D") == 0 ||
+ strcmp(argv[i], "-isystem") == 0) {
+ if (i == argc-1) {
+ cc_log("missing argument to %s\n", argv[i]);
+ failed();
+ }
+
+ args_add(stripped_args, argv[i]);
+ args_add(stripped_args, argv[i+1]);
+ i++;
+ continue;
+ }
+
+ if (argv[i][0] == '-') {
+ args_add(stripped_args, argv[i]);
+ continue;
+ }
+
+ if (input_file) {
+ cc_log("multiple input files (%s and %s)\n",
+ input_file, argv[i]);
+ failed();
+ }
+
+ input_file = argv[i];
+ args_add(stripped_args, argv[i]);
+ }
+
+ if (!found_c_opt) {
+ cc_log("No -c option found\n");
+ failed();
+ }
+
+ if (!input_file) {
+ cc_log("No input file found\n");
+ failed();
+ }
+
+ if (!output_file) {
+ char *p;
+ output_file = strdup(input_file);
+ if ((p = strrchr(output_file, '/'))) {
+ output_file = p+1;
+ }
+ p = strrchr(output_file, '.');
+ if (!p || !p[1]) {
+ cc_log("badly formed output_file %s\n", output_file);
+ failed();
+ }
+ p[1] = 'o';
+ p[2] = 0;
+#if 0
+ cc_log("Formed output file %s from input_file %s\n",
+ output_file, input_file);
+#endif
+ }
+}
+
+static void ccache(int argc, char *argv[])
+{
+ /* find the real compiler */
+ argv[0] = find_compiler(argv[0]);
+ if (!argv[0]) {
+ exit(STATUS_NOTFOUND);
+ }
+
+ orig_args = args_init();
+
+ orig_args->argv = argv;
+ orig_args->argc = argc;
+
+ /* process argument list, returning a new set of arguments for pre-processing */
+ process_args(argc, argv);
+
+ /* run with -E to find the hash */
+ find_hash(stripped_args);
+
+ /* if we can return from cache at this point then do */
+ from_cache(1);
+
+ /* run real compiler, semding output to cache */
+ to_cache(stripped_args);
+
+ /* return from cache */
+ from_cache(0);
+
+ /* oh oh! */
+ cc_log("secondary from_cache failed!\n");
+ failed();
+}
+
+
+int main(int argc, char *argv[])
+{
+ if (mkdir(cache_dir, 0755) != 0 && errno != EEXIST) {
+ fprintf(stderr,"Failed to create %s (%s)\n",
+ cache_dir, strerror(errno));
+ exit(1);
+ }
+ ccache(argc, argv);
+ return 1;
+}
--- /dev/null
+#define _GNU_SOURCE
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#define STATUS_NOTFOUND 3
+#define STATUS_FATAL 4
+#define STATUS_NOCACHE 5
+
+
+#define CACHE_BASEDIR "/tmp/ccache"
+#define CCACHE_LOGFILE "/tmp/ccache.log"
+
+typedef unsigned uint32;
+
+#include "mdfour.h"
+
+void hash_start(void);
+void hash_string(const char *s);
+void hash_file(const char *fname);
+char *hash_result(void);
+
+int cc_log(const char *format, ...);
+void fatal(const char *msg);
+void oom(const char *msg);
+
+void copy_fd(int fd_in, int fd_out);
+
+void execute(char **argv,
+ const char *path_stdout,
+ const char *path_stderr,
+ const char *path_status);
+
+typedef struct {
+ char **argv;
+ int argc;
+} ARGS;
+
+
+#define x_asprintf asprintf
+#define x_strdup strdup
+
+ARGS *args_init(void);
+void args_add(ARGS *args, const char *s);
+
+
--- /dev/null
+#include "ccache.h"
+
+
+/*
+ execute a compiler backend, capturing all output to the given paths
+ the full path to the compiler to run is in argv[0]
+*/
+void execute(char **argv,
+ const char *path_stdout,
+ const char *path_stderr,
+ const char *path_status)
+{
+ pid_t pid;
+ int fd;
+ int s, status;
+
+ pid = fork();
+ if (pid == -1) fatal("Failed to fork");
+
+ if (pid == 0) {
+ fd = open(path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
+ if (fd == -1) {
+ exit(STATUS_NOCACHE);
+ }
+ dup2(fd, 1);
+ close(fd);
+
+ fd = open(path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
+ if (fd == -1) {
+ exit(STATUS_NOCACHE);
+ }
+ dup2(fd, 2);
+ close(fd);
+
+ exit(execv(argv[0], argv));
+ }
+
+ if (waitpid(pid, &status, 0) != pid) {
+ fatal("waitpid failed");
+ }
+
+ fd = open(path_status, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644);
+ if (fd == -1) {
+ fatal("Failed to create status file");
+ }
+ s = WEXITSTATUS(status);
+ if (write(fd, &s, sizeof(s)) != sizeof(s)) {
+ fatal("failed to write status file");
+ }
+ close(fd);
+}
+
--- /dev/null
+/*
+ simple front-end functions to mdfour code
+ Copyright tridge@samba.org 2002
+
+*/
+
+#include "ccache.h"
+
+static struct mdfour md;
+
+void hash_start(void)
+{
+ mdfour_begin(&md);
+}
+
+void hash_string(const char *s)
+{
+ mdfour_update(&md, s, strlen(s));
+}
+
+/* add contents of a file to the hash */
+void hash_file(const char *fname)
+{
+ char buf[1024];
+ int fd, n;
+
+ fd = open(fname, O_RDONLY);
+ if (fd == -1) {
+ cc_log("Failed to open %s\n", fname);
+ fatal("hash_file");
+ }
+
+ while ((n = read(fd, buf, sizeof(buf))) > 0) {
+ mdfour_update(&md, buf, n);
+ }
+ close(fd);
+}
+
+/* return the hash result as a static string */
+char *hash_result(void)
+{
+ unsigned char sum[16];
+ static char ret[33];
+ int i;
+
+ mdfour_result(&md, sum);
+
+ for (i=0;i<16;i++) {
+ snprintf(&ret[i*2], 3, "%02x", (unsigned)sum[i]);
+ }
+
+ return ret;
+}
--- /dev/null
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ a implementation of MD4 designed for use in the SMB authentication protocol
+ Copyright (C) Andrew Tridgell 1997-1998.
+
+ 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"
+
+/* NOTE: This code makes no attempt to be fast!
+
+ It assumes that a int is at least 32 bits long
+*/
+
+static struct mdfour *m;
+
+#define MASK32 (0xffffffff)
+
+#define F(X,Y,Z) ((((X)&(Y)) | ((~(X))&(Z))))
+#define G(X,Y,Z) ((((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))))
+#define H(X,Y,Z) (((X)^(Y)^(Z)))
+#define lshift(x,s) (((((x)<<(s))&MASK32) | (((x)>>(32-(s)))&MASK32)))
+
+#define ROUND1(a,b,c,d,k,s) a = lshift((a + F(b,c,d) + M[k])&MASK32, s)
+#define ROUND2(a,b,c,d,k,s) a = lshift((a + G(b,c,d) + M[k] + 0x5A827999)&MASK32,s)
+#define ROUND3(a,b,c,d,k,s) a = lshift((a + H(b,c,d) + M[k] + 0x6ED9EBA1)&MASK32,s)
+
+/* this applies md4 to 64 byte chunks */
+static void mdfour64(uint32 *M)
+{
+ uint32 AA, BB, CC, DD;
+ uint32 A,B,C,D;
+
+ A = m->A; B = m->B; C = m->C; D = m->D;
+ AA = A; BB = B; CC = C; DD = D;
+
+ ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7);
+ ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19);
+ ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7);
+ ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19);
+ ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7);
+ ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19);
+ ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7);
+ ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19);
+
+
+ ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5);
+ ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13);
+ ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5);
+ ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13);
+ ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5);
+ ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13);
+ ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5);
+ ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13);
+
+ ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9);
+ ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15);
+ ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9);
+ ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15);
+ ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9);
+ ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15);
+ ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9);
+ ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15);
+
+ A += AA; B += BB;
+ C += CC; D += DD;
+
+ A &= MASK32; B &= MASK32;
+ C &= MASK32; D &= MASK32;
+
+ m->A = A; m->B = B; m->C = C; m->D = D;
+}
+
+static void copy64(uint32 *M, const unsigned char *in)
+{
+ int i;
+
+ for (i=0;i<16;i++)
+ M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) |
+ (in[i*4+1]<<8) | (in[i*4+0]<<0);
+}
+
+static void copy4(unsigned char *out,uint32 x)
+{
+ out[0] = x&0xFF;
+ out[1] = (x>>8)&0xFF;
+ out[2] = (x>>16)&0xFF;
+ out[3] = (x>>24)&0xFF;
+}
+
+void mdfour_begin(struct mdfour *md)
+{
+ md->A = 0x67452301;
+ md->B = 0xefcdab89;
+ md->C = 0x98badcfe;
+ md->D = 0x10325476;
+ md->totalN = 0;
+}
+
+
+static void mdfour_tail(const unsigned char *in, int n)
+{
+ unsigned char buf[128];
+ uint32 M[16];
+ uint32 b;
+
+ m->totalN += n;
+
+ b = m->totalN * 8;
+
+ memset(buf, 0, 128);
+ if (n) memcpy(buf, in, n);
+ buf[n] = 0x80;
+
+ if (n <= 55) {
+ copy4(buf+56, b);
+ copy64(M, buf);
+ mdfour64(M);
+ } else {
+ copy4(buf+120, b);
+ copy64(M, buf);
+ mdfour64(M);
+ copy64(M, buf+64);
+ mdfour64(M);
+ }
+}
+
+void mdfour_update(struct mdfour *md, const unsigned char *in, int n)
+{
+ uint32 M[16];
+
+ if (n == 0) mdfour_tail(in, n);
+
+ m = md;
+
+ while (n >= 64) {
+ copy64(M, in);
+ mdfour64(M);
+ in += 64;
+ n -= 64;
+ m->totalN += 64;
+ }
+
+ if (n) mdfour_tail(in, n);
+}
+
+
+void mdfour_result(struct mdfour *md, unsigned char *out)
+{
+ m = md;
+
+ copy4(out, m->A);
+ copy4(out+4, m->B);
+ copy4(out+8, m->C);
+ copy4(out+12, m->D);
+}
+
+
+void mdfour(unsigned char *out, unsigned char *in, int n)
+{
+ struct mdfour md;
+ mdfour_begin(&md);
+ mdfour_update(&md, in, n);
+ mdfour_result(&md, out);
+}
+
+#ifdef TEST_MDFOUR
+static void file_checksum1(char *fname)
+{
+ int fd, i;
+ struct mdfour md;
+ unsigned char buf[64*1024], sum[16];
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) {
+ perror("fname");
+ exit(1);
+ }
+
+ mdfour_begin(&md);
+
+ while (1) {
+ int n = read(fd, buf, sizeof(buf));
+ if (n <= 0) break;
+ mdfour_update(&md, buf, n);
+ }
+
+ close(fd);
+
+ mdfour_result(&md, sum);
+
+ for (i=0;i<16;i++)
+ printf("%02X", sum[i]);
+ printf("\n");
+}
+
+#if 0
+#include "../md4.h"
+
+static void file_checksum2(char *fname)
+{
+ int fd, i;
+ MDstruct md;
+ unsigned char buf[64], sum[16];
+
+ fd = open(fname,O_RDONLY);
+ if (fd == -1) {
+ perror("fname");
+ exit(1);
+ }
+
+ MDbegin(&md);
+
+ while (1) {
+ int n = read(fd, buf, sizeof(buf));
+ if (n <= 0) break;
+ MDupdate(&md, buf, n*8);
+ }
+
+ if (!md.done) {
+ MDupdate(&md, buf, 0);
+ }
+
+ close(fd);
+
+ memcpy(sum, md.buffer, 16);
+
+ for (i=0;i<16;i++)
+ printf("%02X", sum[i]);
+ printf("\n");
+}
+#endif
+
+ int main(int argc, char *argv[])
+{
+ file_checksum1(argv[1]);
+#if 0
+ file_checksum2(argv[1]);
+#endif
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ a implementation of MD4 designed for use in the SMB authentication protocol
+ Copyright (C) Andrew Tridgell 1997-1998.
+
+ 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.
+*/
+
+struct mdfour {
+ uint32 A, B, C, D;
+ uint32 totalN;
+};
+
+void mdfour_begin(struct mdfour *md);
+void mdfour_update(struct mdfour *md, const unsigned char *in, int n);
+void mdfour_result(struct mdfour *md, unsigned char *out);
+void mdfour(unsigned char *out, unsigned char *in, int n);
+
+
+
+
--- /dev/null
+foo()
+{
+ printf("blah");
+
--- /dev/null
+#include "ccache.h"
+
+static FILE *logfile;
+
+int cc_log(const char *format, ...)
+{
+ int ret;
+ va_list ap;
+
+ if (!logfile) logfile = fopen(CCACHE_LOGFILE, "a");
+ if (!logfile) return -1;
+
+ va_start(ap, format);
+ ret = vfprintf(logfile, format, ap);
+ va_end(ap);
+ fflush(logfile);
+
+ return ret;
+}
+
+void fatal(const char *msg)
+{
+ cc_log("FATAL: %s\n", msg);
+ exit(1);
+}
+
+void copy_fd(int fd_in, int fd_out)
+{
+ char buf[1024];
+ int n;
+
+ while ((n = read(fd_in, buf, sizeof(buf))) > 0) {
+ if (write(fd_out, buf, n) != n) {
+ fatal("Failed to copy fd");
+ }
+ }
+}
+
+void oom(const char *msg)
+{
+ cc_log("Out of memory: %s\n", msg);
+ exit(1);
+}