]> gitweb.ps.run Git - ps-cgit/blob - ui-clone.c
Add support for cloning over http
[ps-cgit] / ui-clone.c
1 /* ui-clone.c: functions for http cloning, based on
2  * git's http-backend.c by Shawn O. Pearce
3  *
4  * Copyright (C) 2008 Lars Hjemli
5  *
6  * Licensed under GNU General Public License v2
7  *   (see COPYING for full license text)
8  */
9
10 #include "cgit.h"
11 #include "html.h"
12 #include "ui-shared.h"
13
14 static int print_ref_info(const char *refname, const unsigned char *sha1,
15                           int flags, void *cb_data)
16 {
17         struct object *obj;
18
19         if (!(obj = parse_object(sha1)))
20                 return 0;
21
22         if (!strcmp(refname, "HEAD") || !prefixcmp(refname, "refs/heads/"))
23                 htmlf("%s\t%s\n", sha1_to_hex(sha1), refname);
24         else if (!prefixcmp(refname, "refs/tags") && obj->type == OBJ_TAG) {
25                 if (!(obj = deref_tag(obj, refname, 0)))
26                         return 0;
27                 htmlf("%s\t%s\n", sha1_to_hex(sha1), refname);
28                 htmlf("%s\t%s^{}\n", sha1_to_hex(obj->sha1), refname);
29         }
30         return 0;
31 }
32
33 static void print_pack_info(struct cgit_context *ctx)
34 {
35         struct packed_git *pack;
36         int ofs;
37
38         ctx->page.mimetype = "text/plain";
39         ctx->page.filename = "objects/info/packs";
40         cgit_print_http_headers(ctx);
41         ofs = strlen(ctx->repo->path) + strlen("/objects/pack/");
42         prepare_packed_git();
43         for (pack = packed_git; pack; pack = pack->next)
44                 if (pack->pack_local)
45                         htmlf("P %s\n", pack->pack_name + ofs);
46 }
47
48 static void send_file(struct cgit_context *ctx, char *path)
49 {
50         struct stat st;
51         int err;
52
53         if (stat(path, &st)) {
54                 switch (errno) {
55                 case ENOENT:
56                         err = 404;
57                         break;
58                 case EACCES:
59                         err = 403;
60                         break;
61                 default:
62                         err = 400;
63                 }
64                 html_status(err, 0);
65                 return;
66         }
67         ctx->page.mimetype = "application/octet-stream";
68         ctx->page.filename = path;
69         if (prefixcmp(ctx->repo->path, path))
70                 ctx->page.filename += strlen(ctx->repo->path) + 1;
71         cgit_print_http_headers(ctx);
72         html_include(path);
73 }
74
75 void cgit_clone_info(struct cgit_context *ctx)
76 {
77         if (!ctx->qry.path || strcmp(ctx->qry.path, "refs"))
78                 return;
79
80         ctx->page.mimetype = "text/plain";
81         ctx->page.filename = "info/refs";
82         cgit_print_http_headers(ctx);
83         for_each_ref(print_ref_info, ctx);
84 }
85
86 void cgit_clone_objects(struct cgit_context *ctx)
87 {
88         if (!ctx->qry.path) {
89                 html_status(400, 0);
90                 return;
91         }
92
93         if (!strcmp(ctx->qry.path, "info/packs")) {
94                 print_pack_info(ctx);
95                 return;
96         }
97
98         send_file(ctx, git_path("objects/%s", ctx->qry.path));
99 }
100
101 void cgit_clone_head(struct cgit_context *ctx)
102 {
103         send_file(ctx, git_path("%s", "HEAD"));
104 }