* sq_quote_buf is made public, and works on a strbuf. * sq_quote_argv also works on a strbuf. * make sq_quote_argv take a "maxlen" argument to check the buffer won't grow too big. Signed-off-by: Pierre Habouzit <madcoder@xxxxxxxxxx> --- connect.c | 21 ++++++-------- git.c | 16 +++------- quote.c | 94 +++++++++++++++--------------------------------------------- quote.h | 9 ++---- trace.c | 25 +++++++--------- 5 files changed, 52 insertions(+), 113 deletions(-) diff --git a/connect.c b/connect.c index 1653a0e..06d279e 100644 --- a/connect.c +++ b/connect.c @@ -577,16 +577,13 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) if (pid < 0) die("unable to fork"); if (!pid) { - char command[MAX_CMD_LEN]; - char *posn = command; - int size = MAX_CMD_LEN; - int of = 0; + struct strbuf cmd; - of |= add_to_string(&posn, &size, prog, 0); - of |= add_to_string(&posn, &size, " ", 0); - of |= add_to_string(&posn, &size, path, 1); - - if (of) + strbuf_init(&cmd, MAX_CMD_LEN); + strbuf_addstr(&cmd, prog); + strbuf_addch(&cmd, ' '); + sq_quote_buf(&cmd, path); + if (cmd.len >= MAX_CMD_LEN) die("command line too long"); dup2(pipefd[1][0], 0); @@ -606,10 +603,10 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) ssh_basename++; if (!port) - execlp(ssh, ssh_basename, host, command, NULL); + execlp(ssh, ssh_basename, host, cmd.buf, NULL); else execlp(ssh, ssh_basename, "-p", port, host, - command, NULL); + cmd.buf, NULL); } else { unsetenv(ALTERNATE_DB_ENVIRONMENT); @@ -618,7 +615,7 @@ pid_t git_connect(int fd[2], char *url, const char *prog, int flags) unsetenv(GIT_WORK_TREE_ENVIRONMENT); unsetenv(GRAFT_ENVIRONMENT); unsetenv(INDEX_ENVIRONMENT); - execlp("sh", "sh", "-c", command, NULL); + execlp("sh", "sh", "-c", cmd.buf, NULL); } die("exec failed"); } diff --git a/git.c b/git.c index 6773c12..d7c6bca 100644 --- a/git.c +++ b/git.c @@ -187,19 +187,13 @@ static int handle_alias(int *argcp, const char ***argv) if (alias_string) { if (alias_string[0] == '!') { if (*argcp > 1) { - int i, sz = PATH_MAX; - char *s = xmalloc(sz), *new_alias = s; + struct strbuf buf; - add_to_string(&s, &sz, alias_string, 0); + strbuf_init(&buf, PATH_MAX); + strbuf_addstr(&buf, alias_string); + sq_quote_argv(&buf, (*argv) + 1, *argcp - 1, PATH_MAX); free(alias_string); - alias_string = new_alias; - for (i = 1; i < *argcp && - !add_to_string(&s, &sz, " ", 0) && - !add_to_string(&s, &sz, (*argv)[i], 1) - ; i++) - ; /* do nothing */ - if (!sz) - die("Too many or long arguments"); + alias_string = buf.buf; } trace_printf("trace: alias to shell cmd: %s => %s\n", alias_command, alias_string + 1); diff --git a/quote.c b/quote.c index d88bf75..edd1a09 100644 --- a/quote.c +++ b/quote.c @@ -12,37 +12,31 @@ * a'b ==> a'\''b ==> 'a'\''b' * a!b ==> a'\!'b ==> 'a'\!'b' */ -#undef EMIT -#define EMIT(x) do { if (++len < n) *bp++ = (x); } while(0) - static inline int need_bs_quote(char c) { return (c == '\'' || c == '!'); } -static size_t sq_quote_buf(char *dst, size_t n, const char *src) +void sq_quote_buf(struct strbuf *dst, const char *src) { - char c; - char *bp = dst; - size_t len = 0; - - EMIT('\''); - while ((c = *src++)) { - if (need_bs_quote(c)) { - EMIT('\''); - EMIT('\\'); - EMIT(c); - EMIT('\''); - } else { - EMIT(c); + char *to_free = NULL; + + if (dst->buf == src) + to_free = strbuf_detach(dst); + + strbuf_addch(dst, '\''); + while (*src) { + size_t len = strcspn(src, "'\\"); + strbuf_add(dst, src, len); + src += len; + while (need_bs_quote(*src)) { + strbuf_addstr(dst, "'\\"); + strbuf_addch(dst, *src++); + strbuf_addch(dst, '\''); } } - EMIT('\''); - - if ( n ) - *bp = 0; - - return len; + strbuf_addch(dst, '\''); + free(to_free); } void sq_quote_print(FILE *stream, const char *src) @@ -62,11 +56,10 @@ void sq_quote_print(FILE *stream, const char *src) fputc('\'', stream); } -char *sq_quote_argv(const char** argv, int count) +void sq_quote_argv(struct strbuf *dst, const char** argv, int count, + size_t maxlen) { - char *buf, *to; int i; - size_t len = 0; /* Count argv if needed. */ if (count < 0) { @@ -74,53 +67,14 @@ char *sq_quote_argv(const char** argv, int count) ; /* just counting */ } - /* Special case: no argv. */ - if (!count) - return xcalloc(1,1); - - /* Get destination buffer length. */ - for (i = 0; i < count; i++) - len += sq_quote_buf(NULL, 0, argv[i]) + 1; - - /* Alloc destination buffer. */ - to = buf = xmalloc(len + 1); - /* Copy into destination buffer. */ + strbuf_grow(dst, 32 * count); for (i = 0; i < count; ++i) { - *to++ = ' '; - to += sq_quote_buf(to, len, argv[i]); + strbuf_addch(dst, ' '); + sq_quote_buf(dst, argv[i]); + if (maxlen && dst->len > maxlen) + die("Too many or long arguments"); } - - return buf; -} - -/* - * Append a string to a string buffer, with or without shell quoting. - * Return true if the buffer overflowed. - */ -int add_to_string(char **ptrp, int *sizep, const char *str, int quote) -{ - char *p = *ptrp; - int size = *sizep; - int oc; - int err = 0; - - if (quote) - oc = sq_quote_buf(p, size, str); - else { - oc = strlen(str); - memcpy(p, str, (size <= oc) ? size - 1 : oc); - } - - if (size <= oc) { - err = 1; - oc = size - 1; - } - - *ptrp += oc; - **ptrp = '\0'; - *sizep -= oc; - return err; } char *sq_dequote(char *arg) diff --git a/quote.h b/quote.h index 8a59cc5..78e8d3e 100644 --- a/quote.h +++ b/quote.h @@ -29,13 +29,10 @@ */ extern void sq_quote_print(FILE *stream, const char *src); -extern char *sq_quote_argv(const char** argv, int count); -/* - * Append a string to a string buffer, with or without shell quoting. - * Return true if the buffer overflowed. - */ -extern int add_to_string(char **ptrp, int *sizep, const char *str, int quote); +extern void sq_quote_buf(struct strbuf *, const char *src); +extern void sq_quote_argv(struct strbuf *, const char **argv, int count, + size_t maxlen); /* This unwraps what sq_quote() produces in place, but returns * NULL if the input does not look like what sq_quote would have diff --git a/trace.c b/trace.c index 91548a5..efc656b 100644 --- a/trace.c +++ b/trace.c @@ -85,32 +85,29 @@ void trace_printf(const char *fmt, ...) void trace_argv_printf(const char **argv, int count, const char *fmt, ...) { - char buf[8192]; va_list ap; - char *argv_str; - size_t argv_len; + struct strbuf trace; int fd, len, need_close = 0; fd = get_trace_fd(&need_close); if (!fd) return; + strbuf_init(&trace, 0); + strbuf_grow(&trace, 8192); + va_start(ap, fmt); - len = vsnprintf(buf, sizeof(buf), fmt, ap); + len = vsnprintf(trace.buf, strbuf_avail(&trace) + 1, fmt, ap); va_end(ap); - if (len >= sizeof(buf)) + if (len >= strbuf_avail(&trace)) die("unreasonnable trace length"); + strbuf_setlen(&trace, len); - /* Get the argv string. */ - argv_str = sq_quote_argv(argv, count); - argv_len = strlen(argv_str); - - write_or_whine_pipe(fd, buf, len, err_msg); - write_or_whine_pipe(fd, argv_str, argv_len, err_msg); - write_or_whine_pipe(fd, "\n", 1, err_msg); - - free(argv_str); + sq_quote_argv(&trace, argv, count, 0); + strbuf_addch(&trace, '\n'); + write_or_whine_pipe(fd, trace.buf, trace.len, err_msg); + strbuf_release(&trace); if (need_close) close(fd); } -- 1.5.3.2.1036.gca8d2
Attachment:
pgphMMKeZELpz.pgp
Description: PGP signature