diff --git a/CCache/ccache.c b/CCache/ccache.c index 3d5f13633..ee6616776 100644 --- a/CCache/ccache.c +++ b/CCache/ccache.c @@ -136,7 +136,7 @@ static void failed(void) putenv("CCACHE_OUTFILES"); } - execv(orig_args->argv[0], orig_args->argv); + execv(orig_args->argv[0], (const char *const *)orig_args->argv); cc_log("execv returned (%s)!\n", strerror(errno)); perror(orig_args->argv[0]); exit(1); @@ -722,7 +722,11 @@ static void find_compiler(int argc, char **argv) if (strcmp(base, MYNAME) == 0) { args_remove_first(orig_args); free(base); - if (strchr(argv[1],'/')) { + if (strchr(argv[1],'/') +#ifdef _WIN32 + || strchr(argv[1],'\\') +#endif + ) { /* a full path was given */ return; } diff --git a/CCache/ccache.h b/CCache/ccache.h index 8b988d37a..d34588586 100644 --- a/CCache/ccache.h +++ b/CCache/ccache.h @@ -2,7 +2,11 @@ #define CCACHE_VERSION SWIG_VERSION +#ifndef _WIN32 #include "config.h" +#else +#define PACKAGE_NAME "ccache-swig.exe" +#endif #include #include @@ -10,8 +14,16 @@ #include #include #include -#include -#include + +#ifndef _WIN32 + #include + #include +#else +#define _WIN32_WINNT 0x0500 + #include + #include +#endif + #include #include #include diff --git a/CCache/execute.c b/CCache/execute.c index 1694f6681..be6beef69 100644 --- a/CCache/execute.c +++ b/CCache/execute.c @@ -18,6 +18,33 @@ #include "ccache.h" +#ifdef _WIN32 +static char *argvtos(char **argv) +{ + int i, len; + char *ptr, *str; + + for (i = 0, len = 0; argv[i]; i++) { + len += strlen(argv[i]) + 3; + } + + str = ptr = (char *)malloc(len + 1); + if (str == NULL) + return NULL; + + for (i = 0; argv[i]; i++) { + len = strlen(argv[i]); + *ptr++ = '"'; + memcpy(ptr, argv[i], len); + ptr += len; + *ptr++ = '"'; + *ptr++ = ' '; + } + *ptr = 0; + + return str; +} +#endif /* execute a compiler backend, capturing all output to the given paths @@ -27,6 +54,60 @@ int execute(char **argv, const char *path_stdout, const char *path_stderr) { +#ifdef _WIN32 + PROCESS_INFORMATION pinfo; + STARTUPINFO sinfo; + BOOL ret; + DWORD exitcode; + char *args; + HANDLE fd_out, fd_err; + SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; + + /* TODO: needs moving after possible exit() below, but before stdout is redirected */ + if (ccache_verbose) { + display_execute_args(argv); + } + + fd_out = CreateFile(path_stdout, GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (fd_out == INVALID_HANDLE_VALUE) { + return STATUS_NOCACHE; + } + + fd_err = CreateFile(path_stderr, GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, + FILE_ATTRIBUTE_NORMAL, NULL); + if (fd_err == INVALID_HANDLE_VALUE) { + return STATUS_NOCACHE; + } + + ZeroMemory(&pinfo, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&sinfo, sizeof(STARTUPINFO)); + + sinfo.cb = sizeof(STARTUPINFO); + sinfo.hStdError = fd_err; + sinfo.hStdOutput = fd_out; + sinfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + sinfo.dwFlags |= STARTF_USESTDHANDLES; + + args = argvtos(argv); + + ret = CreateProcessA(argv[0], args, NULL, NULL, TRUE, 0, NULL, NULL, + &sinfo, &pinfo); + + free(args); + CloseHandle(fd_out); + CloseHandle(fd_err); + + if (ret == 0) + return -1; + + WaitForSingleObject(pinfo.hProcess, INFINITE); + GetExitCodeProcess(pinfo.hProcess, &exitcode); + CloseHandle(pinfo.hProcess); + CloseHandle(pinfo.hThread); + + return exitcode; +#else pid_t pid; int status; @@ -69,6 +150,7 @@ int execute(char **argv, } return WEXITSTATUS(status); +#endif } @@ -77,6 +159,19 @@ int execute(char **argv, */ char *find_executable(const char *name, const char *exclude_name) { +#if _WIN32 + (void)exclude_name; + DWORD ret; + char namebuf[MAX_PATH]; + + ret = SearchPathA(getenv("CCACHE_PATH"), name, ".exe", + sizeof(namebuf), namebuf, NULL); + if (ret != 0) { + return x_strdup(namebuf); + } + + return NULL; +#else char *path; char *tok; struct stat st1, st2; @@ -131,6 +226,7 @@ char *find_executable(const char *name, const char *exclude_name) } return NULL; +#endif } void display_execute_args(char **argv) diff --git a/CCache/unify.c b/CCache/unify.c index e436ed7fd..758756ddd 100644 --- a/CCache/unify.c +++ b/CCache/unify.c @@ -238,6 +238,39 @@ static void unify(unsigned char *p, size_t size) */ int unify_hash(const char *fname) { +#ifdef _WIN32 + HANDLE file; + HANDLE section; + MEMORY_BASIC_INFORMATION minfo; + char *map; + + file = CreateFileA(fname, GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, 0, NULL); + if (file == INVALID_HANDLE_VALUE) + return -1; + + section = CreateFileMappingA(file, NULL, PAGE_READONLY, 0, 0, NULL); + CloseHandle(file); + if (section == NULL) + return -1; + + map = MapViewOfFile(section, FILE_MAP_READ, 0, 0, 0); + CloseHandle(section); + if (map == NULL) + return -1; + + if (VirtualQuery(map, &minfo, sizeof(minfo)) != sizeof(minfo)) { + UnmapViewOfFile(map); + return -1; + } + + /* pass it through the unifier */ + unify((unsigned char *)map, minfo.RegionSize); + + UnmapViewOfFile(map); + + return 0; +#else int fd; struct stat st; char *map; @@ -265,5 +298,6 @@ int unify_hash(const char *fname) munmap(map, st.st_size); return 0; +#endif } diff --git a/CCache/util.c b/CCache/util.c index 8e39b9c21..cdb654d5d 100644 --- a/CCache/util.c +++ b/CCache/util.c @@ -46,19 +46,24 @@ void fatal(const char *msg) int safe_rename(const char* oldpath, const char* newpath) { - /* safe_rename is for creating entries in the cache. + /* safe_rename is for creating entries in the cache. - Works like rename(), but it never overwrites an existing - cache entry. This avoids corruption on NFS. */ - int status = link( oldpath, newpath ); - if( status == 0 || errno == EEXIST ) - { - return unlink( oldpath ); - } - else - { - return -1; - } + Works like rename(), but it never overwrites an existing + cache entry. This avoids corruption on NFS. */ +#ifndef _WIN32 + int status = link(oldpath, newpath); + if( status == 0 || errno == EEXIST ) +#else + int status = CreateHardLinkA(newpath, oldpath, NULL) ? 0 : -1; + if( status == 0 || GetLastError() == ERROR_ALREADY_EXISTS ) +#endif + { + return unlink( oldpath ); + } + else + { + return -1; + } } #ifndef ENABLE_ZLIB @@ -75,6 +80,15 @@ void copy_fd(int fd_in, int fd_out) } } +#ifndef HAVE_MKSTEMP +/* cheap and nasty mkstemp replacement */ +static int mkstemp(char *template) +{ + mktemp(template); + return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); +} +#endif + /* move a file using rename */ int move_file(const char *src, const char *dest) { return safe_rename(src, dest); @@ -119,9 +133,13 @@ static int copy_file(const char *src, const char *dest) close(fd1); /* get perms right on the tmp file */ +#ifndef _WIN32 mask = umask(0); fchmod(fd2, 0666 & ~mask); umask(mask); +#else + (void)mask; +#endif /* the close can fail on NFS if out of space */ if (close(fd2) == -1) { @@ -333,7 +351,11 @@ int commit_to_cache(const char *src, const char *dest, int hardlink) int ret = -1; unlink(dest); if (hardlink) { +#ifdef _WIN32 + ret = CreateHardLinkA(dest, src, NULL) ? 0 : -1; +#else ret = link(src, dest); +#endif } if (ret == -1) { ret = copy_file_to_cache(src, dest); @@ -358,7 +380,11 @@ int retrieve_from_cache(const char *src, const char *dest, int hardlink) unlink(dest); /* only make a hardlink if the cache file is uncompressed */ if (hardlink && test_if_compressed(src) == 0) { +#ifdef _WIN32 + ret = CreateHardLinkA(dest, src, NULL) ? 0 : -1; +#else ret = link(src, dest); +#endif } else { ret = copy_file_from_cache(src, dest); } @@ -393,9 +419,15 @@ int create_dir(const char *dir) errno = ENOTDIR; return 1; } +#ifdef _WIN32 + if (mkdir(dir) != 0 && errno != EEXIST) { + return 1; + } +#else if (mkdir(dir, 0777) != 0 && errno != EEXIST) { return 1; } +#endif return 0; } @@ -526,7 +558,12 @@ void traverse(const char *dir, void (*fn)(const char *, struct stat *)) if (strlen(de->d_name) == 0) continue; x_asprintf(&fname, "%s/%s", dir, de->d_name); - if (lstat(fname, &st)) { +#ifdef _WIN32 + if (stat(fname, &st)) +#else + if (lstat(fname, &st)) +#endif + { if (errno != ENOENT) { perror(fname); } @@ -551,8 +588,16 @@ char *str_basename(const char *s) { char *p = strrchr(s, '/'); if (p) { - return x_strdup(p+1); - } + s = (p+1); + } + +#ifdef _WIN32 + p = strrchr(s, '\\'); + + if (p) { + s = (p+1); + } +#endif return x_strdup(s); } @@ -563,6 +608,9 @@ char *dirname(char *s) char *p; s = x_strdup(s); p = strrchr(s, '/'); +#ifdef _WIN32 + p = strrchr(s, '\\'); +#endif if (p) { *p = 0; } @@ -571,6 +619,7 @@ char *dirname(char *s) int lock_fd(int fd) { +#ifndef _WIN32 struct flock fl; int ret; @@ -586,17 +635,26 @@ int lock_fd(int fd) ret = fcntl(fd, F_SETLKW, &fl); } while (ret == -1 && errno == EINTR); return ret; +#else + (void)fd; +#warning "missing implementation???" + return 0; +#endif } /* return size on disk of a file */ size_t file_size(struct stat *st) { +#ifdef _WIN32 + return (st->st_size + 1023) & ~1023; +#else size_t size = st->st_blocks * 512; if ((size_t)st->st_size > size) { /* probably a broken stat() call ... */ size = (st->st_size + 1023) & ~1023; } return size; +#endif } @@ -658,6 +716,17 @@ size_t value_units(const char *s) */ char *x_realpath(const char *path) { +#ifdef _WIN32 + char namebuf[MAX_PATH]; + DWORD ret; + + ret = GetFullPathNameA(path, sizeof(namebuf), namebuf, NULL); + if (ret == 0 || ret >= sizeof(namebuf)) { + return NULL; + } + + return x_strdup(namebuf); +#else int maxlen; char *ret, *p; #ifdef PATH_MAX @@ -693,6 +762,7 @@ char *x_realpath(const char *path) } free(ret); return NULL; +#endif } /* a getcwd that will returns an allocated buffer */ @@ -713,16 +783,6 @@ char *gnu_getcwd(void) } } -#ifndef HAVE_MKSTEMP -/* cheap and nasty mkstemp replacement */ -int mkstemp(char *template) -{ - mktemp(template); - return open(template, O_RDWR | O_CREAT | O_EXCL | O_BINARY, 0600); -} -#endif - - /* create an empty file */ int create_empty_file(const char *fname) { @@ -741,6 +801,24 @@ int create_empty_file(const char *fname) */ const char *get_home_directory(void) { +#ifdef _WIN32 + static char home_path[MAX_PATH] = {0}; + HRESULT ret; + + /* we already have the path */ + if (home_path[0] != 0) { + return home_path; + } + + /* get the path to "Application Data" folder */ + ret = SHGetFolderPathA(NULL, CSIDL_APPDATA | CSIDL_FLAG_CREATE, NULL, 0, home_path); + if (SUCCEEDED(ret)) { + return home_path; + } + + fprintf(stderr, "ccache: Unable to determine home directory\n"); + return NULL; +#else const char *p = getenv("HOME"); if (p) { return p; @@ -753,8 +831,9 @@ const char *get_home_directory(void) } } #endif - cc_log("Unable to determine home directory"); + fatal("Unable to determine home directory"); return NULL; +#endif } int x_utimes(const char *filename)