]> gitweb.ps.run Git - ps-cgit/blob - ui-clone.c
git: update to v2.46.0
[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) 2006-2014 cgit Development Team <cgit@lists.zx2c4.com>
5  *
6  * Licensed under GNU General Public License v2
7  *   (see COPYING for full license text)
8  */
9
10 #define USE_THE_REPOSITORY_VARIABLE
11
12 #include "cgit.h"
13 #include "ui-clone.h"
14 #include "html.h"
15 #include "ui-shared.h"
16 #include "packfile.h"
17 #include "object-store.h"
18
19 static int print_ref_info(const char *refname, const struct object_id *oid,
20                           int flags, void *cb_data)
21 {
22         struct object *obj;
23
24         if (!(obj = parse_object(the_repository, oid)))
25                 return 0;
26
27         htmlf("%s\t%s\n", oid_to_hex(oid), refname);
28         if (obj->type == OBJ_TAG) {
29                 if (!(obj = deref_tag(the_repository, obj, refname, 0)))
30                         return 0;
31                 htmlf("%s\t%s^{}\n", oid_to_hex(&obj->oid), refname);
32         }
33         return 0;
34 }
35
36 static void print_pack_info(void)
37 {
38         struct packed_git *pack;
39         char *offset;
40
41         ctx.page.mimetype = "text/plain";
42         ctx.page.filename = "objects/info/packs";
43         cgit_print_http_headers();
44         reprepare_packed_git(the_repository);
45         for (pack = get_packed_git(the_repository); pack; pack = pack->next) {
46                 if (pack->pack_local) {
47                         offset = strrchr(pack->pack_name, '/');
48                         if (offset && offset[1] != '\0')
49                                 ++offset;
50                         else
51                                 offset = pack->pack_name;
52                         htmlf("P %s\n", offset);
53                 }
54         }
55 }
56
57 static void send_file(const char *path)
58 {
59         struct stat st;
60
61         if (stat(path, &st)) {
62                 switch (errno) {
63                 case ENOENT:
64                         cgit_print_error_page(404, "Not found", "Not found");
65                         break;
66                 case EACCES:
67                         cgit_print_error_page(403, "Forbidden", "Forbidden");
68                         break;
69                 default:
70                         cgit_print_error_page(400, "Bad request", "Bad request");
71                 }
72                 return;
73         }
74         ctx.page.mimetype = "application/octet-stream";
75         ctx.page.filename = path;
76         skip_prefix(path, ctx.repo->path, &ctx.page.filename);
77         skip_prefix(ctx.page.filename, "/", &ctx.page.filename);
78         cgit_print_http_headers();
79         html_include(path);
80 }
81
82 void cgit_clone_info(void)
83 {
84         if (!ctx.qry.path || strcmp(ctx.qry.path, "refs")) {
85                 cgit_print_error_page(400, "Bad request", "Bad request");
86                 return;
87         }
88
89         ctx.page.mimetype = "text/plain";
90         ctx.page.filename = "info/refs";
91         cgit_print_http_headers();
92         refs_for_each_ref(get_main_ref_store(the_repository),
93                           print_ref_info, NULL);
94 }
95
96 void cgit_clone_objects(void)
97 {
98         char *p;
99
100         if (!ctx.qry.path)
101                 goto err;
102
103         if (!strcmp(ctx.qry.path, "info/packs")) {
104                 print_pack_info();
105                 return;
106         }
107
108         /* Avoid directory traversal by forbidding "..", but also work around
109          * other funny business by just specifying a fairly strict format. For
110          * example, now we don't have to stress out about the Cygwin port.
111          */
112         for (p = ctx.qry.path; *p; ++p) {
113                 if (*p == '.' && *(p + 1) == '.')
114                         goto err;
115                 if (!isalnum(*p) && *p != '/' && *p != '.' && *p != '-')
116                         goto err;
117         }
118
119         send_file(git_path("objects/%s", ctx.qry.path));
120         return;
121
122 err:
123         cgit_print_error_page(400, "Bad request", "Bad request");
124 }
125
126 void cgit_clone_head(void)
127 {
128         send_file(git_path("%s", "HEAD"));
129 }