blob: f76c641e355bda747dc74e9bfcaa727de284eaaf [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;
Jason A. Donenfeld6a8d6d42020-03-12 20:52:35 -060059 read_tree_recursive(the_repository,
60 repo_get_commit_tree(the_repository, lookup_commit_reference(the_repository, &oid)),
61 "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
Christian Hesse3d33b462017-07-24 17:22:52 +020062
63done:
64 free(path_items.match);
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020065 return walk_tree_ctx.found_path;
Jason A. Donenfeldcd4c77d2013-05-25 16:32:37 +020066}
67
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020068int cgit_print_file(char *path, const char *head, int file_only)
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020069{
Christian Hesse6e4b7b62016-09-29 21:38:49 +020070 struct object_id oid;
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020071 enum object_type type;
72 char *buf;
73 unsigned long size;
74 struct commit *commit;
John Keepingc1633c62013-03-02 12:32:11 +000075 struct pathspec_item path_items = {
76 .match = path,
77 .len = strlen(path)
78 };
79 struct pathspec paths = {
80 .nr = 1,
81 .items = &path_items
82 };
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010083 struct walk_tree_context walk_tree_ctx = {
84 .match_path = path,
Christian Hessec330a2e2016-10-11 08:55:34 +020085 .matched_oid = &oid,
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +020086 .found_path = 0,
87 .file_only = file_only
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010088 };
89
Christian Hesse6e4b7b62016-09-29 21:38:49 +020090 if (get_oid(head, &oid))
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020091 return -1;
Christian Hesse255b78f2018-06-04 18:49:28 +020092 type = oid_object_info(the_repository, &oid, &size);
John Keeping509488d2015-10-08 23:23:58 +010093 if (type == OBJ_COMMIT) {
Christian Hesse2c9f56f2018-08-28 18:27:00 +020094 commit = lookup_commit_reference(the_repository, &oid);
Jason A. Donenfeld6a8d6d42020-03-12 20:52:35 -060095 read_tree_recursive(the_repository,
96 repo_get_commit_tree(the_repository, commit),
97 "", 0, 0, &paths, walk_tree,
98 &walk_tree_ctx);
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010099 if (!walk_tree_ctx.found_path)
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +0200100 return -1;
Christian Hesse255b78f2018-06-04 18:49:28 +0200101 type = oid_object_info(the_repository, &oid, &size);
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +0200102 }
103 if (type == OBJ_BAD)
104 return -1;
Christian Hesse255b78f2018-06-04 18:49:28 +0200105 buf = read_object_file(&oid, &type, &size);
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +0200106 if (!buf)
107 return -1;
108 buf[size] = '\0';
Mark Lodatod187b982010-09-04 14:18:16 -0400109 html_raw(buf, size);
Christian Hesse30802122015-10-10 16:56:24 +0200110 free(buf);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200111 return 0;
112}
113
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +0200114void cgit_print_blob(const char *hex, char *path, const char *head, int file_only)
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200115{
Christian Hesse6e4b7b62016-09-29 21:38:49 +0200116 struct object_id oid;
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200117 enum object_type type;
Lars Hjemli596eb8f2009-07-25 11:51:19 +0200118 char *buf;
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200119 unsigned long size;
Michael Krelin01d2dce2008-06-24 23:33:24 +0200120 struct commit *commit;
John Keepingc1633c62013-03-02 12:32:11 +0000121 struct pathspec_item path_items = {
122 .match = path,
John Keeping1c32e002013-04-07 15:06:23 +0100123 .len = path ? strlen(path) : 0
John Keepingc1633c62013-03-02 12:32:11 +0000124 };
125 struct pathspec paths = {
126 .nr = 1,
127 .items = &path_items
128 };
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +0100129 struct walk_tree_context walk_tree_ctx = {
130 .match_path = path,
Christian Hessec330a2e2016-10-11 08:55:34 +0200131 .matched_oid = &oid,
Jason A. Donenfelddcbc0432013-05-26 15:20:02 +0200132 .found_path = 0,
133 .file_only = file_only
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +0100134 };
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200135
Michael Krelin01d2dce2008-06-24 23:33:24 +0200136 if (hex) {
Christian Hesse6e4b7b62016-09-29 21:38:49 +0200137 if (get_oid_hex(hex, &oid)) {
John Keeping9a062112015-08-14 12:47:06 +0100138 cgit_print_error_page(400, "Bad request",
139 "Bad hex value: %s", hex);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200140 return;
141 }
142 } else {
Christian Hesse6e4b7b62016-09-29 21:38:49 +0200143 if (get_oid(head, &oid)) {
John Keeping9a062112015-08-14 12:47:06 +0100144 cgit_print_error_page(404, "Not found",
145 "Bad ref: %s", head);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200146 return;
147 }
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200148 }
149
Christian Hesse255b78f2018-06-04 18:49:28 +0200150 type = oid_object_info(the_repository, &oid, &size);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200151
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -0500152 if ((!hex) && type == OBJ_COMMIT && path) {
Christian Hesse2c9f56f2018-08-28 18:27:00 +0200153 commit = lookup_commit_reference(the_repository, &oid);
Jason A. Donenfeld6a8d6d42020-03-12 20:52:35 -0600154 read_tree_recursive(the_repository,
155 repo_get_commit_tree(the_repository, commit),
156 "", 0, 0, &paths, walk_tree,
157 &walk_tree_ctx);
Christian Hesse255b78f2018-06-04 18:49:28 +0200158 type = oid_object_info(the_repository, &oid, &size);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200159 }
160
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200161 if (type == OBJ_BAD) {
John Keeping9a062112015-08-14 12:47:06 +0100162 cgit_print_error_page(404, "Not found",
163 "Bad object name: %s", hex);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200164 return;
165 }
166
Christian Hesse255b78f2018-06-04 18:49:28 +0200167 buf = read_object_file(&oid, &type, &size);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200168 if (!buf) {
John Keeping9a062112015-08-14 12:47:06 +0100169 cgit_print_error_page(500, "Internal server error",
170 "Error reading object %s", hex);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200171 return;
172 }
173
174 buf[size] = '\0';
Jason A. Donenfeld92996ac2016-01-14 14:31:53 +0100175 if (buffer_is_binary(buf, size))
176 ctx.page.mimetype = "application/octet-stream";
177 else
178 ctx.page.mimetype = "text/plain";
Lars Hjemlif3c1a182008-03-24 00:51:19 +0100179 ctx.page.filename = path;
Jason A. Donenfeld9ca25662016-01-14 14:43:43 +0100180
181 html("X-Content-Type-Options: nosniff\n");
182 html("Content-Security-Policy: default-src 'none'\n");
Lukas Fleischerf60ffa12014-01-15 21:53:15 +0100183 cgit_print_http_headers();
Mark Lodatod187b982010-09-04 14:18:16 -0400184 html_raw(buf, size);
Christian Hesse7320bfa2015-10-10 16:56:23 +0200185 free(buf);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200186}