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 |