Blame


1 d71d75ad 2017-11-05 stsp /*
2 d71d75ad 2017-11-05 stsp * Copyright (c) 2017 Stefan Sperling <stsp@openbsd.org>
3 d71d75ad 2017-11-05 stsp *
4 d71d75ad 2017-11-05 stsp * Permission to use, copy, modify, and distribute this software for any
5 d71d75ad 2017-11-05 stsp * purpose with or without fee is hereby granted, provided that the above
6 d71d75ad 2017-11-05 stsp * copyright notice and this permission notice appear in all copies.
7 d71d75ad 2017-11-05 stsp *
8 d71d75ad 2017-11-05 stsp * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 d71d75ad 2017-11-05 stsp * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 d71d75ad 2017-11-05 stsp * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 d71d75ad 2017-11-05 stsp * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 d71d75ad 2017-11-05 stsp * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 d71d75ad 2017-11-05 stsp * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 d71d75ad 2017-11-05 stsp * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 d71d75ad 2017-11-05 stsp */
16 d71d75ad 2017-11-05 stsp
17 d71d75ad 2017-11-05 stsp #include <stdio.h>
18 ab9a70b2 2017-11-06 stsp #include <stdlib.h>
19 ab9a70b2 2017-11-06 stsp #include <string.h>
20 d71d75ad 2017-11-05 stsp #include <sha1.h>
21 ab9a70b2 2017-11-06 stsp #include <zlib.h>
22 ab9a70b2 2017-11-06 stsp #include <ctype.h>
23 ab9a70b2 2017-11-06 stsp #include <limits.h>
24 d71d75ad 2017-11-05 stsp
25 ab9a70b2 2017-11-06 stsp #include "got_error.h"
26 d71d75ad 2017-11-05 stsp #include "got_object.h"
27 ab9a70b2 2017-11-06 stsp #include "got_repository.h"
28 d71d75ad 2017-11-05 stsp
29 ab9a70b2 2017-11-06 stsp #ifndef MIN
30 ab9a70b2 2017-11-06 stsp #define MIN(_a,_b) ((_a) < (_b) ? (_a) : (_b))
31 ab9a70b2 2017-11-06 stsp #endif
32 ab9a70b2 2017-11-06 stsp
33 ab9a70b2 2017-11-06 stsp #ifndef nitems
34 ab9a70b2 2017-11-06 stsp #define nitems(_a) (sizeof(_a) / sizeof((_a)[0]))
35 ab9a70b2 2017-11-06 stsp #endif
36 ab9a70b2 2017-11-06 stsp
37 ab9a70b2 2017-11-06 stsp #define GOT_OBJ_TAG_COMMIT "commit"
38 ab9a70b2 2017-11-06 stsp #define GOT_OBJ_TAG_TREE "tree"
39 ab9a70b2 2017-11-06 stsp #define GOT_OBJ_TAG_BLOB "blob"
40 ab9a70b2 2017-11-06 stsp
41 d71d75ad 2017-11-05 stsp const char *
42 d71d75ad 2017-11-05 stsp got_object_id_str(struct got_object_id *id, char *buf, size_t size)
43 d71d75ad 2017-11-05 stsp {
44 d71d75ad 2017-11-05 stsp char *p = buf;
45 d71d75ad 2017-11-05 stsp char hex[3];
46 d71d75ad 2017-11-05 stsp int i;
47 d71d75ad 2017-11-05 stsp
48 d71d75ad 2017-11-05 stsp if (size < SHA1_DIGEST_STRING_LENGTH)
49 d71d75ad 2017-11-05 stsp return NULL;
50 d71d75ad 2017-11-05 stsp
51 d71d75ad 2017-11-05 stsp for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
52 d71d75ad 2017-11-05 stsp snprintf(hex, sizeof(hex), "%.2x", id->sha1[i]);
53 d71d75ad 2017-11-05 stsp p[0] = hex[0];
54 d71d75ad 2017-11-05 stsp p[1] = hex[1];
55 d71d75ad 2017-11-05 stsp p += 2;
56 d71d75ad 2017-11-05 stsp }
57 d71d75ad 2017-11-05 stsp p[0] = '\0';
58 d71d75ad 2017-11-05 stsp
59 d71d75ad 2017-11-05 stsp return buf;
60 d71d75ad 2017-11-05 stsp }
61 ab9a70b2 2017-11-06 stsp
62 ab9a70b2 2017-11-06 stsp struct got_zstream_buf {
63 ab9a70b2 2017-11-06 stsp z_stream z;
64 ab9a70b2 2017-11-06 stsp char *inbuf;
65 ab9a70b2 2017-11-06 stsp size_t inlen;
66 ab9a70b2 2017-11-06 stsp char *outbuf;
67 ab9a70b2 2017-11-06 stsp size_t outlen;
68 ab9a70b2 2017-11-06 stsp int flags;
69 ab9a70b2 2017-11-06 stsp #define GOT_ZSTREAM_F_HAVE_MORE 0x01
70 ab9a70b2 2017-11-06 stsp };
71 ab9a70b2 2017-11-06 stsp
72 ab9a70b2 2017-11-06 stsp static void
73 ab9a70b2 2017-11-06 stsp inflate_end(struct got_zstream_buf *zb)
74 ab9a70b2 2017-11-06 stsp {
75 ab9a70b2 2017-11-06 stsp free(zb->inbuf);
76 ab9a70b2 2017-11-06 stsp free(zb->outbuf);
77 ab9a70b2 2017-11-06 stsp inflateEnd(&zb->z);
78 ab9a70b2 2017-11-06 stsp }
79 ab9a70b2 2017-11-06 stsp
80 ab9a70b2 2017-11-06 stsp static const struct got_error *
81 ab9a70b2 2017-11-06 stsp inflate_init(struct got_zstream_buf *zb, size_t bufsize)
82 ab9a70b2 2017-11-06 stsp {
83 ab9a70b2 2017-11-06 stsp const struct got_error *err = NULL;
84 ab9a70b2 2017-11-06 stsp
85 ab9a70b2 2017-11-06 stsp memset(zb, 0, sizeof(*zb));
86 ab9a70b2 2017-11-06 stsp
87 ab9a70b2 2017-11-06 stsp zb->z.zalloc = Z_NULL;
88 ab9a70b2 2017-11-06 stsp zb->z.zfree = Z_NULL;
89 ab9a70b2 2017-11-06 stsp if (inflateInit(&zb->z) != Z_OK) {
90 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_IO);
91 ab9a70b2 2017-11-06 stsp goto done;
92 ab9a70b2 2017-11-06 stsp }
93 ab9a70b2 2017-11-06 stsp
94 ab9a70b2 2017-11-06 stsp zb->inlen = zb->outlen = bufsize;
95 ab9a70b2 2017-11-06 stsp
96 ab9a70b2 2017-11-06 stsp zb->inbuf = calloc(1, zb->inlen);
97 ab9a70b2 2017-11-06 stsp if (zb->inbuf == NULL) {
98 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_NO_MEM);
99 ab9a70b2 2017-11-06 stsp goto done;
100 ab9a70b2 2017-11-06 stsp }
101 ab9a70b2 2017-11-06 stsp
102 ab9a70b2 2017-11-06 stsp zb->outbuf = calloc(1, zb->outlen);
103 ab9a70b2 2017-11-06 stsp if (zb->outbuf == NULL) {
104 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_NO_MEM);
105 ab9a70b2 2017-11-06 stsp goto done;
106 ab9a70b2 2017-11-06 stsp }
107 ab9a70b2 2017-11-06 stsp
108 ab9a70b2 2017-11-06 stsp done:
109 ab9a70b2 2017-11-06 stsp if (err)
110 ab9a70b2 2017-11-06 stsp inflate_end(zb);
111 ab9a70b2 2017-11-06 stsp return err;
112 ab9a70b2 2017-11-06 stsp }
113 ab9a70b2 2017-11-06 stsp
114 ab9a70b2 2017-11-06 stsp static const struct got_error *
115 ab9a70b2 2017-11-06 stsp inflate_read(struct got_zstream_buf *zb, FILE *f, size_t *outlenp)
116 ab9a70b2 2017-11-06 stsp {
117 ab9a70b2 2017-11-06 stsp size_t last_total_out = zb->z.total_out;
118 ab9a70b2 2017-11-06 stsp z_stream *z = &zb->z;
119 ab9a70b2 2017-11-06 stsp int n, ret;
120 ab9a70b2 2017-11-06 stsp
121 ab9a70b2 2017-11-06 stsp z->next_out = zb->outbuf;
122 ab9a70b2 2017-11-06 stsp z->avail_out = zb->outlen;
123 ab9a70b2 2017-11-06 stsp
124 ab9a70b2 2017-11-06 stsp if (z->avail_in == 0 && (zb->flags & GOT_ZSTREAM_F_HAVE_MORE) == 0) {
125 ab9a70b2 2017-11-06 stsp int i;
126 ab9a70b2 2017-11-06 stsp n = fread(zb->inbuf, 1, zb->inlen, f);
127 ab9a70b2 2017-11-06 stsp if (n == 0) {
128 ab9a70b2 2017-11-06 stsp if (ferror(f))
129 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_IO);
130 ab9a70b2 2017-11-06 stsp *outlenp = 0;
131 ab9a70b2 2017-11-06 stsp return NULL;
132 ab9a70b2 2017-11-06 stsp }
133 ab9a70b2 2017-11-06 stsp z->next_in = zb->inbuf;
134 ab9a70b2 2017-11-06 stsp z->avail_in = n;
135 ab9a70b2 2017-11-06 stsp }
136 ab9a70b2 2017-11-06 stsp
137 ab9a70b2 2017-11-06 stsp ret = inflate(z, Z_SYNC_FLUSH);
138 ab9a70b2 2017-11-06 stsp if (ret == Z_OK) {
139 ab9a70b2 2017-11-06 stsp if (z->avail_out == 0)
140 ab9a70b2 2017-11-06 stsp zb->flags |= GOT_ZSTREAM_F_HAVE_MORE;
141 ab9a70b2 2017-11-06 stsp else
142 ab9a70b2 2017-11-06 stsp zb->flags &= ~GOT_ZSTREAM_F_HAVE_MORE;
143 ab9a70b2 2017-11-06 stsp } else if (ret != Z_STREAM_END)
144 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_DECOMPRESSION);
145 ab9a70b2 2017-11-06 stsp
146 ab9a70b2 2017-11-06 stsp *outlenp = z->total_out - last_total_out;
147 ab9a70b2 2017-11-06 stsp return NULL;
148 ab9a70b2 2017-11-06 stsp }
149 ab9a70b2 2017-11-06 stsp
150 ab9a70b2 2017-11-06 stsp static const struct got_error *
151 ab9a70b2 2017-11-06 stsp parse_obj_header(struct got_object **obj, char *buf, size_t len)
152 ab9a70b2 2017-11-06 stsp {
153 ab9a70b2 2017-11-06 stsp const char *obj_tags[] = {
154 ab9a70b2 2017-11-06 stsp GOT_OBJ_TAG_COMMIT,
155 ab9a70b2 2017-11-06 stsp GOT_OBJ_TAG_TREE,
156 ab9a70b2 2017-11-06 stsp GOT_OBJ_TAG_BLOB
157 ab9a70b2 2017-11-06 stsp };
158 ab9a70b2 2017-11-06 stsp const int obj_types[] = {
159 ab9a70b2 2017-11-06 stsp GOT_OBJ_TYPE_COMMIT,
160 ab9a70b2 2017-11-06 stsp GOT_OBJ_TYPE_TREE,
161 ab9a70b2 2017-11-06 stsp GOT_OBJ_TYPE_BLOB,
162 ab9a70b2 2017-11-06 stsp };
163 ab9a70b2 2017-11-06 stsp int type = 0;
164 ab9a70b2 2017-11-06 stsp size_t size = 0;
165 ab9a70b2 2017-11-06 stsp int i;
166 ab9a70b2 2017-11-06 stsp char *p = strchr(buf, '\0');
167 ab9a70b2 2017-11-06 stsp
168 ab9a70b2 2017-11-06 stsp if (p == NULL)
169 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
170 ab9a70b2 2017-11-06 stsp
171 ab9a70b2 2017-11-06 stsp for (i = 0; i < nitems(obj_tags); i++) {
172 ab9a70b2 2017-11-06 stsp const char *tag = obj_tags[i];
173 ab9a70b2 2017-11-06 stsp const char *errstr;
174 ab9a70b2 2017-11-06 stsp
175 ab9a70b2 2017-11-06 stsp if (strncmp(buf, tag, strlen(tag)) != 0)
176 ab9a70b2 2017-11-06 stsp continue;
177 ab9a70b2 2017-11-06 stsp
178 ab9a70b2 2017-11-06 stsp type = obj_types[i];
179 ab9a70b2 2017-11-06 stsp if (len <= strlen(tag))
180 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
181 ab9a70b2 2017-11-06 stsp size = strtonum(buf + strlen(tag), 0, LONG_MAX, &errstr);
182 ab9a70b2 2017-11-06 stsp if (errstr != NULL)
183 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
184 ab9a70b2 2017-11-06 stsp break;
185 ab9a70b2 2017-11-06 stsp }
186 ab9a70b2 2017-11-06 stsp
187 ab9a70b2 2017-11-06 stsp if (type == 0)
188 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_OBJ_HDR);
189 ab9a70b2 2017-11-06 stsp
190 ab9a70b2 2017-11-06 stsp *obj = calloc(1, sizeof(**obj));
191 ab9a70b2 2017-11-06 stsp (*obj)->type = type;
192 ab9a70b2 2017-11-06 stsp (*obj)->size = size;
193 ab9a70b2 2017-11-06 stsp return NULL;
194 ab9a70b2 2017-11-06 stsp }
195 ab9a70b2 2017-11-06 stsp
196 ab9a70b2 2017-11-06 stsp static const struct got_error *
197 ab9a70b2 2017-11-06 stsp read_object_header(struct got_object **obj, struct got_repository *repo,
198 ab9a70b2 2017-11-06 stsp const char *path)
199 ab9a70b2 2017-11-06 stsp {
200 ab9a70b2 2017-11-06 stsp const struct got_error *err;
201 ab9a70b2 2017-11-06 stsp FILE *f;
202 ab9a70b2 2017-11-06 stsp struct got_zstream_buf zb;
203 ab9a70b2 2017-11-06 stsp char *p;
204 ab9a70b2 2017-11-06 stsp size_t outlen;
205 ab9a70b2 2017-11-06 stsp int i, ret;
206 ab9a70b2 2017-11-06 stsp
207 ab9a70b2 2017-11-06 stsp f = fopen(path, "rb");
208 ab9a70b2 2017-11-06 stsp if (f == NULL)
209 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_BAD_PATH);
210 ab9a70b2 2017-11-06 stsp
211 ab9a70b2 2017-11-06 stsp err = inflate_init(&zb, 64);
212 ab9a70b2 2017-11-06 stsp if (err) {
213 ab9a70b2 2017-11-06 stsp fclose(f);
214 ab9a70b2 2017-11-06 stsp return err;
215 ab9a70b2 2017-11-06 stsp }
216 ab9a70b2 2017-11-06 stsp
217 ab9a70b2 2017-11-06 stsp err = inflate_read(&zb, f, &outlen);
218 ab9a70b2 2017-11-06 stsp if (err)
219 ab9a70b2 2017-11-06 stsp goto done;
220 ab9a70b2 2017-11-06 stsp
221 ab9a70b2 2017-11-06 stsp err = parse_obj_header(obj, zb.outbuf, outlen);
222 ab9a70b2 2017-11-06 stsp done:
223 ab9a70b2 2017-11-06 stsp inflate_end(&zb);
224 ab9a70b2 2017-11-06 stsp fclose(f);
225 ab9a70b2 2017-11-06 stsp return err;
226 ab9a70b2 2017-11-06 stsp }
227 ab9a70b2 2017-11-06 stsp
228 ab9a70b2 2017-11-06 stsp const struct got_error *
229 ab9a70b2 2017-11-06 stsp got_object_open(struct got_object **obj, struct got_repository *repo,
230 ab9a70b2 2017-11-06 stsp struct got_object_id *id)
231 ab9a70b2 2017-11-06 stsp {
232 ab9a70b2 2017-11-06 stsp const struct got_error *err = NULL;
233 ab9a70b2 2017-11-06 stsp char *path_objects = got_repo_get_path_objects(repo);
234 ab9a70b2 2017-11-06 stsp char hex[SHA1_DIGEST_STRING_LENGTH];
235 ab9a70b2 2017-11-06 stsp char *path = NULL;
236 ab9a70b2 2017-11-06 stsp
237 ab9a70b2 2017-11-06 stsp if (path_objects == NULL)
238 ab9a70b2 2017-11-06 stsp return got_error(GOT_ERR_NO_MEM);
239 ab9a70b2 2017-11-06 stsp
240 ab9a70b2 2017-11-06 stsp got_object_id_str(id, hex, sizeof(hex));
241 ab9a70b2 2017-11-06 stsp
242 ab9a70b2 2017-11-06 stsp if (asprintf(&path, "%s/%.2x/%s",
243 ab9a70b2 2017-11-06 stsp path_objects, id->sha1[0], hex + 2) == -1) {
244 ab9a70b2 2017-11-06 stsp err = got_error(GOT_ERR_NO_MEM);
245 ab9a70b2 2017-11-06 stsp goto done;
246 ab9a70b2 2017-11-06 stsp }
247 ab9a70b2 2017-11-06 stsp
248 ab9a70b2 2017-11-06 stsp err = read_object_header(obj, repo, path);
249 ab9a70b2 2017-11-06 stsp if (err == NULL)
250 ab9a70b2 2017-11-06 stsp memcpy((*obj)->id.sha1, id->sha1, SHA1_DIGEST_LENGTH);
251 ab9a70b2 2017-11-06 stsp
252 ab9a70b2 2017-11-06 stsp done:
253 ab9a70b2 2017-11-06 stsp free(path);
254 ab9a70b2 2017-11-06 stsp free(path_objects);
255 ab9a70b2 2017-11-06 stsp return err;
256 ab9a70b2 2017-11-06 stsp }
257 ab9a70b2 2017-11-06 stsp
258 ab9a70b2 2017-11-06 stsp void
259 ab9a70b2 2017-11-06 stsp got_object_close(struct got_object *obj)
260 ab9a70b2 2017-11-06 stsp {
261 ab9a70b2 2017-11-06 stsp free(obj);
262 ab9a70b2 2017-11-06 stsp }