diff options
Diffstat (limited to 'third_party/cgit/ui-blob.c')
-rw-r--r-- | third_party/cgit/ui-blob.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/third_party/cgit/ui-blob.c b/third_party/cgit/ui-blob.c new file mode 100644 index 000000000000..08f94ee97eb3 --- /dev/null +++ b/third_party/cgit/ui-blob.c @@ -0,0 +1,182 @@ +/* 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, 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 (repo_get_oid(the_repository, ref, &oid)) + goto done; + if (oid_object_info(the_repository, &oid, &size) != OBJ_COMMIT) + goto done; + read_tree(the_repository, + repo_get_commit_tree(the_repository, lookup_commit_reference(the_repository, &oid)), + &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 (repo_get_oid(the_repository, head, &oid)) + return -1; + type = oid_object_info(the_repository, &oid, &size); + if (type == OBJ_COMMIT) { + commit = lookup_commit_reference(the_repository, &oid); + read_tree(the_repository, repo_get_commit_tree(the_repository, commit), + &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 = repo_read_object_file(the_repository, &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 (repo_get_oid(the_repository, 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(the_repository, &oid); + read_tree(the_repository, repo_get_commit_tree(the_repository, commit), + &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 = repo_read_object_file(the_repository, &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); +} |