]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Handle @file syntax on Windows correctly (#392)
authorMike Blumenkrantz <michael.blumenkrantz@gmail.com>
Thu, 25 Apr 2019 18:24:01 +0000 (14:24 -0400)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 25 Apr 2019 18:24:01 +0000 (20:24 +0200)
* add length return to win32argvtos()

this is useful for determining the length of the generated argument string

* correctly handle @file syntax on Windows

the @file syntax means that the process reads command arguments from the
specified file. this is commonly used in order to shorten commands which
would otherwise be longer than the maximum length limit: many build systems
do this in all cases to avoid hitting this limit.

when a command exceeds 8192 characters on on Windows, ccache now writes
the parsed/modified arguments to a tmpfile and then runs the command using
that tmpfile with @tmpfile in order to preserve this mechanism and avoid hitting
the length limit

fixes #95

src/ccache.h
src/execute.c
src/hashutil.c

index 39e4b0ca9e6046a943433b2579f76e2517088ef8..66a98457b264d54c345b309bffda263045dff6bf 100644 (file)
@@ -289,7 +289,7 @@ typedef int (*COMPAR_FN_T)(const void *, const void *);
 #endif
 
 #ifdef _WIN32
-char *win32argvtos(char *prefix, char **argv);
+char *win32argvtos(char *prefix, char **argv, int *length);
 char *win32getshell(char *path);
 int win32execute(char *path, char **argv, int doreturn,
                  int fd_stdout, int fd_stderr);
index ca72d2762d16777a0e4c5c85847f36ed63f91df1..87aabed6e6373e2c532a875fad4a0a34264b9865 100644 (file)
@@ -26,10 +26,11 @@ find_executable_in_path(const char *name, const char *exclude_name, char *path);
 // Re-create a win32 command line string based on **argv.
 // http://msdn.microsoft.com/en-us/library/17w5ykft.aspx
 char *
-win32argvtos(char *prefix, char **argv)
+win32argvtos(char *prefix, char **argv, int *length)
 {
        int i = 0;
        int k = 0;
+        *length = 0;
        char *arg = prefix ? prefix : argv[i++];
        do {
                int bs = 0;
@@ -54,6 +55,7 @@ win32argvtos(char *prefix, char **argv)
        if (!str) {
                return NULL;
        }
+        *length = k;
 
        i = 0;
        arg = prefix ? prefix : argv[i++];
@@ -162,13 +164,29 @@ win32execute(char *path, char **argv, int doreturn,
                }
        }
 
-       char *args = win32argvtos(sh, argv);
+       int length;
+       char *args = win32argvtos(sh, argv, &length);
        const char *ext = strrchr(path, '.');
        char full_path_win_ext[MAX_PATH] = {0};
        add_exe_ext_if_no_to_fullpath(full_path_win_ext, MAX_PATH, ext, path);
-       BOOL ret =
-               CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
-                             &si, &pi);
+       BOOL ret = FALSE;
+        if (length > 8192) {
+                char *tmp_file = format("%s.tmp", path);
+                FILE *fp = create_tmp_file(&tmp_file, "w");
+                char atfile[MAX_PATH + 3];
+                fwrite(args, 1, length - 1, fp);
+                fclose(fp);
+                if (ferror(fp)) {
+                        cc_log("Error writing @file; this command will probably fail:\n%s", args);
+                }
+                snprintf(atfile, sizeof(atfile), "\"@%s\"", tmp_file);
+                ret = CreateProcess(NULL, atfile, NULL, NULL, 1, 0, NULL, NULL,
+                                    &si, &pi);
+        }
+        if (!ret) {
+                ret = CreateProcess(full_path_win_ext, args, NULL, NULL, 1, 0, NULL, NULL,
+                                    &si, &pi);
+        }
        if (fd_stdout != -1) {
                close(fd_stdout);
                close(fd_stderr);
index 289ba1717e23372fea291cf105612854e5af116c..edf446c4cbef8964029b651daf9f83657c6f1f0e 100644 (file)
@@ -212,7 +212,8 @@ hash_command_output(struct hash *hash, const char *command,
 
        char *win32args;
        if (!cmd) {
-               win32args = win32argvtos(sh, args->argv);
+               int length;
+               win32args = win32argvtos(sh, args->argv, &length);
        } else {
                win32args = (char *)command;  // quoted
        }