blob: 1da43c81519927f99b7f67a8c08d7df0eee34359 [file] [log] [blame]
Lars Hjemlib1f9b9c2008-02-23 22:45:33 +01001/* ui-blob.c: show blob content
2 *
3 * Copyright (C) 2008 Lars Hjemli
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +02004 * Copyright (C) 2010 Jason A. Donenfeld <Jason@zx2c4.com>
Lars Hjemlib1f9b9c2008-02-23 22:45:33 +01005 *
6 * Licensed under GNU General Public License v2
7 * (see COPYING for full license text)
8 */
9
Lars Hjemlica8eb8f2007-05-09 00:48:09 +020010#include "cgit.h"
John Keeping8f208792013-04-06 11:37:59 +010011#include "ui-blob.h"
Lars Hjemlib1f9b9c2008-02-23 22:45:33 +010012#include "html.h"
Lars Hjemlia4d1ca12008-03-24 16:50:57 +010013#include "ui-shared.h"
Lars Hjemlica8eb8f2007-05-09 00:48:09 +020014
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010015struct walk_tree_context {
16 char *match_path;
17 unsigned char *matched_sha1;
18 int found_path;
19};
Michael Krelin01d2dce2008-06-24 23:33:24 +020020
Lukas Fleischer53bc7472013-03-03 16:04:29 +010021static int walk_tree(const unsigned char *sha1, const char *base, int baselen,
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010022 const char *pathname, unsigned mode, int stage, void *cbdata)
23{
24 struct walk_tree_context *walk_tree_ctx = cbdata;
25
26 if (strncmp(base, walk_tree_ctx->match_path, baselen)
27 || strcmp(walk_tree_ctx->match_path + baselen, pathname))
Michael Krelin01d2dce2008-06-24 23:33:24 +020028 return READ_TREE_RECURSIVE;
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010029 memmove(walk_tree_ctx->matched_sha1, sha1, 20);
30 walk_tree_ctx->found_path = 1;
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020031 return 0;
32}
33
34int cgit_print_file(char *path, const char *head)
35{
36 unsigned char sha1[20];
37 enum object_type type;
38 char *buf;
39 unsigned long size;
40 struct commit *commit;
John Keepingc1633c62013-03-02 12:32:11 +000041 struct pathspec_item path_items = {
42 .match = path,
43 .len = strlen(path)
44 };
45 struct pathspec paths = {
46 .nr = 1,
47 .items = &path_items
48 };
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010049 struct walk_tree_context walk_tree_ctx = {
50 .match_path = path,
51 .matched_sha1 = sha1,
52 .found_path = 0
53 };
54
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020055 if (get_sha1(head, sha1))
56 return -1;
57 type = sha1_object_info(sha1, &size);
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -050058 if (type == OBJ_COMMIT && path) {
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020059 commit = lookup_commit_reference(sha1);
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010060 read_tree_recursive(commit->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
61 if (!walk_tree_ctx.found_path)
Jason A. Donenfeld379e80e2010-08-04 00:45:42 +020062 return -1;
63 type = sha1_object_info(sha1, &size);
64 }
65 if (type == OBJ_BAD)
66 return -1;
67 buf = read_sha1_file(sha1, &type, &size);
68 if (!buf)
69 return -1;
70 buf[size] = '\0';
Mark Lodatod187b982010-09-04 14:18:16 -040071 html_raw(buf, size);
Michael Krelin01d2dce2008-06-24 23:33:24 +020072 return 0;
73}
74
75void cgit_print_blob(const char *hex, char *path, const char *head)
Lars Hjemlica8eb8f2007-05-09 00:48:09 +020076{
Lars Hjemlica8eb8f2007-05-09 00:48:09 +020077 unsigned char sha1[20];
78 enum object_type type;
Lars Hjemli596eb8f2009-07-25 11:51:19 +020079 char *buf;
Lars Hjemlica8eb8f2007-05-09 00:48:09 +020080 unsigned long size;
Michael Krelin01d2dce2008-06-24 23:33:24 +020081 struct commit *commit;
John Keepingc1633c62013-03-02 12:32:11 +000082 struct pathspec_item path_items = {
83 .match = path,
John Keeping1c32e002013-04-07 15:06:23 +010084 .len = path ? strlen(path) : 0
John Keepingc1633c62013-03-02 12:32:11 +000085 };
86 struct pathspec paths = {
87 .nr = 1,
88 .items = &path_items
89 };
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +010090 struct walk_tree_context walk_tree_ctx = {
91 .match_path = path,
92 .matched_sha1 = sha1,
93 };
Lars Hjemlica8eb8f2007-05-09 00:48:09 +020094
Michael Krelin01d2dce2008-06-24 23:33:24 +020095 if (hex) {
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -050096 if (get_sha1_hex(hex, sha1)) {
Michael Krelin01d2dce2008-06-24 23:33:24 +020097 cgit_print_error(fmt("Bad hex value: %s", hex));
98 return;
99 }
100 } else {
Lukas Fleischer53bc7472013-03-03 16:04:29 +0100101 if (get_sha1(head, sha1)) {
Michael Krelin01d2dce2008-06-24 23:33:24 +0200102 cgit_print_error(fmt("Bad ref: %s", head));
103 return;
104 }
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200105 }
106
107 type = sha1_object_info(sha1, &size);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200108
Jason A. Donenfeldbdae1d82013-03-03 23:21:33 -0500109 if ((!hex) && type == OBJ_COMMIT && path) {
Michael Krelin01d2dce2008-06-24 23:33:24 +0200110 commit = lookup_commit_reference(sha1);
Lukas Fleischer41f9c4e2013-03-03 17:27:46 +0100111 read_tree_recursive(commit->tree, "", 0, 0, &paths, walk_tree, &walk_tree_ctx);
Michael Krelin01d2dce2008-06-24 23:33:24 +0200112 type = sha1_object_info(sha1,&size);
113 }
114
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200115 if (type == OBJ_BAD) {
116 cgit_print_error(fmt("Bad object name: %s", hex));
117 return;
118 }
119
120 buf = read_sha1_file(sha1, &type, &size);
121 if (!buf) {
122 cgit_print_error(fmt("Error reading object %s", hex));
123 return;
124 }
125
126 buf[size] = '\0';
Michael Krelin42effc92008-06-24 23:42:32 +0200127 ctx.page.mimetype = ctx.qry.mimetype;
Lars Hjemli596eb8f2009-07-25 11:51:19 +0200128 if (!ctx.page.mimetype) {
129 if (buffer_is_binary(buf, size))
130 ctx.page.mimetype = "application/octet-stream";
131 else
132 ctx.page.mimetype = "text/plain";
133 }
Lars Hjemlif3c1a182008-03-24 00:51:19 +0100134 ctx.page.filename = path;
135 cgit_print_http_headers(&ctx);
Mark Lodatod187b982010-09-04 14:18:16 -0400136 html_raw(buf, size);
Lars Hjemlica8eb8f2007-05-09 00:48:09 +0200137}