sequencer: fix quoting in write_author_script
[gitweb.git] / sequencer.c
index c4e44185593a809244ce96c12d84fc3f89478daf..ba11fe5bcabdc3767a53450bb9426f7928420075 100644 (file)
@@ -636,7 +636,7 @@ static int write_author_script(const char *message)
                else if (*message != '\'')
                        strbuf_addch(&buf, *(message++));
                else
-                       strbuf_addf(&buf, "'\\\\%c'", *(message++));
+                       strbuf_addf(&buf, "'\\%c'", *(message++));
        strbuf_addstr(&buf, "'\nGIT_AUTHOR_EMAIL='");
        while (*message && *message != '\n' && *message != '\r')
                if (skip_prefix(message, "> ", &message))
@@ -644,19 +644,37 @@ static int write_author_script(const char *message)
                else if (*message != '\'')
                        strbuf_addch(&buf, *(message++));
                else
-                       strbuf_addf(&buf, "'\\\\%c'", *(message++));
+                       strbuf_addf(&buf, "'\\%c'", *(message++));
        strbuf_addstr(&buf, "'\nGIT_AUTHOR_DATE='@");
        while (*message && *message != '\n' && *message != '\r')
                if (*message != '\'')
                        strbuf_addch(&buf, *(message++));
                else
-                       strbuf_addf(&buf, "'\\\\%c'", *(message++));
+                       strbuf_addf(&buf, "'\\%c'", *(message++));
        strbuf_addch(&buf, '\'');
        res = write_message(buf.buf, buf.len, rebase_path_author_script(), 1);
        strbuf_release(&buf);
        return res;
 }
 
+
+/*
+ * write_author_script() used to fail to terminate the last line with a "'" and
+ * also escaped "'" incorrectly as "'\\\\''" rather than "'\\''". We check for
+ * the terminating "'" on the last line to see how "'" has been escaped in case
+ * git was upgraded while rebase was stopped.
+ */
+static int quoting_is_broken(const char *s, size_t n)
+{
+       /* Skip any empty lines in case the file was hand edited */
+       while (n > 0 && s[--n] == '\n')
+               ; /* empty */
+       if (n > 0 && s[n] != '\'')
+               return 1;
+
+       return 0;
+}
+
 /*
  * Read a list of environment variable assignments (such as the author-script
  * file) into an environment block. Returns -1 on error, 0 otherwise.
@@ -664,14 +682,18 @@ static int write_author_script(const char *message)
 static int read_env_script(struct argv_array *env)
 {
        struct strbuf script = STRBUF_INIT;
-       int i, count = 0;
-       char *p, *p2;
+       int i, count = 0, sq_bug;
+       const char *p2;
+       char *p;
 
        if (strbuf_read_file(&script, rebase_path_author_script(), 256) <= 0)
                return -1;
-
+       /* write_author_script() used to quote incorrectly */
+       sq_bug = quoting_is_broken(script.buf, script.len);
        for (p = script.buf; *p; p++)
-               if (skip_prefix(p, "'\\\\''", (const char **)&p2))
+               if (sq_bug && skip_prefix(p, "'\\\\''", &p2))
+                       strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
+               else if (skip_prefix(p, "'\\''", &p2))
                        strbuf_splice(&script, p - script.buf, p2 - p, "'", 1);
                else if (*p == '\'')
                        strbuf_splice(&script, p-- - script.buf, 1, "", 0);