blob: 7b6da2a491b83f08642ba1f32bcadb5d5d0224df [file] [log] [blame]
Lars Hjemlib1f9b9c2008-02-23 22:45:33 +01001/* ui-blob.c: show blob content
2 *
Lukas Fleischerf7f26f82014-01-08 15:10:49 +01003 * Copyright (C) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
Lars Hjemlib1f9b9c2008-02-23 22:45:33 +01004 *
5 * Licensed under GNU General Public License v2
6 * (see COPYING for full license text)
7 */
8
Lars Hjemlica8eb8f2007-05-09 00:48:09 +02009#include "cgit.h"
John Keeping8f208792013-04-06 11:37:59 +010010#include "ui-blob.h"
Lars Hjemlib1f9b9c2008-02-23 22:45:33 +010011#include "html.h"
Lars Hjemlia4d1ca12008-03-24 16:50:57 +010012#include "ui-shared.h"
Lars Hjemlica8eb8f2007-05-09 00:48:09 +020013
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010014struct walk_tree_context {
Jason A. Donenfeldcd4c77d2013-05-25 16:32:37 +020015 const char *match_path;
Christian Hessec330a2e2016-10-11 08:55:34 +020016 struct object_id *matched_oid;
John Keeping12d3d4c2015-03-08 16:32:17 +000017 unsigned int found_path:1;
18 unsigned int file_only:1;
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010019};
Michael Krelin01d2dce2008-06-24 23:33:24 +020020
Christian Hesse255b78f2018-06-04 18:49:28 +020021static int walk_tree(const struct object_id *oid, struct strbuf *base,
Christian Hesse7358f632015-02-07 14:18:28 +010022 const char *pathname, unsigned mode, int stage, void *cbdata)
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010023{
24 struct walk_tree_context *walk_tree_ctx = cbdata;
25
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020026 if (walk_tree_ctx->file_only && !S_ISREG(mode))
27 return READ_TREE_RECURSIVE;
Christian Hesse7358f632015-02-07 14:18:28 +010028 if (strncmp(base->buf, walk_tree_ctx->match_path, base->len)
29 || strcmp(walk_tree_ctx->match_path + base->len, pathname))
Michael Krelin01d2dce2008-06-24 23:33:24 +020030 return READ_TREE_RECURSIVE;
Christian Hesse255b78f2018-06-04 18:49:28 +020031 oidcpy(walk_tree_ctx->matched_oid, oid);
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010032 walk_tree_ctx->found_path = 1;
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020033 return 0;
34}
35
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020036int cgit_ref_path_exists(const char *path, const char *ref, int file_only)
Jason A. Donenfeldcd4c77d2013-05-25 16:32:37 +020037{
Christian Hesse6e4b7b62016-09-29 21:38:49 +020038 struct object_id oid;
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020039 unsigned long size;
40 struct pathspec_item path_items = {
Christian Hesse3d33b462017-07-24 17:22:52 +020041 .match = xstrdup(path),
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020042 .len = strlen(path)
43 };
44 struct pathspec paths = {
45 .nr = 1,
46 .items = &path_items
47 };
48 struct walk_tree_context walk_tree_ctx = {
49 .match_path = path,
Christian Hessec330a2e2016-10-11 08:55:34 +020050 .matched_oid = &oid,
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020051 .found_path = 0,
52 .file_only = file_only
53 };
Jason A. Donenfeldcd4c77d2013-05-25 16:32:37 +020054
Christian Hesse6e4b7b62016-09-29 21:38:49 +020055 if (get_oid(ref, &oid))
Christian Hesse3d33b462017-07-24 17:22:52 +020056 goto done;
Christian Hesse255b78f2018-06-04 18:49:28 +020057 if (oid_object_info(the_repository, &oid, &size) != OBJ_COMMIT)
Christian Hesse3d33b462017-07-24 17:22:52 +020058 goto done;
Christian Hesse255b78f2018-06-04 18:49:28 +020059 read_tree_recursive(lookup_commit_reference(&oid)->maybe_tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
Christian Hesse3d33b462017-07-24 17:22:52 +020060
61done:
62 free(path_items.match);
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020063 return walk_tree_ctx.found_path;
Jason A. Donenfeldcd4c77d2013-05-25 16:32:37 +020064}
65
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020066int cgit_print_file(char *path, const char *head, int file_only)
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020067{
Christian Hesse6e4b7b62016-09-29 21:38:49 +020068 struct object_id oid;
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020069 enum object_type type;
70 char *buf;
71 unsigned long size;
72 struct commit *commit;
John Keepingc1633c62013-03-02 12:32:11 +000073 struct pathspec_item path_items = {
74 .match = path,
75 .len = strlen(path)
76 };
77 struct pathspec paths = {
78 .nr = 1,
79 .items = &path_items
80 };
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010081 struct walk_tree_context walk_tree_ctx = {
82 .match_path = path,
Christian Hessec330a2e2016-10-11 08:55:34 +020083 .matched_oid = &oid,
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020084 .found_path = 0,
85 .file_only = file_only
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010086 };
87
Christian Hesse6e4b7b62016-09-29 21:38:49 +020088 if (get_oid(head, &oid))
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020089 return -1;
Christian Hesse255b78f2018-06-04 18:49:28 +020090 type = oid_object_info(the_repository, &oid, &size);
John Keeping509488d2015-10-08 23:23:58 +010091 if (type == OBJ_COMMIT) {
Jeff Smith86a6d352017-08-09 19:02:56 -050092 commit = lookup_commit_reference(&oid);
Christian Hesse255b78f2018-06-04 18:49:28 +020093 read_tree_recursive(commit->maybe_tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010094 if (!walk_tree_ctx.found_path)
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020095 return -1;
Christian Hesse255b78f2018-06-04 18:49:28 +020096 type = oid_object_info(the_repository, &oid, &size);
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020097 }
98 if (type == OBJ_BAD)
99 return -1;
Christian Hesse255b78f2018-06-04 18:49:28 +0200100 buf = read_object_file(&oid, &type, &size);
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +0200101 if (!buf)
102 return -1;
103 buf[size] = '\0';
Mark Lodatod187b982010-09-04 14:18:16 -0400104 html_raw(buf, size);
Christian Hesse30802122015-10-10 16:56:24 +0200105 free(buf);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200106 return 0;
107}
108
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +0200109void cgit_print_blob(const char *hex, char *path, const char *head, int file_only)
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200110{
Christian Hesse6e4b7b62016-09-29 21:38:49 +0200111 struct object_id oid;
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200112 enum object_type type;
Lars Hjemli596eb8f2009-07-25 11:51:19 +0200113 char *buf;
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200114 unsigned long size;
Michael Krelin01d2dce2008-06-24 23:33:24 +0200115 struct commit *commit;
John Keepingc1633c62013-03-02 12:32:11 +0000116 struct pathspec_item path_items = {
117 .match = path,
John Keeping1c32e002013-04-07 15:06:23 +0100118 .len = path ? strlen(path) : 0
John Keepingc1633c62013-03-02 12:32:11 +0000119 };
120 struct pathspec paths = {
121 .nr = 1,
122 .items = &path_items
123 };
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +0100124 struct walk_tree_context walk_tree_ctx = {
125 .match_path = path,
Christian Hessec330a2e2016-10-11 08:55:34 +0200126 .matched_oid = &oid,
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +0200127 .found_path = 0,
128 .file_only = file_only
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +0100129 };
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200130
Michael Krelin01d2dce2008-06-24 23:33:24 +0200131 if (hex) {
Christian Hesse6e4b7b62016-09-29 21:38:49 +0200132 if (get_oid_hex(hex, &oid)) {
John Keeping9a062112015-08-14 12:47:06 +0100133 cgit_print_error_page(400, "Bad request",
134 "Bad hex value: %s", hex);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200135 return;
136 }
137 } else {
Christian Hesse6e4b7b62016-09-29 21:38:49 +0200138 if (get_oid(head, &oid)) {
John Keeping9a062112015-08-14 12:47:06 +0100139 cgit_print_error_page(404, "Not found",
140 "Bad ref: %s", head);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200141 return;
142 }
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200143 }
144
Christian Hesse255b78f2018-06-04 18:49:28 +0200145 type = oid_object_info(the_repository, &oid, &size);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200146
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -0500147 if ((!hex) && type == OBJ_COMMIT && path) {
Jeff Smith86a6d352017-08-09 19:02:56 -0500148 commit = lookup_commit_reference(&oid);
Christian Hesse255b78f2018-06-04 18:49:28 +0200149 read_tree_recursive(commit->maybe_tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
150 type = oid_object_info(the_repository, &oid, &size);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200151 }
152
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200153 if (type == OBJ_BAD) {
John Keeping9a062112015-08-14 12:47:06 +0100154 cgit_print_error_page(404, "Not found",
155 "Bad object name: %s", hex);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200156 return;
157 }
158
Christian Hesse255b78f2018-06-04 18:49:28 +0200159 buf = read_object_file(&oid, &type, &size);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200160 if (!buf) {
John Keeping9a062112015-08-14 12:47:06 +0100161 cgit_print_error_page(500, "Internal server error",
162 "Error reading object %s", hex);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200163 return;
164 }
165
166 buf[size] = '\0';
Jason A. Donenfeld92996ac2016-01-14 14:31:53 +0100167 if (buffer_is_binary(buf, size))
168 ctx.page.mimetype = "application/octet-stream";
169 else
170 ctx.page.mimetype = "text/plain";
Lars Hjemlif3c1a182008-03-24 00:51:19 +0100171 ctx.page.filename = path;
Jason A. Donenfeld9ca25662016-01-14 14:43:43 +0100172
173 html("X-Content-Type-Options: nosniff\n");
174 html("Content-Security-Policy: default-src 'none'\n");
Lukas Fleischerf60ffa12014-01-15 21:53:15 +0100175 cgit_print_http_headers();
Mark Lodatod187b982010-09-04 14:18:16 -0400176 html_raw(buf, size);
Christian Hesse7320bfa2015-10-10 16:56:23 +0200177 free(buf);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200178}