aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar John Keeping <john@keeping.me.uk>2013-04-06 18:28:57 (JST)
committerGravatar Jason A. Donenfeld <Jason@zx2c4.com>2013-04-08 23:12:52 (JST)
commitfb3655df3bf85bd405c5921bbd4b3a54c705c839 (patch)
tree419a962a0b82f5ba3023791549044ff462229250
parent42d5476f258e7909682f1b611da00d64507d45c6 (diff)
downloadcgit-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.c57
-rw-r--r--cgit.c72
-rw-r--r--scan-tree.c160
-rw-r--r--ui-log.c33
-rw-r--r--ui-plain.c6
-rw-r--r--ui-refs.c10
-rw-r--r--ui-repolist.c28
-rw-r--r--ui-shared.c63
-rw-r--r--ui-snapshot.c60
-rw-r--r--ui-summary.c12
-rw-r--r--ui-tag.c14
-rw-r--r--ui-tree.c33
12 files changed, 305 insertions, 243 deletions
diff --git a/cache.c b/cache.c
index 3127fc2..c1d777b 100644
--- a/cache.c
+++ b/cache.c
@@ -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}
diff --git a/cgit.c b/cgit.c
index 4e51283..f73c7b0 100644
--- a/cgit.c
+++ b/cgit.c
@@ -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)
577static char *build_snapshot_setting(int bitmap) 577static 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
597static char *get_first_line(char *txt) 592static 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 */
662static int generate_cached_repolist(const char *path, const char *cached_rc) 657static 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; 686out:
687 strbuf_release(&locked_rc);
688 return result;
690} 689}
691 690
692static void process_cached_repolist(const char *path) 691static 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));
733out:
734 strbuf_release(&cached_rc);
734} 735}
735 736
736static void cgit_parse_args(int argc, const char **argv) 737static void cgit_parse_args(int argc, const char **argv)
@@ -812,7 +813,6 @@ static int calc_ttl()
812int main(int argc, const char **argv) 813int 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