diff options
author | John Keeping <john@keeping.me.uk> | 2013-04-06 13:28:57 +0400 |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2013-04-08 18:12:52 +0400 |
commit | fb3655df3bf85bd405c5921bbd4b3a54c705c839 (patch) | |
tree | 419a962a0b82f5ba3023791549044ff462229250 /ui-snapshot.c | |
parent | 42d5476f258e7909682f1b611da00d64507d45c6 (diff) |
use struct strbuf instead of static buffers
Use "struct strbuf" from Git to remove the limit on file path length.
Notes on scan-tree:
This is slightly involved since I decided to pass the strbuf into
add_repo() and modify if whenever a new file name is required, which
should avoid any extra allocations within that function. The pattern
there is to append the filename, use it and then reset the buffer to its
original length (retaining a trailing '/').
Notes on ui-snapshot:
Since write_archive modifies the argv array passed to it we
copy the argv_array values into a new array of char* and then free the
original argv_array structure and the new array without worrying about
what the values now look like.
Signed-off-by: John Keeping <john@keeping.me.uk>
Diffstat (limited to 'ui-snapshot.c')
-rw-r--r-- | ui-snapshot.c | 60 |
1 files changed, 43 insertions, 17 deletions
diff --git a/ui-snapshot.c b/ui-snapshot.c index a47884e..8e76977 100644 --- a/ui-snapshot.c +++ b/ui-snapshot.c @@ -15,14 +15,33 @@ static int write_archive_type(const char *format, const char *hex, const char *prefix) { struct argv_array argv = ARGV_ARRAY_INIT; + const char **nargv; + int result; argv_array_push(&argv, "snapshot"); argv_array_push(&argv, format); if (prefix) { + struct strbuf buf = STRBUF_INIT; + strbuf_addstr(&buf, prefix); + strbuf_addch(&buf, '/'); argv_array_push(&argv, "--prefix"); - argv_array_push(&argv, fmt("%s/", prefix)); + argv_array_push(&argv, buf.buf); + strbuf_release(&buf); } argv_array_push(&argv, hex); - return write_archive(argv.argc, argv.argv, NULL, 1, NULL, 0); + /* + * Now we need to copy the pointers to arguments into a new + * structure because write_archive will rearrange its arguments + * which may result in duplicated/missing entries causing leaks + * or double-frees in argv_array_clear. + */ + nargv = xmalloc(sizeof(char *) * (argv.argc + 1)); + /* argv_array guarantees a trailing NULL entry. */ + memcpy(nargv, argv.argv, sizeof(char *) * (argv.argc + 1)); + + result = write_archive(argv.argc, nargv, NULL, 1, NULL, 0); + argv_array_clear(&argv); + free(nargv); + return result; } static int write_tar_archive(const char *hex, const char *prefix) @@ -129,29 +148,36 @@ static const char *get_ref_from_filename(const char *url, const char *filename, { const char *reponame; unsigned char sha1[20]; - char *snapshot; + struct strbuf snapshot = STRBUF_INIT; + int result = 1; - snapshot = xstrdup(filename); - snapshot[strlen(snapshot) - strlen(format->suffix)] = '\0'; + strbuf_addstr(&snapshot, filename); + strbuf_setlen(&snapshot, snapshot.len - strlen(format->suffix)); - if (get_sha1(snapshot, sha1) == 0) - return snapshot; + if (get_sha1(snapshot.buf, sha1) == 0) + goto out; reponame = cgit_repobasename(url); - if (prefixcmp(snapshot, reponame) == 0) { - snapshot += strlen(reponame); - while (snapshot && (*snapshot == '-' || *snapshot == '_')) - snapshot++; + if (prefixcmp(snapshot.buf, reponame) == 0) { + const char *new_start = snapshot.buf; + new_start += strlen(reponame); + while (new_start && (*new_start == '-' || *new_start == '_')) + new_start++; + strbuf_splice(&snapshot, 0, new_start - snapshot.buf, "", 0); } - if (get_sha1(snapshot, sha1) == 0) - return snapshot; + if (get_sha1(snapshot.buf, sha1) == 0) + goto out; - snapshot = fmt("v%s", snapshot); - if (get_sha1(snapshot, sha1) == 0) - return snapshot; + strbuf_insert(&snapshot, 0, "v", 1); + if (get_sha1(snapshot.buf, sha1) == 0) + goto out; - return NULL; + result = 0; + strbuf_release(&snapshot); + +out: + return result ? strbuf_detach(&snapshot, NULL) : NULL; } __attribute__((format (printf, 1, 2))) |