Source files for ccache-2.4 and Android patches
[android/toolchain/ccache.git] / patches / ccache-2.4-win32-fixes.patch
1 diff -uwrN ccache-2.4-org/args.c ccache-2.4/args.c
2 --- ccache-2.4-org/args.c       2007-09-05 13:35:09.000000000 +0200
3 +++ ccache-2.4/args.c   2007-09-05 13:35:18.000000000 +0200
4 @@ -38,7 +38,7 @@
5  void args_add(ARGS *args, const char *s)
6  {
7         args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
8 -       args->argv[args->argc] = x_strdup(s);
9 +       args->argv[args->argc] = x_quotedup(s);
10         args->argc++;
11         args->argv[args->argc] = NULL;
12  }
13 @@ -69,7 +69,7 @@
14         args->argv = (char**)x_realloc(args->argv, (args->argc + 2) * sizeof(char *));
15         memmove(&args->argv[1], &args->argv[0], 
16                 (args->argc+1) * sizeof(args->argv[0]));
17 -       args->argv[0] = x_strdup(s);
18 +       args->argv[0] = x_quotedup(s);
19         args->argc++;
20  }
21  
22 diff -uwrN ccache-2.4-org/ccache.c ccache-2.4/ccache.c
23 --- ccache-2.4-org/ccache.c     2007-09-05 13:35:09.000000000 +0200
24 +++ ccache-2.4/ccache.c 2007-09-05 13:35:18.000000000 +0200
25 @@ -125,12 +125,44 @@
26                 args_add_prefix(orig_args, p);
27         }
28  
29 +#if 0
30 +    {
31 +        int  nn;
32 +        cc_log("execv =>");
33 +        for (nn = 0; orig_args->argv[nn] != NULL; nn++)
34 +            cc_log(" %s", orig_args->argv[nn]);
35 +        cc_log("\n");
36 +    }
37 +#endif
38 +#ifdef _WIN32
39 +    exit( spawnv( _P_WAIT, orig_args->argv[0], (const char* const*)orig_args->argv ) );
40 +#else
41         execv(orig_args->argv[0], orig_args->argv);
42         cc_log("execv returned (%s)!\n", strerror(errno));
43         perror(orig_args->argv[0]);
44         exit(1);
45 +#endif
46  }
47  
48 +/* return true if the string contains the name of a ccache executable
49 + */
50 +static int  is_me( const char *s )
51 +{
52 +    const char*   exe = strrchr( s, PATH_CHAR );
53 +    const size_t  len = sizeof(MYNAME)-1;
54 +
55 +    if (exe)
56 +        exe += 1;
57 +    else
58 +        exe = s;
59 +
60 +    return  ( strlen(exe) >= len && memcmp(exe, MYNAME, len) == 0 &&
61 +#ifdef _WIN32
62 +              ((exe[len] == 0) || (strcmp(exe + len, ".exe") == 0)) );
63 +#else
64 +              (exe[len] == 0) );
65 +#endif
66 +}
67  
68  /* return a string to be used to distinguish temporary files 
69     this also tries to cope with NFS by adding the local hostname 
70 @@ -201,7 +233,7 @@
71  
72                 fd = open(tmp_stderr, O_RDONLY | O_BINARY);
73                 if (fd != -1) {
74 -                       if (strcmp(output_file, "/dev/null") == 0 ||
75 +                       if (strcmp(output_file, DEV_NULL) == 0 ||
76                             rename(tmp_hashname, output_file) == 0 || errno == ENOENT) {
77                                 if (cpp_stderr) {
78                                         /* we might have some stderr from cpp */
79 @@ -214,8 +246,7 @@
80                                         }
81                                 }
82  
83 -                               /* we can use a quick method of
84 -                                   getting the failed output */
85 +                               /* we can use a quick method of getting the failed output */
86                                 copy_fd(fd, 2);
87                                 close(fd);
88                                 unlink(tmp_stderr);
89 @@ -231,6 +262,28 @@
90                 failed();
91         }
92  
93 +#ifdef _WIN32
94 +    if (stat(tmp_hashname, &st1) != 0 || rename(tmp_hashname, hashname) != 0) {
95 +        cc_log("failed to rename output: %s\n"
96 +               "'%s'\n"
97 +               "-> '%s'\n",
98 +               strerror(errno), tmp_hashname, hashname);
99 +        stats_update(STATS_ERROR);
100 +        failed();
101 +    }
102 +    cc_log( "Moved '%s' to '%s'\n", tmp_hashname, hashname );
103 +
104 +    x_asprintf(&path_stderr, "%s.stderr", hashname);
105 +    if (stat(tmp_stderr, &st2) != 0 || rename(tmp_stderr, path_stderr) != 0) {
106 +        cc_log("failed to rename output: %s\n"
107 +               "'%s'\n"
108 +               "-> '%s'\n",
109 +               strerror(errno), tmp_stderr, path_stderr);
110 +        stats_update(STATS_ERROR);
111 +        failed();
112 +    }
113 +    cc_log( "Moved '%s' to '%s'\n", tmp_stderr, path_stderr );
114 +#else
115         x_asprintf(&path_stderr, "%s.stderr", hashname);
116  
117         if (stat(tmp_stderr, &st1) != 0 ||
118 @@ -241,6 +294,7 @@
119                 stats_update(STATS_ERROR);
120                 failed();
121         }
122 +#endif
123  
124         cc_log("Placed %s into cache\n", output_file);
125         stats_tocache(file_size(&st1) + file_size(&st2));
126 @@ -360,10 +414,10 @@
127         }
128  
129         /* now the run */
130 -       x_asprintf(&path_stdout, "%s/%s.tmp.%s.%s", temp_dir,
131 +       x_asprintf(&path_stdout, "%s" PATH_SEP "%s.tmp.%s.%s", temp_dir,
132                    input_base, tmp_string(), 
133                    i_extension);
134 -       x_asprintf(&path_stderr, "%s/tmp.cpp_stderr.%s", temp_dir, tmp_string());
135 +       x_asprintf(&path_stderr, "%s" PATH_SEP "tmp.cpp_stderr.%s", temp_dir, tmp_string());
136  
137         if (!direct_i_file) {
138                 /* run cpp on the input file to obtain the .i */
139 @@ -435,15 +489,15 @@
140            on filesystems which are slow for large directories
141         */
142         s = hash_result();
143 -       x_asprintf(&hash_dir, "%s/%c", cache_dir, s[0]);
144 -       x_asprintf(&stats_file, "%s/stats", hash_dir);
145 +       x_asprintf(&hash_dir, "%s" PATH_SEP "%c", cache_dir, s[0]);
146 +       x_asprintf(&stats_file, "%s" PATH_SEP "stats", hash_dir);
147         for (i=1; i<nlevels; i++) {
148                 char *p;
149                 if (create_dir(hash_dir) != 0) {
150                         cc_log("failed to create %s\n", hash_dir);
151                         failed();
152                 }
153 -               x_asprintf(&p, "%s/%c", hash_dir, s[i]);
154 +               x_asprintf(&p, "%s" PATH_SEP "%c", hash_dir, s[i]);
155                 free(hash_dir);
156                 hash_dir = p;
157         }
158 @@ -451,7 +505,7 @@
159                 cc_log("failed to create %s\n", hash_dir);
160                 failed();
161         }
162 -       x_asprintf(&hashname, "%s/%s", hash_dir, s+nlevels);
163 +       x_asprintf(&hashname, "%s" PATH_SEP "%s", hash_dir, s+nlevels);
164         free(hash_dir);
165  }
166  
167 @@ -493,15 +547,19 @@
168  
169         utime(stderr_file, NULL);
170  
171 -       if (strcmp(output_file, "/dev/null") == 0) {
172 +       if (strcmp(output_file, DEV_NULL) == 0) {
173                 ret = 0;
174         } else {
175                 unlink(output_file);
176 +#ifdef _WIN32
177 +        ret = copy_file(hashname, output_file);
178 +#else
179                 if (getenv("CCACHE_HARDLINK")) {
180                         ret = link(hashname, output_file);
181                 } else {
182                         ret = copy_file(hashname, output_file);
183                 }
184 +#endif
185         }
186  
187         /* the hash file might have been deleted by some external process */
188 @@ -572,10 +630,10 @@
189         base = str_basename(argv[0]);
190  
191         /* we might be being invoked like "ccache gcc -c foo.c" */
192 -       if (strcmp(base, MYNAME) == 0) {
193 +       if (is_me(base)) {
194                 args_remove_first(orig_args);
195                 free(base);
196 -               if (strchr(argv[1],'/')) {
197 +               if (strchr(argv[1],PATH_CHAR)) {
198                         /* a full path was given */
199                         return;
200                 }
201 @@ -818,7 +876,7 @@
202         if (!output_file) {
203                 char *p;
204                 output_file = x_strdup(input_file);
205 -               if ((p = strrchr(output_file, '/'))) {
206 +               if ((p = strrchr(output_file, PATH_CHAR))) {
207                         output_file = p+1;
208                 }
209                 p = strrchr(output_file, '.');
210 @@ -847,7 +905,7 @@
211         }
212  
213         /* cope with -o /dev/null */
214 -       if (strcmp(output_file,"/dev/null") != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {
215 +       if (strcmp(output_file,DEV_NULL) != 0 && stat(output_file, &st) == 0 && !S_ISREG(st.st_mode)) {
216                 cc_log("Not a regular file %s\n", output_file);
217                 stats_update(STATS_DEVICE);
218                 failed();
219 @@ -1015,7 +1073,7 @@
220  
221         cache_dir = getenv("CCACHE_DIR");
222         if (!cache_dir) {
223 -               x_asprintf(&cache_dir, "%s/.ccache", get_home_directory());
224 +               x_asprintf(&cache_dir, "%s" PATH_SEP ".ccache", get_home_directory());
225         }
226  
227         temp_dir = getenv("CCACHE_TEMPDIR");
228 @@ -1039,10 +1097,8 @@
229                 }
230         }
231  
232 -
233         /* check if we are being invoked as "ccache" */
234 -       if (strlen(argv[0]) >= strlen(MYNAME) &&
235 -           strcmp(argv[0] + strlen(argv[0]) - strlen(MYNAME), MYNAME) == 0) {
236 +       if (is_me(argv[0])) {
237                 if (argc < 2) {
238                         usage();
239                         exit(1);
240 diff -uwrN ccache-2.4-org/ccache.h ccache-2.4/ccache.h
241 --- ccache-2.4-org/ccache.h     2007-09-05 13:35:09.000000000 +0200
242 +++ ccache-2.4/ccache.h 2007-09-05 13:35:18.000000000 +0200
243 @@ -2,15 +2,33 @@
244  
245  #include "config.h"
246  
247 +#define  UNIX_PATH_CHAR  '/'
248 +#define  UNIX_PATH_SEP   "/"
249 +#define  WIN32_PATH_CHAR  '\\'
250 +#define  WIN32_PATH_SEP   "\\"
251 +
252  #include <stdio.h>
253  #include <unistd.h>
254  #include <stdlib.h>
255  #include <errno.h>
256  #include <sys/stat.h>
257  #include <sys/types.h>
258 +
259 +#ifdef _WIN32
260 +#  include <windows.h>
261 +#  include <sys/locking.h>
262 +#  include <process.h>  /* for _spawn */
263 +#  define  PATH_CHAR  WIN32_PATH_CHAR
264 +#  define  PATH_SEP   WIN32_PATH_SEP
265 +#  define  DEV_NULL   "NUL"
266 +#else
267  #include <sys/wait.h>
268  #include <sys/mman.h>
269  #include <sys/file.h>
270 +#  define  PATH_CHAR  UNIX_PATH_CHAR
271 +#  define  PATH_SEP   UNIX_PATH_SEP
272 +#  define  DEV_NULL   "/dev/null"
273 +#endif
274  #include <fcntl.h>
275  #include <time.h>
276  #include <string.h>
277 @@ -83,6 +101,7 @@
278  int create_dir(const char *dir);
279  void x_asprintf(char **ptr, const char *format, ...);
280  char *x_strdup(const char *s);
281 +char *x_quotedup(const char *s);
282  void *x_realloc(void *ptr, size_t size);
283  void *x_malloc(size_t size);
284  void traverse(const char *dir, void (*fn)(const char *, struct stat *));
285 diff -uwrN ccache-2.4-org/cleanup.c ccache-2.4/cleanup.c
286 --- ccache-2.4-org/cleanup.c    2007-09-05 13:35:09.000000000 +0200
287 +++ ccache-2.4/cleanup.c        2007-09-05 13:35:18.000000000 +0200
288 @@ -143,8 +143,8 @@
289         int i;
290         
291         for (i=0;i<=0xF;i++) {
292 -               x_asprintf(&dname, "%s/%1x", dir, i);
293 -               x_asprintf(&sfile, "%s/%1x/stats", dir, i);
294 +               x_asprintf(&dname, "%s" PATH_SEP "%1x", dir, i);
295 +               x_asprintf(&sfile, "%s" PATH_SEP "%1x" PATH_SEP "stats", dir, i);
296  
297                 memset(counters, 0, sizeof(counters));
298                 stats_read(sfile, counters);
299 @@ -183,7 +183,7 @@
300         int i;
301         
302         for (i=0;i<=0xF;i++) {
303 -               x_asprintf(&dname, "%s/%1x", dir, i);
304 +               x_asprintf(&dname, "%s" PATH_SEP "%1x", dir, i);
305                 traverse(dir, wipe_fn);
306                 free(dname);
307         }
308 diff -uwrN ccache-2.4-org/execute.c ccache-2.4/execute.c
309 --- ccache-2.4-org/execute.c    2007-09-05 13:35:09.000000000 +0200
310 +++ ccache-2.4/execute.c        2007-09-05 13:37:56.000000000 +0200
311 @@ -18,6 +18,11 @@
312  
313  #include "ccache.h"
314  
315 +#ifdef __CYGWIN__
316 +#  define  S_ISLNK(x)  0
317 +#elif !defined S_ISLNK
318 +#  define  S_ISLNK(x)  (((x) & S_IFLNK) != 0)
319 +#endif
320  
321  /*
322    execute a compiler backend, capturing all output to the given paths
323 @@ -27,6 +32,7 @@
324             const char *path_stdout,
325             const char *path_stderr)
326  {
327 +#ifndef _WIN32
328         pid_t pid;
329         int status;
330  
331 @@ -64,8 +70,89 @@
332         }
333  
334         return WEXITSTATUS(status);
335 +#else /* WIN32 */
336 +    int  status = -2;
337 +    int  fd, std_out_old = -1, std_err_old = -1;
338 +
339 +    unlink( path_stdout );
340 +    std_out_old = _dup(1);
341 +    fd = _open( path_stdout, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
342 +    if (fd == -1) {
343 +        status = STATUS_NOCACHE;
344 +        cc_log( "stdout error: failed to open %s\n", path_stdout);
345 +        goto Exit;
346  }
347 +    _dup2(fd, 1);
348 +    _close(fd);
349 +
350 +    std_err_old = _dup(2);
351 +    fd = _open( path_stderr, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL|O_BINARY, 0666);
352 +    if (fd == -1) {
353 +        status = STATUS_NOCACHE;
354 +        cc_log( "stderr error: failed to open %s\n", path_stderr);
355 +        goto Exit;
356 +    }
357 +
358 +    _dup2( fd, 2 );
359 +    _close( fd );
360  
361 +    status = _spawnv( _P_WAIT, argv[0], argv);
362 +
363 +Exit:
364 +    cc_log( "%s:\n stdout -> %s\n stderr -> %s\n process status = %i\n",
365 +            argv[0], path_stdout, path_stderr, status );
366 +    if (status == -1)
367 +        cc_log( "Error %i: %s\n", errno, strerror(errno) );
368 +
369 +    if (std_out_old != -1) _dup2( std_out_old, 1 );
370 +    if (std_err_old != -1) _dup2( std_err_old, 2 );
371 +    _flushall();
372 +
373 +    return (status > 0);
374 +#endif
375 +}
376 +
377 +/*
378 +  check that a file is executable
379 +*/
380 +int  is_exec_file(const char*  fname, const char* exclude_name)
381 +{
382 +#ifndef _WIN32
383 +    struct stat  st1;
384 +#endif
385 +    struct stat  st2;
386 +
387 +    if (access(fname, X_OK) == 0 &&
388 +#ifndef _WIN32  /* no symlinks on Win32 */
389 +        lstat(fname, &st1) == 0 &&
390 +#endif
391 +        stat(fname, &st2) == 0 && S_ISREG(st2.st_mode))
392 +    {
393 +#ifdef _WIN32
394 +        exclude_name=exclude_name;  /* make compiler happy */
395 +        return 1;
396 +#else
397 +        /* if it is a symlink, ensure it doesn't point at something called
398 +         * 'exclude_name', which corresponds to the ccache binary itself */
399 +         if (S_ISLNK(st1.st_mode)) {
400 +             char*  buf = x_realpath(fname);
401 +             if (buf) {
402 +                 char*  p = str_basename(buf);
403 +                 if (strcmp(p, exclude_name) == 0) {
404 +                     /* a link to ccache itself !! */
405 +                     free(p);
406 +                     free(buf);
407 +                     return -1;
408 +                 }
409 +                 free(p);
410 +                 free(buf);
411 +             }
412 +         }
413 +         return 1;
414 +#endif
415 +    }
416 +    return 0;
417 +}
418  
419  /*
420    find an executable by name in $PATH. Exclude any that are links to exclude_name 
421 @@ -74,9 +161,9 @@
422  {
423         char *path;
424         char *tok;
425 -       struct stat st1, st2;
426 +       const char*  sep = ":";
427  
428 -       if (*name == '/') {
429 +       if (*name == PATH_CHAR) {
430                 return x_strdup(name);
431         }
432  
433 @@ -91,38 +178,28 @@
434  
435         path = x_strdup(path);
436         
437 +    if (strchr(path, ';')) sep = ";";
438 +
439         /* search the path looking for the first compiler of the right name
440            that isn't us */
441 -       for (tok=strtok(path,":"); tok; tok = strtok(NULL, ":")) {
442 +       for (tok=strtok(path,sep); tok; tok = strtok(NULL,sep)) {
443                 char *fname;
444 -               x_asprintf(&fname, "%s/%s", tok, name);
445 +               x_asprintf(&fname, "%s" PATH_SEP "%s", tok, name);
446                 /* look for a normal executable file */
447 -               if (access(fname, X_OK) == 0 &&
448 -                   lstat(fname, &st1) == 0 &&
449 -                   stat(fname, &st2) == 0 &&
450 -                   S_ISREG(st2.st_mode)) {
451 -                       /* if its a symlink then ensure it doesn't
452 -                           point at something called exclude_name */
453 -                       if (S_ISLNK(st1.st_mode)) {
454 -                               char *buf = x_realpath(fname);
455 -                               if (buf) {
456 -                                       char *p = str_basename(buf);
457 -                                       if (strcmp(p, exclude_name) == 0) {
458 -                                               /* its a link to "ccache" ! */
459 -                                               free(p);
460 -                                               free(buf);
461 -                                               continue;
462 -                                       }
463 -                                       free(buf);
464 -                                       free(p);
465 -                               }
466 +               if ( is_exec_file(fname, exclude_name ) > 0) {
467 +            free(path);
468 +            return fname;
469                         }
470 +               free( fname );
471  
472 -                       /* found it! */
473 +#ifdef _WIN32  /* append .exe */
474 +        x_asprintf(&fname, "%s" PATH_SEP "%s.exe", tok, name);
475 +        if ( is_exec_file(fname, exclude_name ) > 0) {
476                         free(path);
477                         return fname;
478                 }
479                 free(fname);
480 +#endif
481         }
482  
483         return NULL;
484 diff -uwrN ccache-2.4-org/stats.c ccache-2.4/stats.c
485 --- ccache-2.4-org/stats.c      2007-09-05 13:35:09.000000000 +0200
486 +++ ccache-2.4/stats.c  2007-09-05 13:35:18.000000000 +0200
487 @@ -126,7 +126,7 @@
488  
489         if (!stats_file) {
490                 if (!cache_dir) return;
491 -               x_asprintf(&stats_file, "%s/stats", cache_dir);
492 +               x_asprintf(&stats_file, "%s" PATH_SEP "stats", cache_dir);
493         }
494  
495         /* open safely to try to prevent symlink races */
496 @@ -215,9 +215,9 @@
497                 char *fname;
498  
499                 if (dir == -1) {
500 -                       x_asprintf(&fname, "%s/stats", cache_dir);
501 +                       x_asprintf(&fname, "%s" PATH_SEP "stats", cache_dir);
502                 } else {
503 -                       x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
504 +                       x_asprintf(&fname, "%s" PATH_SEP "%1x" PATH_SEP "stats", cache_dir, dir);
505                 }
506  
507                 stats_read(fname, counters);
508 @@ -259,12 +259,12 @@
509         char *fname;
510         unsigned counters[STATS_END];
511  
512 -       x_asprintf(&fname, "%s/stats", cache_dir);
513 +       x_asprintf(&fname, "%s" PATH_SEP "stats", cache_dir);
514         unlink(fname);
515         free(fname);
516  
517         for (dir=0;dir<=0xF;dir++) {
518 -               x_asprintf(&fname, "%s/%1x/stats", cache_dir, dir);
519 +               x_asprintf(&fname, "%s" PATH_SEP "%1x" PATH_SEP "stats", cache_dir, dir);
520                 fd = safe_open(fname);
521                 if (fd == -1) {
522                         free(fname);
523 @@ -305,9 +305,9 @@
524                 char *fname, *cdir;
525                 int fd;
526  
527 -               x_asprintf(&cdir, "%s/%1x", cache_dir, dir);
528 +               x_asprintf(&cdir, "%s" PATH_SEP "%1x", cache_dir, dir);
529                 create_dir(cdir);
530 -               x_asprintf(&fname, "%s/stats", cdir);
531 +               x_asprintf(&fname, "%s" PATH_SEP "stats", cdir);
532                 free(cdir);
533  
534                 memset(counters, 0, sizeof(counters));
535 @@ -336,7 +336,7 @@
536         char *stats_file;
537  
538         create_dir(dir);
539 -       x_asprintf(&stats_file, "%s/stats", dir);
540 +       x_asprintf(&stats_file, "%s" PATH_SEP "stats", dir);
541  
542         memset(counters, 0, sizeof(counters));
543  
544 diff -uwrN ccache-2.4-org/unify.c ccache-2.4/unify.c
545 --- ccache-2.4-org/unify.c      2007-09-05 13:35:09.000000000 +0200
546 +++ ccache-2.4/unify.c  2007-09-05 13:35:18.000000000 +0200
547 @@ -249,6 +249,32 @@
548                 return -1;
549         }
550  
551 +#ifdef _WIN32
552 +    {
553 +        HANDLE  view = CreateFileMapping((HANDLE) _get_osfhandle(fd), NULL,
554 +                                         PAGE_READONLY|SEC_COMMIT, 0, 0, NULL);
555 +        if (view == NULL) {
556 +            cc_log( "Failed to create file mapping %s: %s\n",
557 +                    fname, strerror(errno) );
558 +                    stats_update(STATS_PREPROCESSOR);
559 +                    return -1;
560 +        }
561 +        map = MapViewOfFile(view, FILE_MAP_READ, 0, 0, st.st_size);
562 +        if (map == NULL) {
563 +            CloseHandle(view);
564 +            cc_log( "Failed to map view of file %s: %s\n",
565 +                    fname, strerror(errno) );
566 +            stats_update(STATS_PREPROCESSOR);
567 +            return -1;
568 +        }
569 +
570 +        unify((unsigned char*)map, st.st_size);
571 +
572 +        UnmapViewOfFile(map);
573 +        CloseHandle(view);
574 +        close(fd);
575 +    }
576 +#else
577         /* we use mmap() to make it easy to handle arbitrarily long
578             lines in preprocessor output. I have seen lines of over
579             100k in length, so this is well worth it */
580 @@ -263,7 +289,7 @@
581         unify((unsigned char *)map, st.st_size);
582  
583         munmap(map, st.st_size);
584 -
585 +#endif
586         return 0;
587  }
588  
589 diff -uwrN ccache-2.4-org/util.c ccache-2.4/util.c
590 --- ccache-2.4-org/util.c       2007-09-05 13:35:09.000000000 +0200
591 +++ ccache-2.4/util.c   2007-09-05 13:35:18.000000000 +0200
592 @@ -20,6 +20,29 @@
593  
594  static FILE *logfile;
595  
596 +#ifdef WIN32
597 +int  fchmod(int  fildes, mode_t  mode)
598 +{
599 +    # warning "fchmod not implemented"
600 +    fildes=fildes;
601 +    mode=mode;
602 +    return 0;
603 +}
604 +
605 +#   define  mkdir(a,b)     _mkdir(a)
606 +#   define  lstat(a,b)     stat(a,b)
607 +#   define  x_realpath(a)  strdup(a)
608 +#endif
609 +
610 +#ifndef HAVE_MKSTEMP
611 +/* cheap and nasty mkstemp replacement */
612 +int mkstemp(char *template)
613 +{
614 +       mktemp(template);
615 +       return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
616 +}
617 +#endif
618 +
619  /* log a message to the CCACHE_LOGFILE location */
620  void cc_log(const char *format, ...)
621  {
622 @@ -68,6 +91,7 @@
623         char *tmp_name;
624         mode_t mask;
625  
626 +    cc_log( "copying '%s' to '%s'\n", src, dest);
627         x_asprintf(&tmp_name, "%s.XXXXXX", dest);
628  
629         fd1 = open(src, O_RDONLY|O_BINARY);
630 @@ -168,6 +192,30 @@
631  }
632  
633  /*
634 +  this is like x_strdup() but add quotes around the arguments if it contains
635 +  spaces
636 +*/
637 +char*  x_quotedup(const char* s)
638 +{
639 +    if ( strchr(s, ' ') != NULL) {
640 +        size_t  len = strlen(s);
641 +        char*   arg = malloc( len+3 );
642 +
643 +        if (arg == NULL) {
644 +            fatal("out of memory in x_quotedup\n" );
645 +        }
646 +        arg[0] = '"';
647 +        memcpy( arg+1, s, len );
648 +        arg[1+len] = '"';
649 +        arg[2+len] = 0;
650 +
651 +        return arg;
652 +    }
653 +    else
654 +        return x_strdup(s);
655 +}
656 +
657 +/*
658    this is like malloc() but dies if the malloc fails
659  */
660  void *x_malloc(size_t size)
661 @@ -244,7 +292,16 @@
662  /* return the base name of a file - caller frees */
663  char *str_basename(const char *s)
664  {
665 -       char *p = strrchr(s, '/');
666 +       char *p  = strrchr(s,  PATH_CHAR );
667 +#ifdef WIN32
668 +    /* accept both / and \ as path delimiters here */
669 +       char *p2 = strrchr(s, '/');
670 +
671 +       if (p == NULL)
672 +        p = p2;
673 +    else if (p2 != NULL && p2 > p)
674 +        p = p2;
675 +#endif
676         if (p) {
677                 return x_strdup(p+1);
678         } 
679 @@ -257,7 +314,7 @@
680  {
681         char *p;
682         s = x_strdup(s);
683 -       p = strrchr(s, '/');
684 +       p = strrchr(s, PATH_CHAR);
685         if (p) {
686                 *p = 0;
687         } 
688 @@ -266,6 +323,9 @@
689  
690  int lock_fd(int fd)
691  {
692 +#ifdef _WIN32
693 +    return _locking(fd, _LK_NBLCK, 1);
694 +#else
695         struct flock fl;
696         int ret;
697  
698 @@ -281,17 +341,22 @@
699                 ret = fcntl(fd, F_SETLKW, &fl);
700         } while (ret == -1 && errno == EINTR);
701         return ret;
702 +#endif
703  }
704  
705  /* return size on disk of a file */
706  size_t file_size(struct stat *st)
707  {
708 +#ifdef _WIN32
709 +    return st->st_size;
710 +#else
711         size_t size = st->st_blocks * 512;
712         if ((size_t)st->st_size > size) {
713                 /* probably a broken stat() call ... */
714                 size = (st->st_size + 1023) & ~1023;
715         }
716         return size;
717 +#endif
718  }
719  
720  
721 @@ -346,7 +411,7 @@
722         return (size_t)v;
723  }
724  
725 -
726 +#ifndef _WIN32
727  /*
728    a sane realpath() function, trying to cope with stupid path limits and 
729    a broken API
730 @@ -389,6 +454,7 @@
731         free(ret);
732         return NULL;
733  }
734 +#endif
735  
736  /* a getcwd that will returns an allocated buffer */
737  char *gnu_getcwd(void)
738 @@ -408,15 +474,6 @@
739         }
740  }
741  
742 -#ifndef HAVE_MKSTEMP
743 -/* cheap and nasty mkstemp replacement */
744 -int mkstemp(char *template)
745 -{
746 -       mktemp(template);
747 -       return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600);
748 -}
749 -#endif
750 -
751  
752  /* create an empty file */
753  int create_empty_file(const char *fname)
754 @@ -434,8 +491,26 @@
755  /*
756    return current users home directory or die
757  */
758 +#ifdef _WIN32
759 +#  define   _WIN32_IE  0x500
760 +#  include <shlobj.h>
761 +#endif
762 +
763  const char *get_home_directory(void)
764  {
765 +#ifdef _WIN32
766 +    static TCHAR  localHome[ MAX_PATH ];
767 +
768 +    /* on Win32, always use a local application directory instead. this    */
769 +    /* avoids many problems: terrible performance with roaming profiles,   */
770 +    /* un-necessary backups of cached object files, and more...            */
771 +    /* (why not use %TEMP% after all ?)                                    */
772 +    if (SHGetSpecialFolderPath( NULL, localHome, CSIDL_LOCAL_APPDATA, FALSE))
773 +        return localHome;
774 +
775 +    fatal("Unable to determine home directory");
776 +    return NULL;
777 +#else
778         const char *p = getenv("HOME");
779         if (p) {
780                 return p;
781 @@ -450,5 +525,6 @@
782  #endif
783         fatal("Unable to determine home directory");
784         return NULL;
785 +#endif
786  }
787