diff options
author | John Keeping <john@keeping.me.uk> | 2013-04-06 18:28:57 (JST) |
---|---|---|
committer | Jason A. Donenfeld <Jason@zx2c4.com> | 2013-04-08 23:12:52 (JST) |
commit | fb3655df3bf85bd405c5921bbd4b3a54c705c839 (patch) | |
tree | 419a962a0b82f5ba3023791549044ff462229250 | |
parent | 42d5476f258e7909682f1b611da00d64507d45c6 (diff) | |
download | cgit-fb3655df3bf85bd405c5921bbd4b3a54c705c839.zip cgit-fb3655df3bf85bd405c5921bbd4b3a54c705c839.tar.gz |
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>
-rw-r--r-- | cache.c | 57 | ||||
-rw-r--r-- | cgit.c | 72 | ||||
-rw-r--r-- | scan-tree.c | 160 | ||||
-rw-r--r-- | ui-log.c | 33 | ||||
-rw-r--r-- | ui-plain.c | 6 | ||||
-rw-r--r-- | ui-refs.c | 10 | ||||
-rw-r--r-- | ui-repolist.c | 28 | ||||
-rw-r--r-- | ui-shared.c | 63 | ||||
-rw-r--r-- | ui-snapshot.c | 60 | ||||
-rw-r--r-- | ui-summary.c | 12 | ||||
-rw-r--r-- | ui-tag.c | 14 | ||||
-rw-r--r-- | ui-tree.c | 33 |
12 files changed, 305 insertions, 243 deletions
@@ -312,9 +312,9 @@ int cache_process(int size, const char *path, const char *key, int ttl, | |||
312 | cache_fill_fn fn, void *cbdata) | 312 | cache_fill_fn fn, void *cbdata) |
313 | { | 313 | { |
314 | unsigned long hash; | 314 | unsigned long hash; |
315 | int len, i; | 315 | int i; |
316 | char filename[1024]; | 316 | struct strbuf filename = STRBUF_INIT; |
317 | char lockname[1024 + 5]; /* 5 = ".lock" */ | 317 | struct strbuf lockname = STRBUF_INIT; |
318 | struct cache_slot slot; | 318 | struct cache_slot slot; |
319 | 319 | ||
320 | /* If the cache is disabled, just generate the content */ | 320 | /* If the cache is disabled, just generate the content */ |
@@ -329,32 +329,22 @@ int cache_process(int size, const char *path, const char *key, int ttl, | |||
329 | fn(cbdata); | 329 | fn(cbdata); |
330 | return 0; | 330 | return 0; |
331 | } | 331 | } |
332 | len = strlen(path); | ||
333 | if (len > sizeof(filename) - 10) { /* 10 = "/01234567\0" */ | ||
334 | cache_log("[cgit] Cache path too long, caching is disabled: %s\n", | ||
335 | path); | ||
336 | fn(cbdata); | ||
337 | return 0; | ||
338 | } | ||
339 | if (!key) | 332 | if (!key) |
340 | key = ""; | 333 | key = ""; |
341 | hash = hash_str(key) % size; | 334 | hash = hash_str(key) % size; |
342 | strcpy(filename, path); | 335 | strbuf_addstr(&filename, path); |
343 | if (filename[len - 1] != '/') | 336 | strbuf_ensure_end(&filename, '/'); |
344 | filename[len++] = '/'; | ||
345 | for (i = 0; i < 8; i++) { | 337 | for (i = 0; i < 8; i++) { |
346 | sprintf(filename + len++, "%x", | 338 | strbuf_addf(&filename, "%x", (unsigned char)(hash & 0xf)); |
347 | (unsigned char)(hash & 0xf)); | ||
348 | hash >>= 4; | 339 | hash >>= 4; |
349 | } | 340 | } |
350 | filename[len] = '\0'; | 341 | strbuf_addbuf(&lockname, &filename); |
351 | strcpy(lockname, filename); | 342 | strbuf_addstr(&lockname, ".lock"); |
352 | strcpy(lockname + len, ".lock"); | ||
353 | slot.fn = fn; | 343 | slot.fn = fn; |
354 | slot.cbdata = cbdata; | 344 | slot.cbdata = cbdata; |
355 | slot.ttl = ttl; | 345 | slot.ttl = ttl; |
356 | slot.cache_name = filename; | 346 | slot.cache_name = strbuf_detach(&filename, NULL); |
357 | slot.lock_name = lockname; | 347 | slot.lock_name = strbuf_detach(&lockname, NULL); |
358 | slot.key = key; | 348 | slot.key = key; |
359 | slot.keylen = strlen(key); | 349 | slot.keylen = strlen(key); |
360 | return process_slot(&slot); | 350 | return process_slot(&slot); |
@@ -381,18 +371,13 @@ int cache_ls(const char *path) | |||
381 | struct dirent *ent; | 371 | struct dirent *ent; |
382 | int err = 0; | 372 | int err = 0; |
383 | struct cache_slot slot; | 373 | struct cache_slot slot; |
384 | char fullname[1024]; | 374 | struct strbuf fullname = STRBUF_INIT; |
385 | char *name; | 375 | size_t prefixlen; |
386 | 376 | ||
387 | if (!path) { | 377 | if (!path) { |
388 | cache_log("[cgit] cache path not specified\n"); | 378 | cache_log("[cgit] cache path not specified\n"); |
389 | return -1; | 379 | return -1; |
390 | } | 380 | } |
391 | if (strlen(path) > 1024 - 10) { | ||
392 | cache_log("[cgit] cache path too long: %s\n", | ||
393 | path); | ||
394 | return -1; | ||
395 | } | ||
396 | dir = opendir(path); | 381 | dir = opendir(path); |
397 | if (!dir) { | 382 | if (!dir) { |
398 | err = errno; | 383 | err = errno; |
@@ -400,30 +385,28 @@ int cache_ls(const char *path) | |||
400 | path, strerror(err), err); | 385 | path, strerror(err), err); |
401 | return err; | 386 | return err; |
402 | } | 387 | } |
403 | strcpy(fullname, path); | 388 | strbuf_addstr(&fullname, path); |
404 | name = fullname + strlen(path); | 389 | strbuf_ensure_end(&fullname, '/'); |
405 | if (*(name - 1) != '/') { | 390 | prefixlen = fullname.len; |
406 | *name++ = '/'; | ||
407 | *name = '\0'; | ||
408 | } | ||
409 | slot.cache_name = fullname; | ||
410 | while ((ent = readdir(dir)) != NULL) { | 391 | while ((ent = readdir(dir)) != NULL) { |
411 | if (strlen(ent->d_name) != 8) | 392 | if (strlen(ent->d_name) != 8) |
412 | continue; | 393 | continue; |
413 | strcpy(name, ent->d_name); | 394 | strbuf_setlen(&fullname, prefixlen); |
395 | strbuf_addstr(&fullname, ent->d_name); | ||
414 | if ((err = open_slot(&slot)) != 0) { | 396 | if ((err = open_slot(&slot)) != 0) { |
415 | cache_log("[cgit] unable to open path %s: %s (%d)\n", | 397 | cache_log("[cgit] unable to open path %s: %s (%d)\n", |
416 | fullname, strerror(err), err); | 398 | fullname.buf, strerror(err), err); |
417 | continue; | 399 | continue; |
418 | } | 400 | } |
419 | printf("%s %s %10"PRIuMAX" %s\n", | 401 | printf("%s %s %10"PRIuMAX" %s\n", |
420 | name, | 402 | fullname.buf, |
421 | sprintftime("%Y-%m-%d %H:%M:%S", | 403 | sprintftime("%Y-%m-%d %H:%M:%S", |
422 | slot.cache_st.st_mtime), | 404 | slot.cache_st.st_mtime), |
423 | (uintmax_t)slot.cache_st.st_size, | 405 | (uintmax_t)slot.cache_st.st_size, |
424 | slot.buf); | 406 | slot.buf); |
425 | close_slot(&slot); | 407 | close_slot(&slot); |
426 | } | 408 | } |
409 | slot.cache_name = strbuf_detach(&fullname, NULL); | ||
427 | closedir(dir); | 410 | closedir(dir); |
428 | return 0; | 411 | return 0; |
429 | } | 412 | } |
@@ -468,8 +468,8 @@ static int prepare_repo_cmd(struct cgit_context *ctx) | |||
468 | if (nongit) { | 468 | if (nongit) { |
469 | const char *name = ctx->repo->name; | 469 | const char *name = ctx->repo->name; |
470 | rc = errno; | 470 | rc = errno; |
471 | ctx->page.title = fmt("%s - %s", ctx->cfg.root_title, | 471 | ctx->page.title = fmtalloc("%s - %s", ctx->cfg.root_title, |
472 | "config error"); | 472 | "config error"); |
473 | ctx->repo = NULL; | 473 | ctx->repo = NULL; |
474 | cgit_print_http_headers(ctx); | 474 | cgit_print_http_headers(ctx); |
475 | cgit_print_docstart(ctx); | 475 | cgit_print_docstart(ctx); |
@@ -479,7 +479,7 @@ static int prepare_repo_cmd(struct cgit_context *ctx) | |||
479 | cgit_print_docend(); | 479 | cgit_print_docend(); |
480 | return 1; | 480 | return 1; |
481 | } | 481 | } |
482 | ctx->page.title = fmt("%s - %s", ctx->repo->name, ctx->repo->desc); | 482 | ctx->page.title = fmtalloc("%s - %s", ctx->repo->name, ctx->repo->desc); |
483 | 483 | ||
484 | if (!ctx->repo->defbranch) | 484 | if (!ctx->repo->defbranch) |
485 | ctx->repo->defbranch = guess_defbranch(); | 485 | ctx->repo->defbranch = guess_defbranch(); |
@@ -577,21 +577,16 @@ static int cmp_repos(const void *a, const void *b) | |||
577 | static char *build_snapshot_setting(int bitmap) | 577 | static char *build_snapshot_setting(int bitmap) |
578 | { | 578 | { |
579 | const struct cgit_snapshot_format *f; | 579 | const struct cgit_snapshot_format *f; |
580 | char *result = xstrdup(""); | 580 | struct strbuf result = STRBUF_INIT; |
581 | char *tmp; | ||
582 | int len; | ||
583 | 581 | ||
584 | for (f = cgit_snapshot_formats; f->suffix; f++) { | 582 | for (f = cgit_snapshot_formats; f->suffix; f++) { |
585 | if (f->bit & bitmap) { | 583 | if (f->bit & bitmap) { |
586 | tmp = result; | 584 | if (result.len) |
587 | result = xstrdup(fmt("%s%s ", tmp, f->suffix)); | 585 | strbuf_addch(&result, ' '); |
588 | free(tmp); | 586 | strbuf_addstr(&result, f->suffix); |
589 | } | 587 | } |
590 | } | 588 | } |
591 | len = strlen(result); | 589 | return strbuf_detach(&result, NULL); |
592 | if (len) | ||
593 | result[len - 1] = '\0'; | ||
594 | return result; | ||
595 | } | 590 | } |
596 | 591 | ||
597 | static char *get_first_line(char *txt) | 592 | static char *get_first_line(char *txt) |
@@ -639,7 +634,7 @@ static void print_repo(FILE *f, struct cgit_repo *repo) | |||
639 | fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); | 634 | fprintf(f, "repo.source-filter=%s\n", repo->source_filter->cmd); |
640 | if (repo->snapshots != ctx.cfg.snapshots) { | 635 | if (repo->snapshots != ctx.cfg.snapshots) { |
641 | char *tmp = build_snapshot_setting(repo->snapshots); | 636 | char *tmp = build_snapshot_setting(repo->snapshots); |
642 | fprintf(f, "repo.snapshots=%s\n", tmp); | 637 | fprintf(f, "repo.snapshots=%s\n", tmp ? tmp : ""); |
643 | free(tmp); | 638 | free(tmp); |
644 | } | 639 | } |
645 | if (repo->max_stats != ctx.cfg.max_stats) | 640 | if (repo->max_stats != ctx.cfg.max_stats) |
@@ -661,20 +656,22 @@ static void print_repolist(FILE *f, struct cgit_repolist *list, int start) | |||
661 | */ | 656 | */ |
662 | static int generate_cached_repolist(const char *path, const char *cached_rc) | 657 | static int generate_cached_repolist(const char *path, const char *cached_rc) |
663 | { | 658 | { |
664 | char *locked_rc; | 659 | struct strbuf locked_rc = STRBUF_INIT; |
660 | int result = 0; | ||
665 | int idx; | 661 | int idx; |
666 | FILE *f; | 662 | FILE *f; |
667 | 663 | ||
668 | locked_rc = xstrdup(fmt("%s.lock", cached_rc)); | 664 | strbuf_addf(&locked_rc, "%s.lock", cached_rc); |
669 | f = fopen(locked_rc, "wx"); | 665 | f = fopen(locked_rc.buf, "wx"); |
670 | if (!f) { | 666 | if (!f) { |
671 | /* Inform about the error unless the lockfile already existed, | 667 | /* Inform about the error unless the lockfile already existed, |
672 | * since that only means we've got concurrent requests. | 668 | * since that only means we've got concurrent requests. |
673 | */ | 669 | */ |
674 | if (errno != EEXIST) | 670 | result = errno; |
671 | if (result != EEXIST) | ||
675 | fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", | 672 | fprintf(stderr, "[cgit] Error opening %s: %s (%d)\n", |
676 | locked_rc, strerror(errno), errno); | 673 | locked_rc.buf, strerror(result), result); |
677 | return errno; | 674 | goto out; |
678 | } | 675 | } |
679 | idx = cgit_repolist.count; | 676 | idx = cgit_repolist.count; |
680 | if (ctx.cfg.project_list) | 677 | if (ctx.cfg.project_list) |
@@ -682,55 +679,59 @@ static int generate_cached_repolist(const char *path, const char *cached_rc) | |||
682 | else | 679 | else |
683 | scan_tree(path, repo_config); | 680 | scan_tree(path, repo_config); |
684 | print_repolist(f, &cgit_repolist, idx); | 681 | print_repolist(f, &cgit_repolist, idx); |
685 | if (rename(locked_rc, cached_rc)) | 682 | if (rename(locked_rc.buf, cached_rc)) |
686 | fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", | 683 | fprintf(stderr, "[cgit] Error renaming %s to %s: %s (%d)\n", |
687 | locked_rc, cached_rc, strerror(errno), errno); | 684 | locked_rc.buf, cached_rc, strerror(errno), errno); |
688 | fclose(f); | 685 | fclose(f); |
689 | return 0; | 686 | out: |
687 | strbuf_release(&locked_rc); | ||
688 | return result; | ||
690 | } | 689 | } |
691 | 690 | ||
692 | static void process_cached_repolist(const char *path) | 691 | static void process_cached_repolist(const char *path) |
693 | { | 692 | { |
694 | struct stat st; | 693 | struct stat st; |
695 | char *cached_rc; | 694 | struct strbuf cached_rc = STRBUF_INIT; |
696 | time_t age; | 695 | time_t age; |
697 | unsigned long hash; | 696 | unsigned long hash; |
698 | 697 | ||
699 | hash = hash_str(path); | 698 | hash = hash_str(path); |
700 | if (ctx.cfg.project_list) | 699 | if (ctx.cfg.project_list) |
701 | hash += hash_str(ctx.cfg.project_list); | 700 | hash += hash_str(ctx.cfg.project_list); |
702 | cached_rc = xstrdup(fmt("%s/rc-%8lx", ctx.cfg.cache_root, hash)); | 701 | strbuf_addf(&cached_rc, "%s/rc-%8lx", ctx.cfg.cache_root, hash); |
703 | 702 | ||
704 | if (stat(cached_rc, &st)) { | 703 | if (stat(cached_rc.buf, &st)) { |
705 | /* Nothing is cached, we need to scan without forking. And | 704 | /* Nothing is cached, we need to scan without forking. And |
706 | * if we fail to generate a cached repolist, we need to | 705 | * if we fail to generate a cached repolist, we need to |
707 | * invoke scan_tree manually. | 706 | * invoke scan_tree manually. |
708 | */ | 707 | */ |
709 | if (generate_cached_repolist(path, cached_rc)) { | 708 | if (generate_cached_repolist(path, cached_rc.buf)) { |
710 | if (ctx.cfg.project_list) | 709 | if (ctx.cfg.project_list) |
711 | scan_projects(path, ctx.cfg.project_list, | 710 | scan_projects(path, ctx.cfg.project_list, |
712 | repo_config); | 711 | repo_config); |
713 | else | 712 | else |
714 | scan_tree(path, repo_config); | 713 | scan_tree(path, repo_config); |
715 | } | 714 | } |
716 | return; | 715 | goto out; |
717 | } | 716 | } |
718 | 717 | ||
719 | parse_configfile(cached_rc, config_cb); | 718 | parse_configfile(cached_rc.buf, config_cb); |
720 | 719 | ||
721 | /* If the cached configfile hasn't expired, lets exit now */ | 720 | /* If the cached configfile hasn't expired, lets exit now */ |
722 | age = time(NULL) - st.st_mtime; | 721 | age = time(NULL) - st.st_mtime; |
723 | if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) | 722 | if (age <= (ctx.cfg.cache_scanrc_ttl * 60)) |
724 | return; | 723 | goto out; |
725 | 724 | ||
726 | /* The cached repolist has been parsed, but it was old. So lets | 725 | /* The cached repolist has been parsed, but it was old. So lets |
727 | * rescan the specified path and generate a new cached repolist | 726 | * rescan the specified path and generate a new cached repolist |
728 | * in a child-process to avoid latency for the current request. | 727 | * in a child-process to avoid latency for the current request. |
729 | */ | 728 | */ |
730 | if (fork()) | 729 | if (fork()) |
731 | return; | 730 | goto out; |
732 | 731 | ||
733 | exit(generate_cached_repolist(path, cached_rc)); | 732 | exit(generate_cached_repolist(path, cached_rc.buf)); |
733 | out: | ||
734 | strbuf_release(&cached_rc); | ||
734 | } | 735 | } |
735 | 736 | ||
736 | static void cgit_parse_args(int argc, const char **argv) | 737 | static void cgit_parse_args(int argc, const char **argv) |
@@ -812,7 +813,6 @@ static int calc_ttl() | |||
812 | int main(int argc, const char **argv) | 813 | int main(int argc, const char **argv) |
813 | { | 814 | { |
814 | const char *path; | 815 | const char *path; |
815 | char *qry; | ||
816 | int err, ttl; | 816 | int err, ttl; |
817 | 817 | ||
818 | prepare_context(&ctx); | 818 | prepare_context(&ctx); |
@@ -843,9 +843,9 @@ int main(int argc, const char **argv) | |||
843 | path++; | 843 | path++; |
844 | ctx.qry.url = xstrdup(path); | 844 | ctx.qry.url = xstrdup(path); |
845 | if (ctx.qry.raw) { | 845 | if (ctx.qry.raw) { |
846 | qry = ctx.qry.raw; | 846 | char *newqry = fmtalloc("%s?%s", path, ctx.qry.raw); |
847 | ctx.qry.raw = xstrdup(fmt("%s?%s", path, qry)); | 847 | free(ctx.qry.raw); |
848 | free(qry); | 848 | ctx.qry.raw = newqry; |
849 | } else | 849 | } else |
850 | ctx.qry.raw = xstrdup(ctx.qry.url); | 850 | ctx.qry.raw = xstrdup(ctx.qry.url); |
851 | cgit_parse_url(ctx.qry.url); | 851 | cgit_parse_url(ctx.qry.url); |
diff --git a/scan-tree.c b/scan-tree.c index 05caba5..beb584b 100644 --- a/scan-tree.c +++ b/scan-tree.c | |||
@@ -12,38 +12,38 @@ | |||
12 | #include "configfile.h" | 12 | #include "configfile.h" |
13 | #include "html.h" | 13 | #include "html.h" |
14 | 14 | ||
15 | #define MAX_PATH 4096 | ||
16 | |||
17 | /* return 1 if path contains a objects/ directory and a HEAD file */ | 15 | /* return 1 if path contains a objects/ directory and a HEAD file */ |
18 | static int is_git_dir(const char *path) | 16 | static int is_git_dir(const char *path) |
19 | { | 17 | { |
20 | struct stat st; | 18 | struct stat st; |
21 | static char buf[MAX_PATH]; | 19 | struct strbuf pathbuf = STRBUF_INIT; |
20 | int result = 0; | ||
22 | 21 | ||
23 | if (snprintf(buf, MAX_PATH, "%s/objects", path) >= MAX_PATH) { | 22 | strbuf_addf(&pathbuf, "%s/objects", path); |
24 | fprintf(stderr, "Insanely long path: %s\n", path); | 23 | if (stat(pathbuf.buf, &st)) { |
25 | return 0; | ||
26 | } | ||
27 | if (stat(buf, &st)) { | ||
28 | if (errno != ENOENT) | 24 | if (errno != ENOENT) |
29 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | 25 | fprintf(stderr, "Error checking path %s: %s (%d)\n", |
30 | path, strerror(errno), errno); | 26 | path, strerror(errno), errno); |
31 | return 0; | 27 | goto out; |
32 | } | 28 | } |
33 | if (!S_ISDIR(st.st_mode)) | 29 | if (!S_ISDIR(st.st_mode)) |
34 | return 0; | 30 | goto out; |
35 | 31 | ||
36 | sprintf(buf, "%s/HEAD", path); | 32 | strbuf_reset(&pathbuf); |
37 | if (stat(buf, &st)) { | 33 | strbuf_addf(&pathbuf, "%s/HEAD", path); |
34 | if (stat(pathbuf.buf, &st)) { | ||
38 | if (errno != ENOENT) | 35 | if (errno != ENOENT) |
39 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | 36 | fprintf(stderr, "Error checking path %s: %s (%d)\n", |
40 | path, strerror(errno), errno); | 37 | path, strerror(errno), errno); |
41 | return 0; | 38 | goto out; |
42 | } | 39 | } |
43 | if (!S_ISREG(st.st_mode)) | 40 | if (!S_ISREG(st.st_mode)) |
44 | return 0; | 41 | goto out; |
45 | 42 | ||
46 | return 1; | 43 | result = 1; |
44 | out: | ||
45 | strbuf_release(&pathbuf); | ||
46 | return result; | ||
47 | } | 47 | } |
48 | 48 | ||
49 | struct cgit_repo *repo; | 49 | struct cgit_repo *repo; |
@@ -75,47 +75,61 @@ static char *xstrrchr(char *s, char *from, int c) | |||
75 | return from < s ? NULL : from; | 75 | return from < s ? NULL : from; |
76 | } | 76 | } |
77 | 77 | ||
78 | static void add_repo(const char *base, const char *path, repo_config_fn fn) | 78 | static void add_repo(const char *base, struct strbuf *path, repo_config_fn fn) |
79 | { | 79 | { |
80 | struct stat st; | 80 | struct stat st; |
81 | struct passwd *pwd; | 81 | struct passwd *pwd; |
82 | char *rel, *p, *slash; | 82 | size_t pathlen; |
83 | struct strbuf rel = STRBUF_INIT; | ||
84 | char *p, *slash; | ||
83 | int n; | 85 | int n; |
84 | size_t size; | 86 | size_t size; |
85 | 87 | ||
86 | if (stat(path, &st)) { | 88 | if (stat(path->buf, &st)) { |
87 | fprintf(stderr, "Error accessing %s: %s (%d)\n", | 89 | fprintf(stderr, "Error accessing %s: %s (%d)\n", |
88 | path, strerror(errno), errno); | 90 | path->buf, strerror(errno), errno); |
89 | return; | 91 | return; |
90 | } | 92 | } |
91 | 93 | ||
92 | if (ctx.cfg.strict_export && stat(fmt("%s/%s", path, ctx.cfg.strict_export), &st)) | 94 | strbuf_addch(path, '/'); |
93 | return; | 95 | pathlen = path->len; |
94 | 96 | ||
95 | if (!stat(fmt("%s/noweb", path), &st)) | 97 | if (ctx.cfg.strict_export) { |
98 | strbuf_addstr(path, ctx.cfg.strict_export); | ||
99 | if(stat(path->buf, &st)) | ||
100 | return; | ||
101 | strbuf_setlen(path, pathlen); | ||
102 | } | ||
103 | |||
104 | strbuf_addstr(path, "noweb"); | ||
105 | if (!stat(path->buf, &st)) | ||
96 | return; | 106 | return; |
107 | strbuf_setlen(path, pathlen); | ||
97 | 108 | ||
98 | if (base == path) | 109 | if (strncmp(base, path->buf, strlen(base))) |
99 | rel = xstrdup(path); | 110 | strbuf_addbuf(&rel, path); |
100 | else | 111 | else |
101 | rel = xstrdup(path + strlen(base) + 1); | 112 | strbuf_addstr(&rel, path->buf + strlen(base) + 1); |
102 | 113 | ||
103 | if (!strcmp(rel + strlen(rel) - 5, "/.git")) | 114 | if (!strcmp(rel.buf + rel.len - 5, "/.git")) |
104 | rel[strlen(rel) - 5] = '\0'; | 115 | strbuf_setlen(&rel, rel.len - 5); |
105 | 116 | ||
106 | repo = cgit_add_repo(rel); | 117 | repo = cgit_add_repo(rel.buf); |
107 | config_fn = fn; | 118 | config_fn = fn; |
108 | if (ctx.cfg.enable_git_config) | 119 | if (ctx.cfg.enable_git_config) { |
109 | git_config_from_file(gitconfig_config, fmt("%s/config", path), NULL); | 120 | strbuf_addstr(path, "config"); |
121 | git_config_from_file(gitconfig_config, path->buf, NULL); | ||
122 | strbuf_setlen(path, pathlen); | ||
123 | } | ||
110 | 124 | ||
111 | if (ctx.cfg.remove_suffix) | 125 | if (ctx.cfg.remove_suffix) |
112 | if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git")) | 126 | if ((p = strrchr(repo->url, '.')) && !strcmp(p, ".git")) |
113 | *p = '\0'; | 127 | *p = '\0'; |
114 | repo->path = xstrdup(path); | 128 | repo->path = xstrdup(path->buf); |
115 | while (!repo->owner) { | 129 | while (!repo->owner) { |
116 | if ((pwd = getpwuid(st.st_uid)) == NULL) { | 130 | if ((pwd = getpwuid(st.st_uid)) == NULL) { |
117 | fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", | 131 | fprintf(stderr, "Error reading owner-info for %s: %s (%d)\n", |
118 | path, strerror(errno), errno); | 132 | path->buf, strerror(errno), errno); |
119 | break; | 133 | break; |
120 | } | 134 | } |
121 | if (pwd->pw_gecos) | 135 | if (pwd->pw_gecos) |
@@ -125,30 +139,32 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn) | |||
125 | } | 139 | } |
126 | 140 | ||
127 | if (repo->desc == cgit_default_repo_desc || !repo->desc) { | 141 | if (repo->desc == cgit_default_repo_desc || !repo->desc) { |
128 | p = fmt("%s/description", path); | 142 | strbuf_addstr(path, "description"); |
129 | if (!stat(p, &st)) | 143 | if (!stat(path->buf, &st)) |
130 | readfile(p, &repo->desc, &size); | 144 | readfile(path->buf, &repo->desc, &size); |
145 | strbuf_setlen(path, pathlen); | ||
131 | } | 146 | } |
132 | 147 | ||
133 | if (!repo->readme) { | 148 | if (!repo->readme) { |
134 | p = fmt("%s/README.html", path); | 149 | strbuf_addstr(path, "README.html"); |
135 | if (!stat(p, &st)) | 150 | if (!stat(path->buf, &st)) |
136 | repo->readme = "README.html"; | 151 | repo->readme = "README.html"; |
152 | strbuf_setlen(path, pathlen); | ||
137 | } | 153 | } |
138 | if (ctx.cfg.section_from_path) { | 154 | if (ctx.cfg.section_from_path) { |
139 | n = ctx.cfg.section_from_path; | 155 | n = ctx.cfg.section_from_path; |
140 | if (n > 0) { | 156 | if (n > 0) { |
141 | slash = rel; | 157 | slash = rel.buf; |
142 | while (slash && n && (slash = strchr(slash, '/'))) | 158 | while (slash && n && (slash = strchr(slash, '/'))) |
143 | n--; | 159 | n--; |
144 | } else { | 160 | } else { |
145 | slash = rel + strlen(rel); | 161 | slash = rel.buf + rel.len; |
146 | while (slash && n && (slash = xstrrchr(rel, slash, '/'))) | 162 | while (slash && n && (slash = xstrrchr(rel.buf, slash, '/'))) |
147 | n++; | 163 | n++; |
148 | } | 164 | } |
149 | if (slash && !n) { | 165 | if (slash && !n) { |
150 | *slash = '\0'; | 166 | *slash = '\0'; |
151 | repo->section = xstrdup(rel); | 167 | repo->section = xstrdup(rel.buf); |
152 | *slash = '/'; | 168 | *slash = '/'; |
153 | if (!prefixcmp(repo->name, repo->section)) { | 169 | if (!prefixcmp(repo->name, repo->section)) { |
154 | repo->name += strlen(repo->section); | 170 | repo->name += strlen(repo->section); |
@@ -158,19 +174,19 @@ static void add_repo(const char *base, const char *path, repo_config_fn fn) | |||
158 | } | 174 | } |
159 | } | 175 | } |
160 | 176 | ||
161 | p = fmt("%s/cgitrc", path); | 177 | strbuf_addstr(path, "cgitrc"); |
162 | if (!stat(p, &st)) | 178 | if (!stat(path->buf, &st)) |
163 | parse_configfile(xstrdup(p), &repo_config); | 179 | parse_configfile(xstrdup(path->buf), &repo_config); |
164 | |||
165 | 180 | ||
166 | free(rel); | 181 | strbuf_release(&rel); |
167 | } | 182 | } |
168 | 183 | ||
169 | static void scan_path(const char *base, const char *path, repo_config_fn fn) | 184 | static void scan_path(const char *base, const char *path, repo_config_fn fn) |
170 | { | 185 | { |
171 | DIR *dir = opendir(path); | 186 | DIR *dir = opendir(path); |
172 | struct dirent *ent; | 187 | struct dirent *ent; |
173 | char *buf; | 188 | struct strbuf pathbuf = STRBUF_INIT; |
189 | size_t pathlen = strlen(path); | ||
174 | struct stat st; | 190 | struct stat st; |
175 | 191 | ||
176 | if (!dir) { | 192 | if (!dir) { |
@@ -178,14 +194,22 @@ static void scan_path(const char *base, const char *path, repo_config_fn fn) | |||
178 | path, strerror(errno), errno); | 194 | path, strerror(errno), errno); |
179 | return; | 195 | return; |
180 | } | 196 | } |
181 | if (is_git_dir(path)) { | 197 | |
182 | add_repo(base, path, fn); | 198 | strbuf_add(&pathbuf, path, strlen(path)); |
199 | if (is_git_dir(pathbuf.buf)) { | ||
200 | add_repo(base, &pathbuf, fn); | ||
183 | goto end; | 201 | goto end; |
184 | } | 202 | } |
185 | if (is_git_dir(fmt("%s/.git", path))) { | 203 | strbuf_addstr(&pathbuf, "/.git"); |
186 | add_repo(base, fmt("%s/.git", path), fn); | 204 | if (is_git_dir(pathbuf.buf)) { |
205 | add_repo(base, &pathbuf, fn); | ||
187 | goto end; | 206 | goto end; |
188 | } | 207 | } |
208 | /* | ||
209 | * Add one because we don't want to lose the trailing '/' when we | ||
210 | * reset the length of pathbuf in the loop below. | ||
211 | */ | ||
212 | pathlen++; | ||
189 | while ((ent = readdir(dir)) != NULL) { | 213 | while ((ent = readdir(dir)) != NULL) { |
190 | if (ent->d_name[0] == '.') { | 214 | if (ent->d_name[0] == '.') { |
191 | if (ent->d_name[1] == '\0') | 215 | if (ent->d_name[1] == '\0') |
@@ -195,24 +219,18 @@ static void scan_path(const char *base, const char *path, repo_config_fn fn) | |||
195 | if (!ctx.cfg.scan_hidden_path) | 219 | if (!ctx.cfg.scan_hidden_path) |
196 | continue; | 220 | continue; |
197 | } | 221 | } |
198 | buf = malloc(strlen(path) + strlen(ent->d_name) + 2); | 222 | strbuf_setlen(&pathbuf, pathlen); |
199 | if (!buf) { | 223 | strbuf_addstr(&pathbuf, ent->d_name); |
200 | fprintf(stderr, "Alloc error on %s: %s (%d)\n", | 224 | if (stat(pathbuf.buf, &st)) { |
201 | path, strerror(errno), errno); | ||
202 | exit(1); | ||
203 | } | ||
204 | sprintf(buf, "%s/%s", path, ent->d_name); | ||
205 | if (stat(buf, &st)) { | ||
206 | fprintf(stderr, "Error checking path %s: %s (%d)\n", | 225 | fprintf(stderr, "Error checking path %s: %s (%d)\n", |
207 | buf, strerror(errno), errno); | 226 | pathbuf.buf, strerror(errno), errno); |
208 | free(buf); | ||
209 | continue; | 227 | continue; |
210 | } | 228 | } |
211 | if (S_ISDIR(st.st_mode)) | 229 | if (S_ISDIR(st.st_mode)) |
212 | scan_path(base, buf, fn); | 230 | scan_path(base, pathbuf.buf, fn); |
213 | free(buf); | ||
214 | } | 231 | } |
215 | end: | 232 | end: |
233 | strbuf_release(&pathbuf); | ||
216 | closedir(dir); | 234 | closedir(dir); |
217 | } | 235 | } |
218 | 236 | ||
@@ -220,7 +238,7 @@ end: | |||
220 | 238 | ||
221 | void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn) | 239 | void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn) |
222 | { | 240 | { |
223 | char line[MAX_PATH * 2], *z; | 241 | struct strbuf line = STRBUF_INIT; |
224 | FILE *projects; | 242 | FILE *projects; |
225 | int err; | 243 | int err; |
226 | 244 | ||
@@ -230,19 +248,19 @@ void scan_projects(const char *path, const char *projectsfile, repo_config_fn fn | |||
230 | projectsfile, strerror(errno), errno); | 248 | projectsfile, strerror(errno), errno); |
231 | return; | 249 | return; |
232 | } | 250 | } |
233 | while (fgets(line, sizeof(line), projects) != NULL) { | 251 | while (strbuf_getline(&line, projects, '\n') != EOF) { |
234 | for (z = &lastc(line); | 252 | if (!line.len) |
235 | strlen(line) && strchr("\n\r", *z); | 253 | continue; |
236 | z = &lastc(line)) | 254 | strbuf_insert(&line, 0, "/", 1); |
237 | *z = '\0'; | 255 | strbuf_insert(&line, 0, path, strlen(path)); |
238 | if (strlen(line)) | 256 | scan_path(path, line.buf, fn); |
239 | scan_path(path, fmt("%s/%s", path, line), fn); | ||
240 | } | 257 | } |
241 | if ((err = ferror(projects))) { | 258 | if ((err = ferror(projects))) { |
242 | fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n", | 259 | fprintf(stderr, "Error reading from projectsfile %s: %s (%d)\n", |
243 | projectsfile, strerror(err), err); | 260 | projectsfile, strerror(err), err); |
244 | } | 261 | } |
245 | fclose(projects); | 262 | fclose(projects); |
263 | strbuf_release(&line); | ||
246 | } | 264 | } |
247 | 265 | ||
248 | void scan_tree(const char *path, repo_config_fn fn) | 266 | void scan_tree(const char *path, repo_config_fn fn) |
@@ -243,15 +243,19 @@ static void print_commit(struct commit *commit, struct rev_info *revs) | |||
243 | cgit_free_commitinfo(info); | 243 | cgit_free_commitinfo(info); |
244 | } | 244 | } |
245 | 245 | ||
246 | static const char *disambiguate_ref(const char *ref) | 246 | static const char *disambiguate_ref(const char *ref, int *must_free_result) |
247 | { | 247 | { |
248 | unsigned char sha1[20]; | 248 | unsigned char sha1[20]; |
249 | const char *longref; | 249 | struct strbuf longref = STRBUF_INIT; |
250 | 250 | ||
251 | longref = fmt("refs/heads/%s", ref); | 251 | strbuf_addf(&longref, "refs/heads/%s", ref); |
252 | if (get_sha1(longref, sha1) == 0) | 252 | if (get_sha1(longref.buf, sha1) == 0) { |
253 | return longref; | 253 | *must_free_result = 1; |
254 | return strbuf_detach(&longref, NULL); | ||
255 | } | ||
254 | 256 | ||
257 | *must_free_result = 0; | ||
258 | strbuf_release(&longref); | ||
255 | return ref; | 259 | return ref; |
256 | } | 260 | } |
257 | 261 | ||
@@ -284,24 +288,26 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern | |||
284 | struct commit *commit; | 288 | struct commit *commit; |
285 | struct vector vec = VECTOR_INIT(char *); | 289 | struct vector vec = VECTOR_INIT(char *); |
286 | int i, columns = commit_graph ? 4 : 3; | 290 | int i, columns = commit_graph ? 4 : 3; |
287 | char *arg; | 291 | int must_free_tip = 0; |
292 | struct strbuf argbuf = STRBUF_INIT; | ||
288 | 293 | ||
289 | /* First argv is NULL */ | 294 | /* First argv is NULL */ |
290 | vector_push(&vec, NULL, 0); | 295 | vector_push(&vec, NULL, 0); |
291 | 296 | ||
292 | if (!tip) | 297 | if (!tip) |
293 | tip = ctx.qry.head; | 298 | tip = ctx.qry.head; |
294 | tip = disambiguate_ref(tip); | 299 | tip = disambiguate_ref(tip, &must_free_tip); |
295 | vector_push(&vec, &tip, 0); | 300 | vector_push(&vec, &tip, 0); |
296 | 301 | ||
297 | if (grep && pattern && *pattern) { | 302 | if (grep && pattern && *pattern) { |
298 | pattern = xstrdup(pattern); | 303 | pattern = xstrdup(pattern); |
299 | if (!strcmp(grep, "grep") || !strcmp(grep, "author") || | 304 | if (!strcmp(grep, "grep") || !strcmp(grep, "author") || |
300 | !strcmp(grep, "committer")) { | 305 | !strcmp(grep, "committer")) { |
301 | arg = fmt("--%s=%s", grep, pattern); | 306 | strbuf_addf(&argbuf, "--%s=%s", grep, pattern); |
302 | vector_push(&vec, &arg, 0); | 307 | vector_push(&vec, &argbuf.buf, 0); |
303 | } | 308 | } |
304 | if (!strcmp(grep, "range")) { | 309 | if (!strcmp(grep, "range")) { |
310 | char *arg; | ||
305 | /* Split the pattern at whitespace and add each token | 311 | /* Split the pattern at whitespace and add each token |
306 | * as a revision expression. Do not accept other | 312 | * as a revision expression. Do not accept other |
307 | * rev-list options. Also, replace the previously | 313 | * rev-list options. Also, replace the previously |
@@ -336,8 +342,8 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern | |||
336 | } | 342 | } |
337 | 343 | ||
338 | if (path) { | 344 | if (path) { |
339 | arg = "--"; | 345 | static const char *double_dash_arg = "--"; |
340 | vector_push(&vec, &arg, 0); | 346 | vector_push(&vec, &double_dash_arg, 0); |
341 | vector_push(&vec, &path, 0); | 347 | vector_push(&vec, &path, 0); |
342 | } | 348 | } |
343 | 349 | ||
@@ -430,4 +436,9 @@ void cgit_print_log(const char *tip, int ofs, int cnt, char *grep, char *pattern | |||
430 | ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg); | 436 | ctx.qry.vpath, 0, NULL, NULL, ctx.qry.showmsg); |
431 | html("</td></tr>\n"); | 437 | html("</td></tr>\n"); |
432 | } | 438 | } |
439 | |||
440 | /* If we allocated tip then it is safe to cast away const. */ | ||
441 | if (must_free_tip) | ||
442 | free((char*) tip); | ||
443 | strbuf_release(&argbuf); | ||
433 | } | 444 | } |
@@ -109,9 +109,9 @@ static int print_object(const unsigned char *sha1, const char *path) | |||
109 | static char *buildpath(const char *base, int baselen, const char *path) | 109 | static char *buildpath(const char *base, int baselen, const char *path) |
110 | { | 110 | { |
111 | if (path[0]) | 111 | if (path[0]) |
112 | return fmt("%.*s%s/", baselen, base, path); | 112 | return fmtalloc("%.*s%s/", baselen, base, path); |
113 | else | 113 | else |
114 | return fmt("%.*s/", baselen, base); | 114 | return fmtalloc("%.*s/", baselen, base); |
115 | } | 115 | } |
116 | 116 | ||
117 | static void print_dir(const unsigned char *sha1, const char *base, | 117 | static void print_dir(const unsigned char *sha1, const char *base, |
@@ -142,6 +142,7 @@ static void print_dir(const unsigned char *sha1, const char *base, | |||
142 | fullpath); | 142 | fullpath); |
143 | html("</li>\n"); | 143 | html("</li>\n"); |
144 | } | 144 | } |
145 | free(fullpath); | ||
145 | } | 146 | } |
146 | 147 | ||
147 | static void print_dir_entry(const unsigned char *sha1, const char *base, | 148 | static void print_dir_entry(const unsigned char *sha1, const char *base, |
@@ -159,6 +160,7 @@ static void print_dir_entry(const unsigned char *sha1, const char *base, | |||
159 | cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, | 160 | cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, |
160 | fullpath); | 161 | fullpath); |
161 | html("</li>\n"); | 162 | html("</li>\n"); |
163 | free(fullpath); | ||
162 | } | 164 | } |
163 | 165 | ||
164 | static void print_dir_tail(void) | 166 | static void print_dir_tail(void) |
@@ -99,7 +99,7 @@ static void print_tag_header() | |||
99 | static void print_tag_downloads(const struct cgit_repo *repo, const char *ref) | 99 | static void print_tag_downloads(const struct cgit_repo *repo, const char *ref) |
100 | { | 100 | { |
101 | const struct cgit_snapshot_format* f; | 101 | const struct cgit_snapshot_format* f; |
102 | char *filename; | 102 | struct strbuf filename = STRBUF_INIT; |
103 | const char *basename; | 103 | const char *basename; |
104 | int free_ref = 0; | 104 | int free_ref = 0; |
105 | 105 | ||
@@ -111,7 +111,7 @@ static void print_tag_downloads(const struct cgit_repo *repo, const char *ref) | |||
111 | if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1])) | 111 | if ((ref[0] == 'v' || ref[0] == 'V') && isdigit(ref[1])) |
112 | ref++; | 112 | ref++; |
113 | if (isdigit(ref[0])) { | 113 | if (isdigit(ref[0])) { |
114 | ref = xstrdup(fmt("%s-%s", basename, ref)); | 114 | ref = fmtalloc("%s-%s", basename, ref); |
115 | free_ref = 1; | 115 | free_ref = 1; |
116 | } | 116 | } |
117 | } | 117 | } |
@@ -119,13 +119,15 @@ static void print_tag_downloads(const struct cgit_repo *repo, const char *ref) | |||
119 | for (f = cgit_snapshot_formats; f->suffix; f++) { | 119 | for (f = cgit_snapshot_formats; f->suffix; f++) { |
120 | if (!(repo->snapshots & f->bit)) | 120 | if (!(repo->snapshots & f->bit)) |
121 | continue; | 121 | continue; |
122 | filename = fmt("%s%s", ref, f->suffix); | 122 | strbuf_reset(&filename); |
123 | cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); | 123 | strbuf_addf(&filename, "%s%s", ref, f->suffix); |
124 | cgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL, filename.buf); | ||
124 | html(" "); | 125 | html(" "); |
125 | } | 126 | } |
126 | 127 | ||
127 | if (free_ref) | 128 | if (free_ref) |
128 | free((char *)ref); | 129 | free((char *)ref); |
130 | strbuf_release(&filename); | ||
129 | } | 131 | } |
130 | 132 | ||
131 | static int print_tag(struct refinfo *ref) | 133 | static int print_tag(struct refinfo *ref) |
diff --git a/ui-repolist.c b/ui-repolist.c index 76fe71a..47ca997 100644 --- a/ui-repolist.c +++ b/ui-repolist.c | |||
@@ -33,7 +33,7 @@ static time_t read_agefile(char *path) | |||
33 | 33 | ||
34 | static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime) | 34 | static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime) |
35 | { | 35 | { |
36 | char *path; | 36 | struct strbuf path = STRBUF_INIT; |
37 | struct stat s; | 37 | struct stat s; |
38 | struct cgit_repo *r = (struct cgit_repo *)repo; | 38 | struct cgit_repo *r = (struct cgit_repo *)repo; |
39 | 39 | ||
@@ -41,32 +41,36 @@ static int get_repo_modtime(const struct cgit_repo *repo, time_t *mtime) | |||
41 | *mtime = repo->mtime; | 41 | *mtime = repo->mtime; |
42 | return 1; | 42 | return 1; |
43 | } | 43 | } |
44 | path = fmt("%s/%s", repo->path, ctx.cfg.agefile); | 44 | strbuf_addf(&path, "%s/%s", repo->path, ctx.cfg.agefile); |
45 | if (stat(path, &s) == 0) { | 45 | if (stat(path.buf, &s) == 0) { |
46 | *mtime = read_agefile(path); | 46 | *mtime = read_agefile(path.buf); |
47 | if (*mtime) { | 47 | if (*mtime) { |
48 | r->mtime = *mtime; | 48 | r->mtime = *mtime; |
49 | return 1; | 49 | goto end; |
50 | } | 50 | } |
51 | } | 51 | } |
52 | 52 | ||
53 | path = fmt("%s/refs/heads/%s", repo->path, repo->defbranch ? | 53 | strbuf_reset(&path); |
54 | repo->defbranch : "master"); | 54 | strbuf_addf(&path, "%s/refs/heads/%s", repo->path, |
55 | if (stat(path, &s) == 0) { | 55 | repo->defbranch ? repo->defbranch : "master"); |
56 | if (stat(path.buf, &s) == 0) { | ||
56 | *mtime = s.st_mtime; | 57 | *mtime = s.st_mtime; |
57 | r->mtime = *mtime; | 58 | r->mtime = *mtime; |
58 | return 1; | 59 | goto end; |
59 | } | 60 | } |
60 | 61 | ||
61 | path = fmt("%s/%s", repo->path, "packed-refs"); | 62 | strbuf_reset(&path); |
62 | if (stat(path, &s) == 0) { | 63 | strbuf_addf(&path, "%s/%s", repo->path, "packed-refs"); |
64 | if (stat(path.buf, &s) == 0) { | ||
63 | *mtime = s.st_mtime; | 65 | *mtime = s.st_mtime; |
64 | r->mtime = *mtime; | 66 | r->mtime = *mtime; |
65 | return 1; | 67 | goto end; |
66 | } | 68 | } |
67 | 69 | ||
68 | *mtime = 0; | 70 | *mtime = 0; |
69 | r->mtime = *mtime; | 71 | r->mtime = *mtime; |
72 | end: | ||
73 | strbuf_release(&path); | ||
70 | return (r->mtime != 0); | 74 | return (r->mtime != 0); |
71 | } | 75 | } |
72 | 76 | ||
diff --git a/ui-shared.c b/ui-shared.c index b93b77a..519eef7 100644 --- a/ui-shared.c +++ b/ui-shared.c | |||
@@ -62,7 +62,7 @@ const char *cgit_hosturl() | |||
62 | return NULL; | 62 | return NULL; |
63 | if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80) | 63 | if (!ctx.env.server_port || atoi(ctx.env.server_port) == 80) |
64 | return ctx.env.server_name; | 64 | return ctx.env.server_name; |
65 | return xstrdup(fmt("%s:%s", ctx.env.server_name, ctx.env.server_port)); | 65 | return fmtalloc("%s:%s", ctx.env.server_name, ctx.env.server_port); |
66 | } | 66 | } |
67 | 67 | ||
68 | const char *cgit_rooturl() | 68 | const char *cgit_rooturl() |
@@ -75,31 +75,30 @@ const char *cgit_rooturl() | |||
75 | 75 | ||
76 | char *cgit_repourl(const char *reponame) | 76 | char *cgit_repourl(const char *reponame) |
77 | { | 77 | { |
78 | if (ctx.cfg.virtual_root) { | 78 | if (ctx.cfg.virtual_root) |
79 | return fmt("%s%s/", ctx.cfg.virtual_root, reponame); | 79 | return fmtalloc("%s%s/", ctx.cfg.virtual_root, reponame); |
80 | } else { | 80 | else |
81 | return fmt("?r=%s", reponame); | 81 | return fmtalloc("?r=%s", reponame); |
82 | } | ||
83 | } | 82 | } |
84 | 83 | ||
85 | char *cgit_fileurl(const char *reponame, const char *pagename, | 84 | char *cgit_fileurl(const char *reponame, const char *pagename, |
86 | const char *filename, const char *query) | 85 | const char *filename, const char *query) |
87 | { | 86 | { |
88 | char *tmp; | 87 | struct strbuf sb = STRBUF_INIT; |
89 | char *delim; | 88 | char *delim; |
90 | 89 | ||
91 | if (ctx.cfg.virtual_root) { | 90 | if (ctx.cfg.virtual_root) { |
92 | tmp = fmt("%s%s/%s/%s", ctx.cfg.virtual_root, reponame, | 91 | strbuf_addf(&sb, "%s%s/%s/%s", ctx.cfg.virtual_root, reponame, |
93 | pagename, (filename ? filename:"")); | 92 | pagename, (filename ? filename:"")); |
94 | delim = "?"; | 93 | delim = "?"; |
95 | } else { | 94 | } else { |
96 | tmp = fmt("?url=%s/%s/%s", reponame, pagename, | 95 | strbuf_addf(&sb, "?url=%s/%s/%s", reponame, pagename, |
97 | (filename ? filename : "")); | 96 | (filename ? filename : "")); |
98 | delim = "&"; | 97 | delim = "&"; |
99 | } | 98 | } |
100 | if (query) | 99 | if (query) |
101 | tmp = fmt("%s%s%s", tmp, delim, query); | 100 | strbuf_addf(&sb, "%s%s", delim, query); |
102 | return tmp; | 101 | return strbuf_detach(&sb, NULL); |
103 | } | 102 | } |
104 | 103 | ||
105 | char *cgit_pageurl(const char *reponame, const char *pagename, | 104 | char *cgit_pageurl(const char *reponame, const char *pagename, |
@@ -548,21 +547,21 @@ void cgit_submodule_link(const char *class, char *path, const char *rev) | |||
548 | htmlf("class='%s' ", class); | 547 | htmlf("class='%s' ", class); |
549 | html("href='"); | 548 | html("href='"); |
550 | if (item) { | 549 | if (item) { |
551 | html_attr(fmt(item->util, rev)); | 550 | html_attrf(item->util, rev); |
552 | } else if (ctx.repo->module_link) { | 551 | } else if (ctx.repo->module_link) { |
553 | dir = strrchr(path, '/'); | 552 | dir = strrchr(path, '/'); |
554 | if (dir) | 553 | if (dir) |
555 | dir++; | 554 | dir++; |
556 | else | 555 | else |
557 | dir = path; | 556 | dir = path; |
558 | html_attr(fmt(ctx.repo->module_link, dir, rev)); | 557 | html_attrf(ctx.repo->module_link, dir, rev); |
559 | } else { | 558 | } else { |
560 | html("#"); | 559 | html("#"); |
561 | } | 560 | } |
562 | html("'>"); | 561 | html("'>"); |
563 | html_txt(path); | 562 | html_txt(path); |
564 | html("</a>"); | 563 | html("</a>"); |
565 | html_txt(fmt(" @ %.7s", rev)); | 564 | html_txtf(" @ %.7s", rev); |
566 | if (item && tail) | 565 | if (item && tail) |
567 | path[len - 1] = tail; | 566 | path[len - 1] = tail; |
568 | } | 567 | } |
@@ -678,12 +677,16 @@ void cgit_print_docstart(struct cgit_context *ctx) | |||
678 | html("'/>\n"); | 677 | html("'/>\n"); |
679 | } | 678 | } |
680 | if (host && ctx->repo && ctx->qry.head) { | 679 | if (host && ctx->repo && ctx->qry.head) { |
680 | struct strbuf sb = STRBUF_INIT; | ||
681 | strbuf_addf(&sb, "h=%s", ctx->qry.head); | ||
682 | |||
681 | html("<link rel='alternate' title='Atom feed' href='"); | 683 | html("<link rel='alternate' title='Atom feed' href='"); |
682 | html(cgit_httpscheme()); | 684 | html(cgit_httpscheme()); |
683 | html_attr(cgit_hosturl()); | 685 | html_attr(cgit_hosturl()); |
684 | html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath, | 686 | html_attr(cgit_fileurl(ctx->repo->url, "atom", ctx->qry.vpath, |
685 | fmt("h=%s", ctx->qry.head))); | 687 | sb.buf)); |
686 | html("' type='application/atom+xml'/>\n"); | 688 | html("' type='application/atom+xml'/>\n"); |
689 | strbuf_release(&sb); | ||
687 | } | 690 | } |
688 | if (ctx->cfg.head_include) | 691 | if (ctx->cfg.head_include) |
689 | html_include(ctx->cfg.head_include); | 692 | html_include(ctx->cfg.head_include); |
@@ -725,13 +728,14 @@ static int print_branch_option(const char *refname, const unsigned char *sha1, | |||
725 | void cgit_add_hidden_formfields(int incl_head, int incl_search, | 728 | void cgit_add_hidden_formfields(int incl_head, int incl_search, |
726 | const char *page) | 729 | const char *page) |
727 | { | 730 | { |
728 | char *url; | ||
729 | |||
730 | if (!ctx.cfg.virtual_root) { | 731 | if (!ctx.cfg.virtual_root) { |
731 | url = fmt("%s/%s", ctx.qry.repo, page); | 732 | struct strbuf url = STRBUF_INIT; |
733 | |||
734 | strbuf_addf(&url, "%s/%s", ctx.qry.repo, page); | ||
732 | if (ctx.qry.vpath) | 735 | if (ctx.qry.vpath) |
733 | url = fmt("%s/%s", url, ctx.qry.vpath); | 736 | strbuf_addf(&url, "/%s", ctx.qry.vpath); |
734 | html_hidden("url", url); | 737 | html_hidden("url", url.buf); |
738 | strbuf_release(&url); | ||
735 | } | 739 | } |
736 | 740 | ||
737 | if (incl_head && ctx.qry.head && ctx.repo->defbranch && | 741 | if (incl_head && ctx.qry.head && ctx.repo->defbranch && |
@@ -926,20 +930,23 @@ void cgit_print_snapshot_links(const char *repo, const char *head, | |||
926 | const char *hex, int snapshots) | 930 | const char *hex, int snapshots) |
927 | { | 931 | { |
928 | const struct cgit_snapshot_format* f; | 932 | const struct cgit_snapshot_format* f; |
929 | char *prefix; | 933 | struct strbuf filename = STRBUF_INIT; |
930 | char *filename; | 934 | size_t prefixlen; |
931 | unsigned char sha1[20]; | 935 | unsigned char sha1[20]; |
932 | 936 | ||
933 | if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 && | 937 | if (get_sha1(fmt("refs/tags/%s", hex), sha1) == 0 && |
934 | (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1])) | 938 | (hex[0] == 'v' || hex[0] == 'V') && isdigit(hex[1])) |
935 | hex++; | 939 | hex++; |
936 | prefix = xstrdup(fmt("%s-%s", cgit_repobasename(repo), hex)); | 940 | strbuf_addf(&filename, "%s-%s", cgit_repobasename(repo), hex); |
941 | prefixlen = filename.len; | ||
937 | for (f = cgit_snapshot_formats; f->suffix; f++) { | 942 | for (f = cgit_snapshot_formats; f->suffix; f++) { |
938 | if (!(snapshots & f->bit)) | 943 | if (!(snapshots & f->bit)) |
939 | continue; | 944 | continue; |
940 | filename = fmt("%s%s", prefix, f->suffix); | 945 | strbuf_setlen(&filename, prefixlen); |
941 | cgit_snapshot_link(filename, NULL, NULL, NULL, NULL, filename); | 946 | strbuf_addstr(&filename, f->suffix); |
947 | cgit_snapshot_link(filename.buf, NULL, NULL, NULL, NULL, | ||
948 | filename.buf); | ||
942 | html("<br/>"); | 949 | html("<br/>"); |
943 | } | 950 | } |
944 | free(prefix); | 951 | strbuf_release(&filename); |
945 | } | 952 | } |
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 @@ | |||
15 | static int write_archive_type(const char *format, const char *hex, const char *prefix) | 15 | static int write_archive_type(const char *format, const char *hex, const char *prefix) |
16 | { | 16 | { |
17 | struct argv_array argv = ARGV_ARRAY_INIT; | 17 | struct argv_array argv = ARGV_ARRAY_INIT; |
18 | const char **nargv; | ||
19 | int result; | ||
18 | argv_array_push(&argv, "snapshot"); | 20 | argv_array_push(&argv, "snapshot"); |
19 | argv_array_push(&argv, format); | 21 | argv_array_push(&argv, format); |
20 | if (prefix) { | 22 | if (prefix) { |
23 | struct strbuf buf = STRBUF_INIT; | ||
24 | strbuf_addstr(&buf, prefix); | ||
25 | strbuf_addch(&buf, '/'); | ||
21 | argv_array_push(&argv, "--prefix"); | 26 | argv_array_push(&argv, "--prefix"); |
22 | argv_array_push(&argv, fmt("%s/", prefix)); | 27 | argv_array_push(&argv, buf.buf); |
28 | strbuf_release(&buf); | ||
23 | } | 29 | } |
24 | argv_array_push(&argv, hex); | 30 | argv_array_push(&argv, hex); |
25 | return write_archive(argv.argc, argv.argv, NULL, 1, NULL, 0); | 31 | /* |
32 | * Now we need to copy the pointers to arguments into a new | ||
33 | * structure because write_archive will rearrange its arguments | ||
34 | * which may result in duplicated/missing entries causing leaks | ||
35 | * or double-frees in argv_array_clear. | ||
36 | */ | ||
37 | nargv = xmalloc(sizeof(char *) * (argv.argc + 1)); | ||
38 | /* argv_array guarantees a trailing NULL entry. */ | ||
39 | memcpy(nargv, argv.argv, sizeof(char *) * (argv.argc + 1)); | ||
40 | |||
41 | result = write_archive(argv.argc, nargv, NULL, 1, NULL, 0); | ||
42 | argv_array_clear(&argv); | ||
43 | free(nargv); | ||
44 | return result; | ||
26 | } | 45 | } |
27 | 46 | ||
28 | static int write_tar_archive(const char *hex, const char *prefix) | 47 | 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, | |||
129 | { | 148 | { |
130 | const char *reponame; | 149 | const char *reponame; |
131 | unsigned char sha1[20]; | 150 | unsigned char sha1[20]; |
132 | char *snapshot; | 151 | struct strbuf snapshot = STRBUF_INIT; |
152 | int result = 1; | ||
133 | 153 | ||
134 | snapshot = xstrdup(filename); | 154 | strbuf_addstr(&snapshot, filename); |
135 | snapshot[strlen(snapshot) - strlen(format->suffix)] = '\0'; | 155 | strbuf_setlen(&snapshot, snapshot.len - strlen(format->suffix)); |
136 | 156 | ||
137 | if (get_sha1(snapshot, sha1) == 0) | 157 | if (get_sha1(snapshot.buf, sha1) == 0) |
138 | return snapshot; | 158 | goto out; |
139 | 159 | ||
140 | reponame = cgit_repobasename(url); | 160 | reponame = cgit_repobasename(url); |
141 | if (prefixcmp(snapshot, reponame) == 0) { | 161 | if (prefixcmp(snapshot.buf, reponame) == 0) { |
142 | snapshot += strlen(reponame); | 162 | const char *new_start = snapshot.buf; |
143 | while (snapshot && (*snapshot == '-' || *snapshot == '_')) | 163 | new_start += strlen(reponame); |
144 | snapshot++; | 164 | while (new_start && (*new_start == '-' || *new_start == '_')) |
165 | new_start++; | ||
166 | strbuf_splice(&snapshot, 0, new_start - snapshot.buf, "", 0); | ||
145 | } | 167 | } |
146 | 168 | ||
147 | if (get_sha1(snapshot, sha1) == 0) | 169 | if (get_sha1(snapshot.buf, sha1) == 0) |
148 | return snapshot; | 170 | goto out; |
149 | 171 | ||
150 | snapshot = fmt("v%s", snapshot); | 172 | strbuf_insert(&snapshot, 0, "v", 1); |
151 | if (get_sha1(snapshot, sha1) == 0) | 173 | if (get_sha1(snapshot.buf, sha1) == 0) |
152 | return snapshot; | 174 | goto out; |
153 | 175 | ||
154 | return NULL; | 176 | result = 0; |
177 | strbuf_release(&snapshot); | ||
178 | |||
179 | out: | ||
180 | return result ? strbuf_detach(&snapshot, NULL) : NULL; | ||
155 | } | 181 | } |
156 | 182 | ||
157 | __attribute__((format (printf, 1, 2))) | 183 | __attribute__((format (printf, 1, 2))) |
diff --git a/ui-summary.c b/ui-summary.c index bd123ef..f965b32 100644 --- a/ui-summary.c +++ b/ui-summary.c | |||
@@ -17,6 +17,7 @@ | |||
17 | static void print_url(char *base, char *suffix) | 17 | static void print_url(char *base, char *suffix) |
18 | { | 18 | { |
19 | int columns = 3; | 19 | int columns = 3; |
20 | struct strbuf basebuf = STRBUF_INIT; | ||
20 | 21 | ||
21 | if (ctx.repo->enable_log_filecount) | 22 | if (ctx.repo->enable_log_filecount) |
22 | columns++; | 23 | columns++; |
@@ -25,13 +26,16 @@ static void print_url(char *base, char *suffix) | |||
25 | 26 | ||
26 | if (!base || !*base) | 27 | if (!base || !*base) |
27 | return; | 28 | return; |
28 | if (suffix && *suffix) | 29 | if (suffix && *suffix) { |
29 | base = fmt("%s/%s", base, suffix); | 30 | strbuf_addf(&basebuf, "%s/%s", base, suffix); |
31 | base = basebuf.buf; | ||
32 | } | ||
30 | htmlf("<tr><td colspan='%d'><a href='", columns); | 33 | htmlf("<tr><td colspan='%d'><a href='", columns); |
31 | html_url_path(base); | 34 | html_url_path(base); |
32 | html("'>"); | 35 | html("'>"); |
33 | html_txt(base); | 36 | html_txt(base); |
34 | html("</a></td></tr>\n"); | 37 | html("</a></td></tr>\n"); |
38 | strbuf_release(&basebuf); | ||
35 | } | 39 | } |
36 | 40 | ||
37 | static void print_urls(char *txt, char *suffix) | 41 | static void print_urls(char *txt, char *suffix) |
@@ -112,8 +116,8 @@ void cgit_print_repo_readme(char *path) | |||
112 | 116 | ||
113 | /* Prepend repo path to relative readme path unless tracked. */ | 117 | /* Prepend repo path to relative readme path unless tracked. */ |
114 | if (!ref && *ctx.repo->readme != '/') | 118 | if (!ref && *ctx.repo->readme != '/') |
115 | ctx.repo->readme = xstrdup(fmt("%s/%s", ctx.repo->path, | 119 | ctx.repo->readme = fmtalloc("%s/%s", ctx.repo->path, |
116 | ctx.repo->readme)); | 120 | ctx.repo->readme); |
117 | 121 | ||
118 | /* If a subpath is specified for the about page, make it relative | 122 | /* If a subpath is specified for the about page, make it relative |
119 | * to the directory containing the configured readme. | 123 | * to the directory containing the configured readme. |
@@ -41,6 +41,7 @@ static void print_download_links(char *revname) | |||
41 | 41 | ||
42 | void cgit_print_tag(char *revname) | 42 | void cgit_print_tag(char *revname) |
43 | { | 43 | { |
44 | struct strbuf fullref = STRBUF_INIT; | ||
44 | unsigned char sha1[20]; | 45 | unsigned char sha1[20]; |
45 | struct object *obj; | 46 | struct object *obj; |
46 | struct tag *tag; | 47 | struct tag *tag; |
@@ -49,20 +50,21 @@ void cgit_print_tag(char *revname) | |||
49 | if (!revname) | 50 | if (!revname) |
50 | revname = ctx.qry.head; | 51 | revname = ctx.qry.head; |
51 | 52 | ||
52 | if (get_sha1(fmt("refs/tags/%s", revname), sha1)) { | 53 | strbuf_addf(&fullref, "refs/tags/%s", revname); |
54 | if (get_sha1(fullref.buf, sha1)) { | ||
53 | cgit_print_error("Bad tag reference: %s", revname); | 55 | cgit_print_error("Bad tag reference: %s", revname); |
54 | return; | 56 | goto cleanup; |
55 | } | 57 | } |
56 | obj = parse_object(sha1); | 58 | obj = parse_object(sha1); |
57 | if (!obj) { | 59 | if (!obj) { |
58 | cgit_print_error("Bad object id: %s", sha1_to_hex(sha1)); | 60 | cgit_print_error("Bad object id: %s", sha1_to_hex(sha1)); |
59 | return; | 61 | goto cleanup; |
60 | } | 62 | } |
61 | if (obj->type == OBJ_TAG) { | 63 | if (obj->type == OBJ_TAG) { |
62 | tag = lookup_tag(sha1); | 64 | tag = lookup_tag(sha1); |
63 | if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { | 65 | if (!tag || parse_tag(tag) || !(info = cgit_parse_tag(tag))) { |
64 | cgit_print_error("Bad tag object: %s", revname); | 66 | cgit_print_error("Bad tag object: %s", revname); |
65 | return; | 67 | goto cleanup; |
66 | } | 68 | } |
67 | html("<table class='commit-info'>\n"); | 69 | html("<table class='commit-info'>\n"); |
68 | htmlf("<tr><td>tag name</td><td>"); | 70 | htmlf("<tr><td>tag name</td><td>"); |
@@ -101,5 +103,7 @@ void cgit_print_tag(char *revname) | |||
101 | print_download_links(revname); | 103 | print_download_links(revname); |
102 | html("</table>\n"); | 104 | html("</table>\n"); |
103 | } | 105 | } |
104 | return; | 106 | |
107 | cleanup: | ||
108 | strbuf_release(&fullref); | ||
105 | } | 109 | } |
@@ -129,14 +129,14 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen, | |||
129 | { | 129 | { |
130 | struct walk_tree_context *walk_tree_ctx = cbdata; | 130 | struct walk_tree_context *walk_tree_ctx = cbdata; |
131 | char *name; | 131 | char *name; |
132 | char *fullpath; | 132 | struct strbuf fullpath = STRBUF_INIT; |
133 | char *class; | 133 | struct strbuf class = STRBUF_INIT; |
134 | enum object_type type; | 134 | enum object_type type; |
135 | unsigned long size = 0; | 135 | unsigned long size = 0; |
136 | 136 | ||
137 | name = xstrdup(pathname); | 137 | name = xstrdup(pathname); |
138 | fullpath = fmt("%s%s%s", ctx.qry.path ? ctx.qry.path : "", | 138 | strbuf_addf(&fullpath, "%s%s%s", ctx.qry.path ? ctx.qry.path : "", |
139 | ctx.qry.path ? "/" : "", name); | 139 | ctx.qry.path ? "/" : "", name); |
140 | 140 | ||
141 | if (!S_ISGITLINK(mode)) { | 141 | if (!S_ISGITLINK(mode)) { |
142 | type = sha1_object_info(sha1, &size); | 142 | type = sha1_object_info(sha1, &size); |
@@ -152,33 +152,34 @@ static int ls_item(const unsigned char *sha1, const char *base, int baselen, | |||
152 | cgit_print_filemode(mode); | 152 | cgit_print_filemode(mode); |
153 | html("</td><td>"); | 153 | html("</td><td>"); |
154 | if (S_ISGITLINK(mode)) { | 154 | if (S_ISGITLINK(mode)) { |
155 | cgit_submodule_link("ls-mod", fullpath, sha1_to_hex(sha1)); | 155 | cgit_submodule_link("ls-mod", fullpath.buf, sha1_to_hex(sha1)); |
156 | } else if (S_ISDIR(mode)) { | 156 | } else if (S_ISDIR(mode)) { |
157 | cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, | 157 | cgit_tree_link(name, NULL, "ls-dir", ctx.qry.head, |
158 | walk_tree_ctx->curr_rev, fullpath); | 158 | walk_tree_ctx->curr_rev, fullpath.buf); |
159 | } else { | 159 | } else { |
160 | class = strrchr(name, '.'); | 160 | char *ext = strrchr(name, '.'); |
161 | if (class != NULL) { | 161 | strbuf_addstr(&class, "ls-blob"); |
162 | class = fmt("ls-blob %s", class + 1); | 162 | if (ext) |
163 | } else | 163 | strbuf_addf(&class, " %s", ext + 1); |
164 | class = "ls-blob"; | 164 | cgit_tree_link(name, NULL, class.buf, ctx.qry.head, |
165 | cgit_tree_link(name, NULL, class, ctx.qry.head, | 165 | walk_tree_ctx->curr_rev, fullpath.buf); |
166 | walk_tree_ctx->curr_rev, fullpath); | ||
167 | } | 166 | } |
168 | htmlf("</td><td class='ls-size'>%li</td>", size); | 167 | htmlf("</td><td class='ls-size'>%li</td>", size); |
169 | 168 | ||
170 | html("<td>"); | 169 | html("<td>"); |
171 | cgit_log_link("log", NULL, "button", ctx.qry.head, | 170 | cgit_log_link("log", NULL, "button", ctx.qry.head, |
172 | walk_tree_ctx->curr_rev, fullpath, 0, NULL, NULL, | 171 | walk_tree_ctx->curr_rev, fullpath.buf, 0, NULL, NULL, |
173 | ctx.qry.showmsg); | 172 | ctx.qry.showmsg); |
174 | if (ctx.repo->max_stats) | 173 | if (ctx.repo->max_stats) |
175 | cgit_stats_link("stats", NULL, "button", ctx.qry.head, | 174 | cgit_stats_link("stats", NULL, "button", ctx.qry.head, |
176 | fullpath); | 175 | fullpath.buf); |
177 | if (!S_ISGITLINK(mode)) | 176 | if (!S_ISGITLINK(mode)) |
178 | cgit_plain_link("plain", NULL, "button", ctx.qry.head, | 177 | cgit_plain_link("plain", NULL, "button", ctx.qry.head, |
179 | walk_tree_ctx->curr_rev, fullpath); | 178 | walk_tree_ctx->curr_rev, fullpath.buf); |
180 | html("</td></tr>\n"); | 179 | html("</td></tr>\n"); |
181 | free(name); | 180 | free(name); |
181 | strbuf_release(&fullpath); | ||
182 | strbuf_release(&class); | ||
182 | return 0; | 183 | return 0; |
183 | } | 184 | } |
184 | 185 | ||