summaryrefslogtreecommitdiffstatshomepage
path: root/ui-patch.c
Commit message (Expand)AuthorAge
* ui-patch: replace 'unsigned char sha1[20]' with 'struct object_id oid'Christian Hesse2016-10-04
* git: update to v2.7.0Christian Hesse2016-01-13
* patch: use cgit_print_error_page() for HTTP status codesJohn Keeping2015-08-14
* ui-patch: make sure to send http headersChristian Hesse2015-08-14
* ui-patch: match git-format-patch(1) outputJohn Keeping2014-12-28
* ui-patch: Flush stdout after outputting dataJohn Keeping2014-06-28
* Switch to exclusively using global ctxLukas Fleischer2014-01-17
* Update copyright informationLukas Fleischer2014-01-08
* ui-patch.c: Add additional newline after each patchLukas Fleischer2013-08-26
* ui-patch.c: Fix signature delimiterLukas Fleischer2013-08-26
* ui-patch.c: Fix formatting for merge commitsLukas Fleischer2013-08-22
* ui-patch: Rename variablesLukas Fleischer2013-08-20
* Allow for creating patch seriesLukas Fleischer2013-08-20
* ui-patch.c: Use log_tree_commit() to generate diffsLukas Fleischer2013-08-20
* Extract filepair_cb from ui-patch.cLukas Fleischer2013-08-16
* Convert cgit_print_error to a variadic functionJohn Keeping2013-04-08
* Always #include corresponding .h in .c filesJohn Keeping2013-04-08
* ui-patch: use cgit_version not CGIT_VERSIONJohn Keeping2013-03-20
* Format git diff headers correctly when adding or removing files.Michael Halstead2012-11-15
* Add URL parameter 'ignorews' for optionally ignoring whitespace in diffsJohan Herland2010-07-18
* Add URL parameter 'context' for changing the number of context lines in diffsJohan Herland2010-06-19
* ui-patch: Apply path limit to generated patchJohan Herland2010-06-19
* Introduce noplainemail option to hide email adresses from spambotsMartin Szulecki2009-08-08
* Handle binary files in diffsLars Hjemli2009-01-31
* ui-patch: whitespace changes in the patch generation codeTomas Carnecky2008-12-30
* Added `local-time` option to cgitrcStefan Naewe2008-08-01
* Merge branch 'lh/cleanup'Lars Hjemli2008-04-08
|\
| * Add ui-shared.hLars Hjemli2008-03-24
| * Remove obsolete cacheitem parameter to ui-functionsLars Hjemli2008-03-24
| * Add struct cgit_page to cgit_contextLars Hjemli2008-03-24
| * Introduce html.hLars Hjemli2008-03-18
| * Introduce struct cgit_contextLars Hjemli2008-02-16
* | Fix segfault in patch view for root commitLars Hjemli2008-03-17
|/
* Check for NULL-subject in patch viewLars Hjemli2008-01-10
* Add plain patch viewLars Hjemli2007-12-11
.Number.Integer.Long */
/* ui-blob.c: show blob content
 *
 * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
 *
 * Licensed under GNU General Public License v2
 *   (see COPYING for full license text)
 */

#include "cgit.h"
#include "ui-blob.h"
#include "html.h"
#include "ui-shared.h"

struct walk_tree_context {
	const char *match_path;
	struct object_id *matched_oid;
	unsigned int found_path:1;
	unsigned int file_only:1;
};

static int walk_tree(const struct object_id *oid, struct strbuf *base,
		const char *pathname, unsigned mode, int stage, void *cbdata)
{
	struct walk_tree_context *walk_tree_ctx = cbdata;

	if (walk_tree_ctx->file_only && !S_ISREG(mode))
		return READ_TREE_RECURSIVE;
	if (strncmp(base->buf, walk_tree_ctx->match_path, base->len)
		|| strcmp(walk_tree_ctx->match_path + base->len, pathname))
		return READ_TREE_RECURSIVE;
	oidcpy(walk_tree_ctx->matched_oid, oid);
	walk_tree_ctx->found_path = 1;
	return 0;
}

int cgit_ref_path_exists(const char *path, const char *ref, int file_only)
{
	struct object_id oid;
	unsigned long size;
	struct pathspec_item path_items = {
		.match = xstrdup(path),
		.len = strlen(path)
	};
	struct pathspec paths = {
		.nr = 1,
		.items = &path_items
	};
	struct walk_tree_context walk_tree_ctx = {
		.match_path = path,
		.matched_oid = &oid,
		.found_path = 0,
		.file_only = file_only
	};

	if (get_oid(ref, &oid))
		goto done;
	if (oid_object_info(the_repository, &oid, &size) != OBJ_COMMIT)
		goto done;
	read_tree_recursive(lookup_commit_reference(&oid)->maybe_tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);

done:
	free(path_items.match);
	return walk_tree_ctx.found_path;
}

int cgit_print_file(char *path, const char *head, int file_only)
{
	struct object_id oid;
	enum object_type type;
	char *buf;
	unsigned long size;
	struct commit *commit;
	struct pathspec_item path_items = {
		.match = path,
		.len = strlen(path)
	};
	struct pathspec paths = {
		.nr = 1,
		.items = &path_items
	};
	struct walk_tree_context walk_tree_ctx = {
		.match_path = path,
		.matched_oid = &oid,
		.found_path = 0,
		.file_only = file_only
	};

	if (get_oid(head, &oid))
		return -1;
	type = oid_object_info(the_repository, &oid, &size);
	if (type == OBJ_COMMIT) {
		commit = lookup_commit_reference(&oid);
		read_tree_recursive(commit->maybe_tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
		if (!walk_tree_ctx.found_path)
			return -1;
		type = oid_object_info(the_repository, &oid, &size);
	}
	if (type == OBJ_BAD)
		return -1;
	buf = read_object_file(&oid, &type, &size);
	if (!buf)
		return -1;
	buf[size] = '\0';
	html_raw(buf, size);
	free(buf);
	return 0;
}

void cgit_print_blob(const char *hex, char *path, const char *head, int file_only)
{
	struct object_id oid;
	enum object_type type;
	char *buf;
	unsigned long size;
	struct commit *commit;
	struct pathspec_item path_items = {
		.match = path,
		.len = path ? strlen(path) : 0
	};
	struct pathspec paths = {
		.nr = 1,
		.items = &path_items
	};
	struct walk_tree_context walk_tree_ctx = {
		.match_path = path,
		.matched_oid = &oid,
		.found_path = 0,
		.file_only = file_only
	};

	if (hex) {
		if (get_oid_hex(hex, &oid)) {
			cgit_print_error_page(400, "Bad request",
					"Bad hex value: %s", hex);
			return;
		}
	} else {
		if (get_oid(head, &oid)) {
			cgit_print_error_page(404, "Not found",
					"Bad ref: %s", head);
			return;
		}
	}

	type = oid_object_info(the_repository, &oid, &size);

	if ((!hex) && type == OBJ_COMMIT && path) {
		commit = lookup_commit_reference(&oid);
		read_tree_recursive(commit->maybe_tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
		type = oid_object_info(the_repository, &oid, &size);
	}

	if (type == OBJ_BAD) {
		cgit_print_error_page(404, "Not found",
				"Bad object name: %s", hex);
		return;
	}

	buf = read_object_file(&oid, &type, &size);
	if (!buf) {
		cgit_print_error_page(500, "Internal server error",
				"Error reading object %s", hex);
		return;
	}

	buf[size] = '\0';
	if (buffer_is_binary(buf, size))
		ctx.page.mimetype = "application/octet-stream";
	else
		ctx.page.mimetype = "text/plain";
	ctx.page.filename = path;

	html("X-Content-Type-Options: nosniff\n");
	html("Content-Security-Policy: default-src 'none'\n");
	cgit_print_http_headers();
	html_raw(buf, size);
	free(buf);
}