-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | cache.c | 4 | ||||
m--------- | git | 0 | ||||
-rwxr-xr-x | tests/setup.sh | 6 | ||||
-rw-r--r-- | ui-plain.c | 2 |
5 files changed, 8 insertions, 6 deletions
@@ -1,129 +1,129 @@ CGIT_VERSION = v0.8.1 CGIT_SCRIPT_NAME = cgit.cgi CGIT_SCRIPT_PATH = /var/www/htdocs/cgit CGIT_CONFIG = /etc/cgitrc CACHE_ROOT = /var/cache/cgit SHA1_HEADER = <openssl/sha.h> -GIT_VER = 1.6.0.2 +GIT_VER = 1.6.0.3 GIT_URL = http://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.bz2 # # Let the user override the above settings. # -include cgit.conf # # Define a way to invoke make in subdirs quietly, shamelessly ripped # from git.git # QUIET_SUBDIR0 = +$(MAKE) -C # space to separate -C and subdir QUIET_SUBDIR1 = ifneq ($(findstring $(MAKEFLAGS),w),w) PRINT_DIR = --no-print-directory else # "make -w" NO_SUBDIR = : endif ifndef V QUIET_CC = @echo ' ' CC $@; QUIET_MM = @echo ' ' MM $@; QUIET_SUBDIR0 = +@subdir= QUIET_SUBDIR1 = ;$(NO_SUBDIR) echo ' ' SUBDIR $$subdir; \ $(MAKE) $(PRINT_DIR) -C $$subdir endif # # Define a pattern rule for automatic dependency building # %.d: %.c $(QUIET_MM)$(CC) $(CFLAGS) -MM $< | sed -e 's/\($*\)\.o:/\1.o $@:/g' >$@ # # Define a pattern rule for silent object building # %.o: %.c $(QUIET_CC)$(CC) -o $*.o -c $(CFLAGS) $< EXTLIBS = git/libgit.a git/xdiff/lib.a -lz -lcrypto OBJECTS = OBJECTS += cache.o OBJECTS += cgit.o OBJECTS += cmd.o OBJECTS += configfile.o OBJECTS += html.o OBJECTS += parsing.o OBJECTS += scan-tree.o OBJECTS += shared.o OBJECTS += ui-atom.o OBJECTS += ui-blob.o OBJECTS += ui-clone.o OBJECTS += ui-commit.o OBJECTS += ui-diff.o OBJECTS += ui-log.o OBJECTS += ui-patch.o OBJECTS += ui-plain.o OBJECTS += ui-refs.o OBJECTS += ui-repolist.o OBJECTS += ui-shared.o OBJECTS += ui-snapshot.o OBJECTS += ui-summary.o OBJECTS += ui-tag.o OBJECTS += ui-tree.o ifdef NEEDS_LIBICONV EXTLIBS += -liconv endif .PHONY: all libgit test install uninstall clean force-version get-git all: cgit VERSION: force-version @./gen-version.sh "$(CGIT_VERSION)" -include VERSION CFLAGS += -g -Wall -Igit CFLAGS += -DSHA1_HEADER='$(SHA1_HEADER)' CFLAGS += -DCGIT_VERSION='"$(CGIT_VERSION)"' CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"' CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"' CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"' ifdef NO_ICONV CFLAGS += -DNO_ICONV endif cgit: $(OBJECTS) libgit $(QUIET_CC)$(CC) $(CFLAGS) $(LDFLAGS) -o cgit $(OBJECTS) $(EXTLIBS) cgit.o: VERSION -include $(OBJECTS:.o=.d) libgit: $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) libgit.a $(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) xdiff/lib.a test: all $(QUIET_SUBDIR0)tests $(QUIET_SUBDIR1) all install: all mkdir -p $(DESTDIR)$(CGIT_SCRIPT_PATH) install cgit $(DESTDIR)$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) install cgit.css $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.css install cgit.png $(DESTDIR)$(CGIT_SCRIPT_PATH)/cgit.png uninstall: rm -f $(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) rm -f $(CGIT_SCRIPT_PATH)/cgit.css rm -f $(CGIT_SCRIPT_PATH)/cgit.png clean: rm -f cgit VERSION *.o *.d get-git: curl $(GIT_URL) | tar -xj && rm -rf git && mv git-$(GIT_VER) git @@ -227,213 +227,213 @@ static int process_slot(struct cache_slot *slot) err = open_slot(slot); if (!err && slot->match) { if (is_expired(slot)) { if (!lock_slot(slot)) { /* If the cachefile has been replaced between * `open_slot` and `lock_slot`, we'll just * serve the stale content from the original * cachefile. This way we avoid pruning the * newly generated slot. The same code-path * is chosen if fill_slot() fails for some * reason. * * TODO? check if the new slot contains the * same key as the old one, since we would * prefer to serve the newest content. * This will require us to open yet another * file-descriptor and read and compare the * key from the new file, so for now we're * lazy and just ignore the new file. */ if (is_modified(slot) || fill_slot(slot)) { unlock_slot(slot, 0); close_lock(slot); } else { close_slot(slot); unlock_slot(slot, 1); slot->cache_fd = slot->lock_fd; } } } if ((err = print_slot(slot)) != 0) { cache_log("[cgit] error printing cache %s: %s (%d)\n", slot->cache_name, strerror(err), err); } close_slot(slot); return err; } /* If the cache slot does not exist (or its key doesn't match the * current key), lets try to create a new cache slot for this * request. If this fails (for whatever reason), lets just generate * the content without caching it and fool the caller to belive * everything worked out (but print a warning on stdout). */ close_slot(slot); if ((err = lock_slot(slot)) != 0) { cache_log("[cgit] Unable to lock slot %s: %s (%d)\n", slot->lock_name, strerror(err), err); slot->fn(slot->cbdata); return 0; } if ((err = fill_slot(slot)) != 0) { cache_log("[cgit] Unable to fill slot %s: %s (%d)\n", slot->lock_name, strerror(err), err); unlock_slot(slot, 0); close_lock(slot); slot->fn(slot->cbdata); return 0; } // We've got a valid cache slot in the lock file, which // is about to replace the old cache slot. But if we // release the lockfile and then try to open the new cache // slot, we might get a race condition with a concurrent // writer for the same cache slot (with a different key). // Lets avoid such a race by just printing the content of // the lock file. slot->cache_fd = slot->lock_fd; unlock_slot(slot, 1); if ((err = print_slot(slot)) != 0) { cache_log("[cgit] error printing cache %s: %s (%d)\n", slot->cache_name, strerror(err), err); } close_slot(slot); return err; } /* Print cached content to stdout, generate the content if necessary. */ int cache_process(int size, const char *path, const char *key, int ttl, cache_fill_fn fn, void *cbdata) { unsigned long hash; int len, i; char filename[1024]; char lockname[1024 + 5]; /* 5 = ".lock" */ struct cache_slot slot; /* If the cache is disabled, just generate the content */ if (size <= 0) { fn(cbdata); return 0; } /* Verify input, calculate filenames */ if (!path) { cache_log("[cgit] Cache path not specified, caching is disabled\n"); fn(cbdata); return 0; } len = strlen(path); if (len > sizeof(filename) - 10) { /* 10 = "/01234567\0" */ cache_log("[cgit] Cache path too long, caching is disabled: %s\n", path); fn(cbdata); return 0; } if (!key) key = ""; hash = hash_str(key) % size; strcpy(filename, path); if (filename[len - 1] != '/') filename[len++] = '/'; for(i = 0; i < 8; i++) { sprintf(filename + len++, "%x", (unsigned char)(hash & 0xf)); hash >>= 4; } filename[len] = '\0'; strcpy(lockname, filename); strcpy(lockname + len, ".lock"); slot.fn = fn; slot.cbdata = cbdata; slot.ttl = ttl; slot.cache_name = filename; slot.lock_name = lockname; slot.key = key; slot.keylen = strlen(key); return process_slot(&slot); } /* Return a strftime formatted date/time * NB: the result from this function is to shared memory */ char *sprintftime(const char *format, time_t time) { static char buf[64]; struct tm *tm; if (!time) return NULL; tm = gmtime(&time); strftime(buf, sizeof(buf)-1, format, tm); return buf; } int cache_ls(const char *path) { DIR *dir; struct dirent *ent; int err = 0; struct cache_slot slot; char fullname[1024]; char *name; if (!path) { cache_log("[cgit] cache path not specified\n"); return -1; } if (strlen(path) > 1024 - 10) { cache_log("[cgit] cache path too long: %s\n", path); return -1; } dir = opendir(path); if (!dir) { err = errno; cache_log("[cgit] unable to open path %s: %s (%d)\n", path, strerror(err), err); return err; } strcpy(fullname, path); name = fullname + strlen(path); if (*(name - 1) != '/') { *name++ = '/'; *name = '\0'; } slot.cache_name = fullname; while((ent = readdir(dir)) != NULL) { if (strlen(ent->d_name) != 8) continue; strcpy(name, ent->d_name); if ((err = open_slot(&slot)) != 0) { cache_log("[cgit] unable to open path %s: %s (%d)\n", fullname, strerror(err), err); continue; } - printf("%s %s %10zd %s\n", + printf("%s %s %10"PRIuMAX" %s\n", name, sprintftime("%Y-%m-%d %H:%M:%S", slot.cache_st.st_mtime), - slot.cache_st.st_size, + (uintmax_t)slot.cache_st.st_size, slot.buf); close_slot(&slot); } closedir(dir); return 0; } /* Print a message to stdout */ void cache_log(const char *format, ...) { va_list args; va_start(args, format); vfprintf(stderr, format, args); va_end(args); } diff --git a/git b/git -Subproject 97a7a82f199f165f85fe39a3c318b18c621e633 +Subproject 031e6c898f61db1ae0c0be641eac6532c1000d5 diff --git a/tests/setup.sh b/tests/setup.sh index 1457dd5..95acb54 100755 --- a/tests/setup.sh +++ b/tests/setup.sh @@ -1,127 +1,129 @@ # This file should be sourced by all test-scripts # # Main functions: # prepare_tests(description) - setup for testing, i.e. create repos+config # run_test(description, script) - run one test, i.e. eval script # # Helper functions # cgit_query(querystring) - call cgit with the specified querystring # cgit_url(url) - call cgit with the specified virtual url # # Example script: # # . setup.sh # prepare_tests "html validation" # run_test 'repo index' 'cgit_url "/" | tidy -e' # run_test 'repo summary' 'cgit_url "/foo" | tidy -e' mkrepo() { name=$1 count=$2 dir=$PWD test -d $name && return printf "Creating testrepo %s\n" $name mkdir -p $name cd $name git init - for ((n=1; n<=count; n++)) + n=1 + while test $n -le $count do echo $n >file-$n git add file-$n git commit -m "commit $n" + n=$(expr $n + 1) done if test "$3" = "testplus" then echo "hello" >a+b git add a+b git commit -m "add a+b" git branch "1+2" fi cd $dir } setup_repos() { rm -rf trash/cache mkdir -p trash/cache mkrepo trash/repos/foo 5 >/dev/null mkrepo trash/repos/bar 50 >/dev/null mkrepo trash/repos/foo+bar 10 testplus >/dev/null cat >trash/cgitrc <<EOF virtual-root=/ cache-root=$PWD/trash/cache cache-size=1021 snapshots=tar.gz tar.bz zip enable-log-filecount=1 enable-log-linecount=1 summary-log=5 summary-branches=5 summary-tags=5 repo.url=foo repo.path=$PWD/trash/repos/foo/.git # Do not specify a description for this repo, as it then will be assigned # the constant value "[no description]" (which actually used to cause a # segfault). repo.url=bar repo.path=$PWD/trash/repos/bar/.git repo.desc=the bar repo repo.url=foo+bar repo.path=$PWD/trash/repos/foo+bar/.git repo.desc=the foo+bar repo EOF } prepare_tests() { setup_repos rm -f test-output.log 2>/dev/null test_count=0 test_failed=0 echo "[$0]" "$@" >test-output.log echo "$@" "($0)" } tests_done() { printf "\n" if test $test_failed -gt 0 then printf "test: *** %s failure(s), logfile=%s\n" \ $test_failed "$(pwd)/test-output.log" false fi } run_test() { desc=$1 script=$2 - ((test_count++)) + test_count=$(expr $test_count + 1) printf "\ntest %d: name='%s'\n" $test_count "$desc" >>test-output.log printf "test %d: eval='%s'\n" $test_count "$2" >>test-output.log eval "$2" >>test-output.log 2>>test-output.log res=$? printf "test %d: exitcode=%d\n" $test_count $res >>test-output.log if test $res = 0 then printf " %2d) %-60s [ok]\n" $test_count "$desc" else ((test_failed++)) printf " %2d) %-60s [failed]\n" $test_count "$desc" fi } cgit_query() { CGIT_CONFIG="$PWD/trash/cgitrc" QUERY_STRING="$1" "$PWD/../cgit" } cgit_url() { CGIT_CONFIG="$PWD/trash/cgitrc" QUERY_STRING="url=$1" "$PWD/../cgit" } @@ -1,79 +1,79 @@ /* ui-plain.c: functions for output of plain blobs by path * * Copyright (C) 2008 Lars Hjemli * * Licensed under GNU General Public License v2 * (see COPYING for full license text) */ #include "cgit.h" #include "html.h" #include "ui-shared.h" char *curr_rev; char *match_path; int match; static void print_object(const unsigned char *sha1, const char *path) { enum object_type type; char *buf; - size_t size; + unsigned long size; type = sha1_object_info(sha1, &size); if (type == OBJ_BAD) { html_status(404, "Not found", 0); return; } buf = read_sha1_file(sha1, &type, &size); if (!buf) { html_status(404, "Not found", 0); return; } ctx.page.mimetype = "text/plain"; ctx.page.filename = fmt("%s", path); ctx.page.size = size; cgit_print_http_headers(&ctx); html_raw(buf, size); match = 1; } static int walk_tree(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *cbdata) { if (S_ISDIR(mode)) return READ_TREE_RECURSIVE; if (S_ISREG(mode)) print_object(sha1, pathname); return 0; } void cgit_print_plain(struct cgit_context *ctx) { const char *rev = ctx->qry.sha1; unsigned char sha1[20]; struct commit *commit; const char *paths[] = {ctx->qry.path, NULL}; if (!rev) rev = ctx->qry.head; curr_rev = xstrdup(rev); if (get_sha1(rev, sha1)) { html_status(404, "Not found", 0); return; } commit = lookup_commit_reference(sha1); if (!commit || parse_commit(commit)) { html_status(404, "Not found", 0); return; } match_path = ctx->qry.path; read_tree_recursive(commit->tree, NULL, 0, 0, paths, walk_tree, NULL); if (!match) html_status(404, "Not found", 0); } |