summaryrefslogtreecommitdiffstatshomepage
path: root/ui-clone.c
blob: 81e7a4e5b8126fb577dc4e1502cdb14744ff3469 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
/* ui-clone.c: functions for http cloning, based on
 * git's http-backend.c by Shawn O. Pearce
 *
 * 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"

static int print_ref_info(const char *refname, const unsigned char *sha1,
                          int flags, void *cb_data)
{
	struct object *obj;

	if (!(obj = parse_object(sha1)))
		return 0;

	if (!strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/"))
		htmlf("%s\t%s\n", sha1_to_hex(sha1), refname);
	else if (!prefixcmp(refname, "refs/tags") && obj->type == OBJ_TAG) {
		if (!(obj = deref_tag(obj, refname, 0)))
			return 0;
		htmlf("%s\t%s\n", sha1_to_hex(sha1), refname);
		htmlf("%s\t%s^{}\n", sha1_to_hex(obj->sha1), refname);
	}
	return 0;
}

static void print_pack_info(struct cgit_context *ctx)
{
	struct packed_git *pack;
	int ofs;

	ctx->page.mimetype = "text/plain";
	ctx->page.filename = "objects/info/packs";
	cgit_print_http_headers(ctx);
	ofs = strlen(ctx->repo->path) + strlen("/objects/pack/");
	prepare_packed_git();
	for (pack = packed_git; pack; pack = pack->next)
		if (pack->pack_local)
			htmlf("P %s\n", pack->pack_name + ofs);
}

static void send_file(struct cgit_context *ctx, char *path)
{
	struct stat st;

	if (stat(path, &st)) {
		switch (errno) {
		case ENOENT:
			html_status(404, "Not found", 0);
			break;
		case EACCES:
			html_status(403, "Forbidden", 0);
			break;
		default:
			html_status(400, "Bad request", 0);
		}
		return;
	}
	ctx->page.mimetype = "application/octet-stream";
	ctx->page.filename = path;
	if (prefixcmp(ctx->repo->path, path))
		ctx->page.filename += strlen(ctx->repo->path) + 1;
	cgit_print_http_headers(ctx);
	html_include(path);
}

void cgit_clone_info(struct cgit_context *ctx)
{
	if (!ctx->qry.path || strcmp(ctx->qry.path, "refs"))
		return;

	ctx->page.mimetype = "text/plain";
	ctx->page.filename = "info/refs";
	cgit_print_http_headers(ctx);
	for_each_ref(print_ref_info, ctx);
}

void cgit_clone_objects(struct cgit_context *ctx)
{
	if (!ctx->qry.path) {
		html_status(400, "Bad request", 0);
		return;
	}

	if (!strcmp(ctx->qry.path, "info/packs")) {
		print_pack_info(ctx);
		return;
	}

	send_file(ctx, git_path("objects/%s", ctx->qry.path));
}

void cgit_clone_head(struct cgit_context *ctx)
{
	send_file(ctx, git_path("%s", "HEAD"));
}
an class="p">)) ctx.page.mimetype = "application/octet-stream"; else ctx.page.mimetype = "text/plain"; } ctx.page.filename = fmt("%s", path); ctx.page.size = size; ctx.page.etag = sha1_to_hex(sha1); cgit_print_http_headers(&ctx); html_raw(buf, size); match = 1; if (freemime) free(ctx.page.mimetype); } static char *buildpath(const char *base, int baselen, const char *path) { if (path[0]) return fmt("%.*s%s/", baselen, base, path); else return fmt("%.*s/", baselen, base); } static void print_dir(const unsigned char *sha1, const char *base, int baselen, const char *path) { char *fullpath, *slash; size_t len; fullpath = buildpath(base, baselen, path); slash = (fullpath[0] == '/' ? "" : "/"); ctx.page.etag = sha1_to_hex(sha1); cgit_print_http_headers(&ctx); htmlf("<html><head><title>%s", slash); html_txt(fullpath); htmlf("</title></head>\n<body>\n<h2>%s", slash); html_txt(fullpath); html("</h2>\n<ul>\n"); len = strlen(fullpath); if (len > 1) { fullpath[len - 1] = 0; slash = strrchr(fullpath, '/'); if (slash) *(slash + 1) = 0; else fullpath = NULL; html("<li>"); cgit_plain_link("../", NULL, NULL, ctx.qry.head, ctx.qry.sha1, fullpath); html("</li>\n"); } match = 2; } static void print_dir_entry(const unsigned char *sha1, const char *base, int baselen, const char *path, unsigned mode) { char *fullpath; fullpath = buildpath(base, baselen, path); if (!S_ISDIR(mode) && !S_ISGITLINK(mode)) fullpath[strlen(fullpath) - 1] = 0; html(" <li>"); if (S_ISGITLINK(mode)) { cgit_submodule_link(NULL, fullpath, sha1_to_hex(sha1)); } else cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, fullpath); html("</li>\n"); match = 2; } static void print_dir_tail(void) { html(" </ul>\n</body></html>\n"); } static int walk_tree(const unsigned char *sha1, const char *base, int baselen, const char *pathname, unsigned mode, int stage, void *cbdata) { if (baselen == match_baselen) { if (S_ISREG(mode)) print_object(sha1, pathname); else if (S_ISDIR(mode)) { print_dir(sha1, base, baselen, pathname); return READ_TREE_RECURSIVE; } } else if (baselen > match_baselen) print_dir_entry(sha1, base, baselen, pathname, mode); else if (S_ISDIR(mode)) return READ_TREE_RECURSIVE; return 0; } static int basedir_len(const char *path) { char *p = strrchr(path, '/'); if (p) return p - path + 1; 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; 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; } if (!paths[0]) { paths[0] = ""; match_baselen = -1; print_dir(commit->tree->object.sha1, "", 0, ""); } else match_baselen = basedir_len(paths[0]); read_tree_recursive(commit->tree, "", 0, 0, paths, walk_tree, NULL); if (!match) html_status(404, "Not found", 0); else if (match == 2) print_dir_tail(); }